1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/AUTHORS Mon Dec 06 13:09:21 2010 +0100
1.3 @@ -0,0 +1,33 @@
1.4 +The GLPK package was developed and programmed by Andrew Makhorin,
1.5 +Department for Applied Informatics, Moscow Aviation Institute, Moscow,
1.6 +Russia.
1.7 +
1.8 +E-mail: <mao@gnu.org>
1.9 +
1.10 +Paper mail: 125871, Russia, Moscow, Volokolamskoye sh., 4,
1.11 + Moscow Aviation Institute, Andrew O. Makhorin
1.12 +
1.13 +-----BEGIN PGP PUBLIC KEY BLOCK-----
1.14 +Version: GnuPG v1.2.2 (MingW32)
1.15 +
1.16 +mQGiBD8UdT8RBAC6yWYxoa1b7U973J0jBuQpgZnhXlGJJpMZgAW9efDBD17vhkJm
1.17 +hPVOQBKRUeOOLcW3/a7NMoNLMdmF1Rgz1FPVy3RgBDsYj4Sp4RBCsX/o0xXh+jxe
1.18 +gncr4bdN0Ruk03pezVtLi9oYygdxfI51SsjZ2vwYP6BhMwv+xrIgcnc4qwCgoCit
1.19 +26mTd0FoGOmsQuipo6X5LaUD/1l7NqFIjiGdWthyG3TqsiK5Ew7xF3fLEABXKPjb
1.20 +PMRTMucX8XXHmW8RUD1vP1uGDnEn6s+fjc3/RtaqKjqGMdLt4XgHQkImaVguNpSS
1.21 +IxN3LaK600BgAbwSd1bomRqWNlczAM7469VvGG9ASpCBveUUrqwerHZcUbvngL62
1.22 +pIcqA/41dO0xYrOTqMRhuguYMgHL2xbwB2Aj2TqRwBm697DIS25B9nE+8UsbjGRx
1.23 +q3EmeuHeZ5kN5RbESXkGUB8whIcYxvH16HRNmM1ZjmFoBVL2Z6S2gpa2ZUqsq7BZ
1.24 +s+hriElm3dfOQCt79/o852uKWu5bSjw2yiemVA2T8tG4OoN6DrQjQW5kcmV3IE1h
1.25 +a2hvcmluIDxtYW9AbWFpMi5yY25ldC5ydT6IWwQTEQIAGwUCPxR1PwYLCQgHAwID
1.26 +FQIDAxYCAQIeAQIXgAAKCRDRe/IwWYHoGKpHAJ44MmzWKr8OiTc0Bb6/RD56aekp
1.27 +3wCdGznQMCfWFkehQPbeNaB5yFIs+8a5AQ0EPxR1UBAEAO3U3H5M0iYv06C4kKty
1.28 +6ReWyYH4CzMAfp2lPVUKzRSjPtoAJ6SkrBSKMT+U+DahxZ4K4HbinvHq3uvlwWax
1.29 +xw0wKxJl4oY6EGE1Jqn3B//Ak47RaNMnrs9V739WT1YNRpQvh4wOCeMekBzksf43
1.30 +hm4dSV4PMQkLmrEeG2+BYaZnAAMFA/4tVHhjGRkxzcTcfHCB+Yo3PXeIQMuIs00c
1.31 +VKCrNReLni/3BWZC0w9tFzZSdz+URXefPWDGuAC16vLCVOD06NcIQGutPe189dUn
1.32 +Kf9Bl6qc9DyWsxSTdF/PbLqcLfEe9g7fHhIwdY+w/hSq2n3NEURMzHiMT1U3CvHd
1.33 +As5IzV/yD4hGBBgRAgAGBQI/FHVQAAoJENF78jBZgegYRZEAmwReJkMSrbs0EQs2
1.34 +wjyTCMd5KDh3AKCR2/RvVad9RT3ShYnUiPPYTL2/Nw==
1.35 +=OfLQ
1.36 +-----END PGP PUBLIC KEY BLOCK-----
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/COPYING Mon Dec 06 13:09:21 2010 +0100
2.3 @@ -0,0 +1,676 @@
2.4 +
2.5 + GNU GENERAL PUBLIC LICENSE
2.6 + Version 3, 29 June 2007
2.7 +
2.8 + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
2.9 + Everyone is permitted to copy and distribute verbatim copies
2.10 + of this license document, but changing it is not allowed.
2.11 +
2.12 + Preamble
2.13 +
2.14 + The GNU General Public License is a free, copyleft license for
2.15 +software and other kinds of works.
2.16 +
2.17 + The licenses for most software and other practical works are designed
2.18 +to take away your freedom to share and change the works. By contrast,
2.19 +the GNU General Public License is intended to guarantee your freedom to
2.20 +share and change all versions of a program--to make sure it remains free
2.21 +software for all its users. We, the Free Software Foundation, use the
2.22 +GNU General Public License for most of our software; it applies also to
2.23 +any other work released this way by its authors. You can apply it to
2.24 +your programs, too.
2.25 +
2.26 + When we speak of free software, we are referring to freedom, not
2.27 +price. Our General Public Licenses are designed to make sure that you
2.28 +have the freedom to distribute copies of free software (and charge for
2.29 +them if you wish), that you receive source code or can get it if you
2.30 +want it, that you can change the software or use pieces of it in new
2.31 +free programs, and that you know you can do these things.
2.32 +
2.33 + To protect your rights, we need to prevent others from denying you
2.34 +these rights or asking you to surrender the rights. Therefore, you have
2.35 +certain responsibilities if you distribute copies of the software, or if
2.36 +you modify it: responsibilities to respect the freedom of others.
2.37 +
2.38 + For example, if you distribute copies of such a program, whether
2.39 +gratis or for a fee, you must pass on to the recipients the same
2.40 +freedoms that you received. You must make sure that they, too, receive
2.41 +or can get the source code. And you must show them these terms so they
2.42 +know their rights.
2.43 +
2.44 + Developers that use the GNU GPL protect your rights with two steps:
2.45 +(1) assert copyright on the software, and (2) offer you this License
2.46 +giving you legal permission to copy, distribute and/or modify it.
2.47 +
2.48 + For the developers' and authors' protection, the GPL clearly explains
2.49 +that there is no warranty for this free software. For both users' and
2.50 +authors' sake, the GPL requires that modified versions be marked as
2.51 +changed, so that their problems will not be attributed erroneously to
2.52 +authors of previous versions.
2.53 +
2.54 + Some devices are designed to deny users access to install or run
2.55 +modified versions of the software inside them, although the manufacturer
2.56 +can do so. This is fundamentally incompatible with the aim of
2.57 +protecting users' freedom to change the software. The systematic
2.58 +pattern of such abuse occurs in the area of products for individuals to
2.59 +use, which is precisely where it is most unacceptable. Therefore, we
2.60 +have designed this version of the GPL to prohibit the practice for those
2.61 +products. If such problems arise substantially in other domains, we
2.62 +stand ready to extend this provision to those domains in future versions
2.63 +of the GPL, as needed to protect the freedom of users.
2.64 +
2.65 + Finally, every program is threatened constantly by software patents.
2.66 +States should not allow patents to restrict development and use of
2.67 +software on general-purpose computers, but in those that do, we wish to
2.68 +avoid the special danger that patents applied to a free program could
2.69 +make it effectively proprietary. To prevent this, the GPL assures that
2.70 +patents cannot be used to render the program non-free.
2.71 +
2.72 + The precise terms and conditions for copying, distribution and
2.73 +modification follow.
2.74 +
2.75 + TERMS AND CONDITIONS
2.76 +
2.77 + 0. Definitions.
2.78 +
2.79 + "This License" refers to version 3 of the GNU General Public License.
2.80 +
2.81 + "Copyright" also means copyright-like laws that apply to other kinds of
2.82 +works, such as semiconductor masks.
2.83 +
2.84 + "The Program" refers to any copyrightable work licensed under this
2.85 +License. Each licensee is addressed as "you". "Licensees" and
2.86 +"recipients" may be individuals or organizations.
2.87 +
2.88 + To "modify" a work means to copy from or adapt all or part of the work
2.89 +in a fashion requiring copyright permission, other than the making of an
2.90 +exact copy. The resulting work is called a "modified version" of the
2.91 +earlier work or a work "based on" the earlier work.
2.92 +
2.93 + A "covered work" means either the unmodified Program or a work based
2.94 +on the Program.
2.95 +
2.96 + To "propagate" a work means to do anything with it that, without
2.97 +permission, would make you directly or secondarily liable for
2.98 +infringement under applicable copyright law, except executing it on a
2.99 +computer or modifying a private copy. Propagation includes copying,
2.100 +distribution (with or without modification), making available to the
2.101 +public, and in some countries other activities as well.
2.102 +
2.103 + To "convey" a work means any kind of propagation that enables other
2.104 +parties to make or receive copies. Mere interaction with a user through
2.105 +a computer network, with no transfer of a copy, is not conveying.
2.106 +
2.107 + An interactive user interface displays "Appropriate Legal Notices"
2.108 +to the extent that it includes a convenient and prominently visible
2.109 +feature that (1) displays an appropriate copyright notice, and (2)
2.110 +tells the user that there is no warranty for the work (except to the
2.111 +extent that warranties are provided), that licensees may convey the
2.112 +work under this License, and how to view a copy of this License. If
2.113 +the interface presents a list of user commands or options, such as a
2.114 +menu, a prominent item in the list meets this criterion.
2.115 +
2.116 + 1. Source Code.
2.117 +
2.118 + The "source code" for a work means the preferred form of the work
2.119 +for making modifications to it. "Object code" means any non-source
2.120 +form of a work.
2.121 +
2.122 + A "Standard Interface" means an interface that either is an official
2.123 +standard defined by a recognized standards body, or, in the case of
2.124 +interfaces specified for a particular programming language, one that
2.125 +is widely used among developers working in that language.
2.126 +
2.127 + The "System Libraries" of an executable work include anything, other
2.128 +than the work as a whole, that (a) is included in the normal form of
2.129 +packaging a Major Component, but which is not part of that Major
2.130 +Component, and (b) serves only to enable use of the work with that
2.131 +Major Component, or to implement a Standard Interface for which an
2.132 +implementation is available to the public in source code form. A
2.133 +"Major Component", in this context, means a major essential component
2.134 +(kernel, window system, and so on) of the specific operating system
2.135 +(if any) on which the executable work runs, or a compiler used to
2.136 +produce the work, or an object code interpreter used to run it.
2.137 +
2.138 + The "Corresponding Source" for a work in object code form means all
2.139 +the source code needed to generate, install, and (for an executable
2.140 +work) run the object code and to modify the work, including scripts to
2.141 +control those activities. However, it does not include the work's
2.142 +System Libraries, or general-purpose tools or generally available free
2.143 +programs which are used unmodified in performing those activities but
2.144 +which are not part of the work. For example, Corresponding Source
2.145 +includes interface definition files associated with source files for
2.146 +the work, and the source code for shared libraries and dynamically
2.147 +linked subprograms that the work is specifically designed to require,
2.148 +such as by intimate data communication or control flow between those
2.149 +subprograms and other parts of the work.
2.150 +
2.151 + The Corresponding Source need not include anything that users
2.152 +can regenerate automatically from other parts of the Corresponding
2.153 +Source.
2.154 +
2.155 + The Corresponding Source for a work in source code form is that
2.156 +same work.
2.157 +
2.158 + 2. Basic Permissions.
2.159 +
2.160 + All rights granted under this License are granted for the term of
2.161 +copyright on the Program, and are irrevocable provided the stated
2.162 +conditions are met. This License explicitly affirms your unlimited
2.163 +permission to run the unmodified Program. The output from running a
2.164 +covered work is covered by this License only if the output, given its
2.165 +content, constitutes a covered work. This License acknowledges your
2.166 +rights of fair use or other equivalent, as provided by copyright law.
2.167 +
2.168 + You may make, run and propagate covered works that you do not
2.169 +convey, without conditions so long as your license otherwise remains
2.170 +in force. You may convey covered works to others for the sole purpose
2.171 +of having them make modifications exclusively for you, or provide you
2.172 +with facilities for running those works, provided that you comply with
2.173 +the terms of this License in conveying all material for which you do
2.174 +not control copyright. Those thus making or running the covered works
2.175 +for you must do so exclusively on your behalf, under your direction
2.176 +and control, on terms that prohibit them from making any copies of
2.177 +your copyrighted material outside their relationship with you.
2.178 +
2.179 + Conveying under any other circumstances is permitted solely under
2.180 +the conditions stated below. Sublicensing is not allowed; section 10
2.181 +makes it unnecessary.
2.182 +
2.183 + 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
2.184 +
2.185 + No covered work shall be deemed part of an effective technological
2.186 +measure under any applicable law fulfilling obligations under article
2.187 +11 of the WIPO copyright treaty adopted on 20 December 1996, or
2.188 +similar laws prohibiting or restricting circumvention of such
2.189 +measures.
2.190 +
2.191 + When you convey a covered work, you waive any legal power to forbid
2.192 +circumvention of technological measures to the extent such circumvention
2.193 +is effected by exercising rights under this License with respect to
2.194 +the covered work, and you disclaim any intention to limit operation or
2.195 +modification of the work as a means of enforcing, against the work's
2.196 +users, your or third parties' legal rights to forbid circumvention of
2.197 +technological measures.
2.198 +
2.199 + 4. Conveying Verbatim Copies.
2.200 +
2.201 + You may convey verbatim copies of the Program's source code as you
2.202 +receive it, in any medium, provided that you conspicuously and
2.203 +appropriately publish on each copy an appropriate copyright notice;
2.204 +keep intact all notices stating that this License and any
2.205 +non-permissive terms added in accord with section 7 apply to the code;
2.206 +keep intact all notices of the absence of any warranty; and give all
2.207 +recipients a copy of this License along with the Program.
2.208 +
2.209 + You may charge any price or no price for each copy that you convey,
2.210 +and you may offer support or warranty protection for a fee.
2.211 +
2.212 + 5. Conveying Modified Source Versions.
2.213 +
2.214 + You may convey a work based on the Program, or the modifications to
2.215 +produce it from the Program, in the form of source code under the
2.216 +terms of section 4, provided that you also meet all of these conditions:
2.217 +
2.218 + a) The work must carry prominent notices stating that you modified
2.219 + it, and giving a relevant date.
2.220 +
2.221 + b) The work must carry prominent notices stating that it is
2.222 + released under this License and any conditions added under section
2.223 + 7. This requirement modifies the requirement in section 4 to
2.224 + "keep intact all notices".
2.225 +
2.226 + c) You must license the entire work, as a whole, under this
2.227 + License to anyone who comes into possession of a copy. This
2.228 + License will therefore apply, along with any applicable section 7
2.229 + additional terms, to the whole of the work, and all its parts,
2.230 + regardless of how they are packaged. This License gives no
2.231 + permission to license the work in any other way, but it does not
2.232 + invalidate such permission if you have separately received it.
2.233 +
2.234 + d) If the work has interactive user interfaces, each must display
2.235 + Appropriate Legal Notices; however, if the Program has interactive
2.236 + interfaces that do not display Appropriate Legal Notices, your
2.237 + work need not make them do so.
2.238 +
2.239 + A compilation of a covered work with other separate and independent
2.240 +works, which are not by their nature extensions of the covered work,
2.241 +and which are not combined with it such as to form a larger program,
2.242 +in or on a volume of a storage or distribution medium, is called an
2.243 +"aggregate" if the compilation and its resulting copyright are not
2.244 +used to limit the access or legal rights of the compilation's users
2.245 +beyond what the individual works permit. Inclusion of a covered work
2.246 +in an aggregate does not cause this License to apply to the other
2.247 +parts of the aggregate.
2.248 +
2.249 + 6. Conveying Non-Source Forms.
2.250 +
2.251 + You may convey a covered work in object code form under the terms
2.252 +of sections 4 and 5, provided that you also convey the
2.253 +machine-readable Corresponding Source under the terms of this License,
2.254 +in one of these ways:
2.255 +
2.256 + a) Convey the object code in, or embodied in, a physical product
2.257 + (including a physical distribution medium), accompanied by the
2.258 + Corresponding Source fixed on a durable physical medium
2.259 + customarily used for software interchange.
2.260 +
2.261 + b) Convey the object code in, or embodied in, a physical product
2.262 + (including a physical distribution medium), accompanied by a
2.263 + written offer, valid for at least three years and valid for as
2.264 + long as you offer spare parts or customer support for that product
2.265 + model, to give anyone who possesses the object code either (1) a
2.266 + copy of the Corresponding Source for all the software in the
2.267 + product that is covered by this License, on a durable physical
2.268 + medium customarily used for software interchange, for a price no
2.269 + more than your reasonable cost of physically performing this
2.270 + conveying of source, or (2) access to copy the
2.271 + Corresponding Source from a network server at no charge.
2.272 +
2.273 + c) Convey individual copies of the object code with a copy of the
2.274 + written offer to provide the Corresponding Source. This
2.275 + alternative is allowed only occasionally and noncommercially, and
2.276 + only if you received the object code with such an offer, in accord
2.277 + with subsection 6b.
2.278 +
2.279 + d) Convey the object code by offering access from a designated
2.280 + place (gratis or for a charge), and offer equivalent access to the
2.281 + Corresponding Source in the same way through the same place at no
2.282 + further charge. You need not require recipients to copy the
2.283 + Corresponding Source along with the object code. If the place to
2.284 + copy the object code is a network server, the Corresponding Source
2.285 + may be on a different server (operated by you or a third party)
2.286 + that supports equivalent copying facilities, provided you maintain
2.287 + clear directions next to the object code saying where to find the
2.288 + Corresponding Source. Regardless of what server hosts the
2.289 + Corresponding Source, you remain obligated to ensure that it is
2.290 + available for as long as needed to satisfy these requirements.
2.291 +
2.292 + e) Convey the object code using peer-to-peer transmission, provided
2.293 + you inform other peers where the object code and Corresponding
2.294 + Source of the work are being offered to the general public at no
2.295 + charge under subsection 6d.
2.296 +
2.297 + A separable portion of the object code, whose source code is excluded
2.298 +from the Corresponding Source as a System Library, need not be
2.299 +included in conveying the object code work.
2.300 +
2.301 + A "User Product" is either (1) a "consumer product", which means any
2.302 +tangible personal property which is normally used for personal, family,
2.303 +or household purposes, or (2) anything designed or sold for incorporation
2.304 +into a dwelling. In determining whether a product is a consumer product,
2.305 +doubtful cases shall be resolved in favor of coverage. For a particular
2.306 +product received by a particular user, "normally used" refers to a
2.307 +typical or common use of that class of product, regardless of the status
2.308 +of the particular user or of the way in which the particular user
2.309 +actually uses, or expects or is expected to use, the product. A product
2.310 +is a consumer product regardless of whether the product has substantial
2.311 +commercial, industrial or non-consumer uses, unless such uses represent
2.312 +the only significant mode of use of the product.
2.313 +
2.314 + "Installation Information" for a User Product means any methods,
2.315 +procedures, authorization keys, or other information required to install
2.316 +and execute modified versions of a covered work in that User Product from
2.317 +a modified version of its Corresponding Source. The information must
2.318 +suffice to ensure that the continued functioning of the modified object
2.319 +code is in no case prevented or interfered with solely because
2.320 +modification has been made.
2.321 +
2.322 + If you convey an object code work under this section in, or with, or
2.323 +specifically for use in, a User Product, and the conveying occurs as
2.324 +part of a transaction in which the right of possession and use of the
2.325 +User Product is transferred to the recipient in perpetuity or for a
2.326 +fixed term (regardless of how the transaction is characterized), the
2.327 +Corresponding Source conveyed under this section must be accompanied
2.328 +by the Installation Information. But this requirement does not apply
2.329 +if neither you nor any third party retains the ability to install
2.330 +modified object code on the User Product (for example, the work has
2.331 +been installed in ROM).
2.332 +
2.333 + The requirement to provide Installation Information does not include a
2.334 +requirement to continue to provide support service, warranty, or updates
2.335 +for a work that has been modified or installed by the recipient, or for
2.336 +the User Product in which it has been modified or installed. Access to a
2.337 +network may be denied when the modification itself materially and
2.338 +adversely affects the operation of the network or violates the rules and
2.339 +protocols for communication across the network.
2.340 +
2.341 + Corresponding Source conveyed, and Installation Information provided,
2.342 +in accord with this section must be in a format that is publicly
2.343 +documented (and with an implementation available to the public in
2.344 +source code form), and must require no special password or key for
2.345 +unpacking, reading or copying.
2.346 +
2.347 + 7. Additional Terms.
2.348 +
2.349 + "Additional permissions" are terms that supplement the terms of this
2.350 +License by making exceptions from one or more of its conditions.
2.351 +Additional permissions that are applicable to the entire Program shall
2.352 +be treated as though they were included in this License, to the extent
2.353 +that they are valid under applicable law. If additional permissions
2.354 +apply only to part of the Program, that part may be used separately
2.355 +under those permissions, but the entire Program remains governed by
2.356 +this License without regard to the additional permissions.
2.357 +
2.358 + When you convey a copy of a covered work, you may at your option
2.359 +remove any additional permissions from that copy, or from any part of
2.360 +it. (Additional permissions may be written to require their own
2.361 +removal in certain cases when you modify the work.) You may place
2.362 +additional permissions on material, added by you to a covered work,
2.363 +for which you have or can give appropriate copyright permission.
2.364 +
2.365 + Notwithstanding any other provision of this License, for material you
2.366 +add to a covered work, you may (if authorized by the copyright holders of
2.367 +that material) supplement the terms of this License with terms:
2.368 +
2.369 + a) Disclaiming warranty or limiting liability differently from the
2.370 + terms of sections 15 and 16 of this License; or
2.371 +
2.372 + b) Requiring preservation of specified reasonable legal notices or
2.373 + author attributions in that material or in the Appropriate Legal
2.374 + Notices displayed by works containing it; or
2.375 +
2.376 + c) Prohibiting misrepresentation of the origin of that material, or
2.377 + requiring that modified versions of such material be marked in
2.378 + reasonable ways as different from the original version; or
2.379 +
2.380 + d) Limiting the use for publicity purposes of names of licensors or
2.381 + authors of the material; or
2.382 +
2.383 + e) Declining to grant rights under trademark law for use of some
2.384 + trade names, trademarks, or service marks; or
2.385 +
2.386 + f) Requiring indemnification of licensors and authors of that
2.387 + material by anyone who conveys the material (or modified versions of
2.388 + it) with contractual assumptions of liability to the recipient, for
2.389 + any liability that these contractual assumptions directly impose on
2.390 + those licensors and authors.
2.391 +
2.392 + All other non-permissive additional terms are considered "further
2.393 +restrictions" within the meaning of section 10. If the Program as you
2.394 +received it, or any part of it, contains a notice stating that it is
2.395 +governed by this License along with a term that is a further
2.396 +restriction, you may remove that term. If a license document contains
2.397 +a further restriction but permits relicensing or conveying under this
2.398 +License, you may add to a covered work material governed by the terms
2.399 +of that license document, provided that the further restriction does
2.400 +not survive such relicensing or conveying.
2.401 +
2.402 + If you add terms to a covered work in accord with this section, you
2.403 +must place, in the relevant source files, a statement of the
2.404 +additional terms that apply to those files, or a notice indicating
2.405 +where to find the applicable terms.
2.406 +
2.407 + Additional terms, permissive or non-permissive, may be stated in the
2.408 +form of a separately written license, or stated as exceptions;
2.409 +the above requirements apply either way.
2.410 +
2.411 + 8. Termination.
2.412 +
2.413 + You may not propagate or modify a covered work except as expressly
2.414 +provided under this License. Any attempt otherwise to propagate or
2.415 +modify it is void, and will automatically terminate your rights under
2.416 +this License (including any patent licenses granted under the third
2.417 +paragraph of section 11).
2.418 +
2.419 + However, if you cease all violation of this License, then your
2.420 +license from a particular copyright holder is reinstated (a)
2.421 +provisionally, unless and until the copyright holder explicitly and
2.422 +finally terminates your license, and (b) permanently, if the copyright
2.423 +holder fails to notify you of the violation by some reasonable means
2.424 +prior to 60 days after the cessation.
2.425 +
2.426 + Moreover, your license from a particular copyright holder is
2.427 +reinstated permanently if the copyright holder notifies you of the
2.428 +violation by some reasonable means, this is the first time you have
2.429 +received notice of violation of this License (for any work) from that
2.430 +copyright holder, and you cure the violation prior to 30 days after
2.431 +your receipt of the notice.
2.432 +
2.433 + Termination of your rights under this section does not terminate the
2.434 +licenses of parties who have received copies or rights from you under
2.435 +this License. If your rights have been terminated and not permanently
2.436 +reinstated, you do not qualify to receive new licenses for the same
2.437 +material under section 10.
2.438 +
2.439 + 9. Acceptance Not Required for Having Copies.
2.440 +
2.441 + You are not required to accept this License in order to receive or
2.442 +run a copy of the Program. Ancillary propagation of a covered work
2.443 +occurring solely as a consequence of using peer-to-peer transmission
2.444 +to receive a copy likewise does not require acceptance. However,
2.445 +nothing other than this License grants you permission to propagate or
2.446 +modify any covered work. These actions infringe copyright if you do
2.447 +not accept this License. Therefore, by modifying or propagating a
2.448 +covered work, you indicate your acceptance of this License to do so.
2.449 +
2.450 + 10. Automatic Licensing of Downstream Recipients.
2.451 +
2.452 + Each time you convey a covered work, the recipient automatically
2.453 +receives a license from the original licensors, to run, modify and
2.454 +propagate that work, subject to this License. You are not responsible
2.455 +for enforcing compliance by third parties with this License.
2.456 +
2.457 + An "entity transaction" is a transaction transferring control of an
2.458 +organization, or substantially all assets of one, or subdividing an
2.459 +organization, or merging organizations. If propagation of a covered
2.460 +work results from an entity transaction, each party to that
2.461 +transaction who receives a copy of the work also receives whatever
2.462 +licenses to the work the party's predecessor in interest had or could
2.463 +give under the previous paragraph, plus a right to possession of the
2.464 +Corresponding Source of the work from the predecessor in interest, if
2.465 +the predecessor has it or can get it with reasonable efforts.
2.466 +
2.467 + You may not impose any further restrictions on the exercise of the
2.468 +rights granted or affirmed under this License. For example, you may
2.469 +not impose a license fee, royalty, or other charge for exercise of
2.470 +rights granted under this License, and you may not initiate litigation
2.471 +(including a cross-claim or counterclaim in a lawsuit) alleging that
2.472 +any patent claim is infringed by making, using, selling, offering for
2.473 +sale, or importing the Program or any portion of it.
2.474 +
2.475 + 11. Patents.
2.476 +
2.477 + A "contributor" is a copyright holder who authorizes use under this
2.478 +License of the Program or a work on which the Program is based. The
2.479 +work thus licensed is called the contributor's "contributor version".
2.480 +
2.481 + A contributor's "essential patent claims" are all patent claims
2.482 +owned or controlled by the contributor, whether already acquired or
2.483 +hereafter acquired, that would be infringed by some manner, permitted
2.484 +by this License, of making, using, or selling its contributor version,
2.485 +but do not include claims that would be infringed only as a
2.486 +consequence of further modification of the contributor version. For
2.487 +purposes of this definition, "control" includes the right to grant
2.488 +patent sublicenses in a manner consistent with the requirements of
2.489 +this License.
2.490 +
2.491 + Each contributor grants you a non-exclusive, worldwide, royalty-free
2.492 +patent license under the contributor's essential patent claims, to
2.493 +make, use, sell, offer for sale, import and otherwise run, modify and
2.494 +propagate the contents of its contributor version.
2.495 +
2.496 + In the following three paragraphs, a "patent license" is any express
2.497 +agreement or commitment, however denominated, not to enforce a patent
2.498 +(such as an express permission to practice a patent or covenant not to
2.499 +sue for patent infringement). To "grant" such a patent license to a
2.500 +party means to make such an agreement or commitment not to enforce a
2.501 +patent against the party.
2.502 +
2.503 + If you convey a covered work, knowingly relying on a patent license,
2.504 +and the Corresponding Source of the work is not available for anyone
2.505 +to copy, free of charge and under the terms of this License, through a
2.506 +publicly available network server or other readily accessible means,
2.507 +then you must either (1) cause the Corresponding Source to be so
2.508 +available, or (2) arrange to deprive yourself of the benefit of the
2.509 +patent license for this particular work, or (3) arrange, in a manner
2.510 +consistent with the requirements of this License, to extend the patent
2.511 +license to downstream recipients. "Knowingly relying" means you have
2.512 +actual knowledge that, but for the patent license, your conveying the
2.513 +covered work in a country, or your recipient's use of the covered work
2.514 +in a country, would infringe one or more identifiable patents in that
2.515 +country that you have reason to believe are valid.
2.516 +
2.517 + If, pursuant to or in connection with a single transaction or
2.518 +arrangement, you convey, or propagate by procuring conveyance of, a
2.519 +covered work, and grant a patent license to some of the parties
2.520 +receiving the covered work authorizing them to use, propagate, modify
2.521 +or convey a specific copy of the covered work, then the patent license
2.522 +you grant is automatically extended to all recipients of the covered
2.523 +work and works based on it.
2.524 +
2.525 + A patent license is "discriminatory" if it does not include within
2.526 +the scope of its coverage, prohibits the exercise of, or is
2.527 +conditioned on the non-exercise of one or more of the rights that are
2.528 +specifically granted under this License. You may not convey a covered
2.529 +work if you are a party to an arrangement with a third party that is
2.530 +in the business of distributing software, under which you make payment
2.531 +to the third party based on the extent of your activity of conveying
2.532 +the work, and under which the third party grants, to any of the
2.533 +parties who would receive the covered work from you, a discriminatory
2.534 +patent license (a) in connection with copies of the covered work
2.535 +conveyed by you (or copies made from those copies), or (b) primarily
2.536 +for and in connection with specific products or compilations that
2.537 +contain the covered work, unless you entered into that arrangement,
2.538 +or that patent license was granted, prior to 28 March 2007.
2.539 +
2.540 + Nothing in this License shall be construed as excluding or limiting
2.541 +any implied license or other defenses to infringement that may
2.542 +otherwise be available to you under applicable patent law.
2.543 +
2.544 + 12. No Surrender of Others' Freedom.
2.545 +
2.546 + If conditions are imposed on you (whether by court order, agreement or
2.547 +otherwise) that contradict the conditions of this License, they do not
2.548 +excuse you from the conditions of this License. If you cannot convey a
2.549 +covered work so as to satisfy simultaneously your obligations under this
2.550 +License and any other pertinent obligations, then as a consequence you may
2.551 +not convey it at all. For example, if you agree to terms that obligate you
2.552 +to collect a royalty for further conveying from those to whom you convey
2.553 +the Program, the only way you could satisfy both those terms and this
2.554 +License would be to refrain entirely from conveying the Program.
2.555 +
2.556 + 13. Use with the GNU Affero General Public License.
2.557 +
2.558 + Notwithstanding any other provision of this License, you have
2.559 +permission to link or combine any covered work with a work licensed
2.560 +under version 3 of the GNU Affero General Public License into a single
2.561 +combined work, and to convey the resulting work. The terms of this
2.562 +License will continue to apply to the part which is the covered work,
2.563 +but the special requirements of the GNU Affero General Public License,
2.564 +section 13, concerning interaction through a network will apply to the
2.565 +combination as such.
2.566 +
2.567 + 14. Revised Versions of this License.
2.568 +
2.569 + The Free Software Foundation may publish revised and/or new versions of
2.570 +the GNU General Public License from time to time. Such new versions will
2.571 +be similar in spirit to the present version, but may differ in detail to
2.572 +address new problems or concerns.
2.573 +
2.574 + Each version is given a distinguishing version number. If the
2.575 +Program specifies that a certain numbered version of the GNU General
2.576 +Public License "or any later version" applies to it, you have the
2.577 +option of following the terms and conditions either of that numbered
2.578 +version or of any later version published by the Free Software
2.579 +Foundation. If the Program does not specify a version number of the
2.580 +GNU General Public License, you may choose any version ever published
2.581 +by the Free Software Foundation.
2.582 +
2.583 + If the Program specifies that a proxy can decide which future
2.584 +versions of the GNU General Public License can be used, that proxy's
2.585 +public statement of acceptance of a version permanently authorizes you
2.586 +to choose that version for the Program.
2.587 +
2.588 + Later license versions may give you additional or different
2.589 +permissions. However, no additional obligations are imposed on any
2.590 +author or copyright holder as a result of your choosing to follow a
2.591 +later version.
2.592 +
2.593 + 15. Disclaimer of Warranty.
2.594 +
2.595 + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
2.596 +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
2.597 +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
2.598 +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
2.599 +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2.600 +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
2.601 +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
2.602 +ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
2.603 +
2.604 + 16. Limitation of Liability.
2.605 +
2.606 + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
2.607 +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
2.608 +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
2.609 +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
2.610 +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
2.611 +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
2.612 +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
2.613 +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
2.614 +SUCH DAMAGES.
2.615 +
2.616 + 17. Interpretation of Sections 15 and 16.
2.617 +
2.618 + If the disclaimer of warranty and limitation of liability provided
2.619 +above cannot be given local legal effect according to their terms,
2.620 +reviewing courts shall apply local law that most closely approximates
2.621 +an absolute waiver of all civil liability in connection with the
2.622 +Program, unless a warranty or assumption of liability accompanies a
2.623 +copy of the Program in return for a fee.
2.624 +
2.625 + END OF TERMS AND CONDITIONS
2.626 +
2.627 + How to Apply These Terms to Your New Programs
2.628 +
2.629 + If you develop a new program, and you want it to be of the greatest
2.630 +possible use to the public, the best way to achieve this is to make it
2.631 +free software which everyone can redistribute and change under these terms.
2.632 +
2.633 + To do so, attach the following notices to the program. It is safest
2.634 +to attach them to the start of each source file to most effectively
2.635 +state the exclusion of warranty; and each file should have at least
2.636 +the "copyright" line and a pointer to where the full notice is found.
2.637 +
2.638 + <one line to give the program's name and a brief idea of what it does.>
2.639 + Copyright (C) <year> <name of author>
2.640 +
2.641 + This program is free software: you can redistribute it and/or modify
2.642 + it under the terms of the GNU General Public License as published by
2.643 + the Free Software Foundation, either version 3 of the License, or
2.644 + (at your option) any later version.
2.645 +
2.646 + This program is distributed in the hope that it will be useful,
2.647 + but WITHOUT ANY WARRANTY; without even the implied warranty of
2.648 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2.649 + GNU General Public License for more details.
2.650 +
2.651 + You should have received a copy of the GNU General Public License
2.652 + along with this program. If not, see <http://www.gnu.org/licenses/>.
2.653 +
2.654 +Also add information on how to contact you by electronic and paper mail.
2.655 +
2.656 + If the program does terminal interaction, make it output a short
2.657 +notice like this when it starts in an interactive mode:
2.658 +
2.659 + <program> Copyright (C) <year> <name of author>
2.660 + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
2.661 + This is free software, and you are welcome to redistribute it
2.662 + under certain conditions; type `show c' for details.
2.663 +
2.664 +The hypothetical commands `show w' and `show c' should show the appropriate
2.665 +parts of the General Public License. Of course, your program's commands
2.666 +might be different; for a GUI interface, you would use an "about box".
2.667 +
2.668 + You should also get your employer (if you work as a programmer) or school,
2.669 +if any, to sign a "copyright disclaimer" for the program, if necessary.
2.670 +For more information on this, and how to apply and follow the GNU GPL, see
2.671 +<http://www.gnu.org/licenses/>.
2.672 +
2.673 + The GNU General Public License does not permit incorporating your program
2.674 +into proprietary programs. If your program is a subroutine library, you
2.675 +may consider it more useful to permit linking proprietary applications with
2.676 +the library. If this is what you want to do, use the GNU Lesser General
2.677 +Public License instead of this License. But first, please read
2.678 +<http://www.gnu.org/philosophy/why-not-lgpl.html>.
2.679 +
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/ChangeLog Mon Dec 06 13:09:21 2010 +0100
3.3 @@ -0,0 +1,2356 @@
3.4 +Sun Dec 05 12:00:00 2010 Andrew Makhorin <mao@gnu.org>
3.5 +
3.6 + * GLPK 4.45 (30:0:30) has been released
3.7 +
3.8 + * glplpx01.c
3.9 + A bug (it_cnt) in routine reset_parms was fixed.
3.10 + Thanks to Ali Baharev <ali.baharev@gmail.com> for report.
3.11 +
3.12 + * glpmpl03.c
3.13 + A bug (print "text\") was fixed.
3.14 + Thanks to Xypron <xypron.glpk@gmx.de> for report.
3.15 +
3.16 + * glpsql.c
3.17 + A precision bug was fixed.
3.18 + Thanks to Xypron <xypron.glpk@gmx.de>.
3.19 +
3.20 + * glpk.tex
3.21 + Some typos were corrected.
3.22 + Thanks to Robbie Morrison <robbie@actrix.co.nz>.
3.23 +
3.24 +Thu Jun 03 12:00:00 2010 Andrew Makhorin <mao@gnu.org>
3.25 +
3.26 + * GLPK 4.44 (29:0:29) has been released
3.27 +
3.28 + * glpapi14.c glpmpl.h glpmpl01.c glpmpl03.c glpmpl04.c
3.29 + Implemented suffixes for variables and constraints.
3.30 +
3.31 + * glpmpl06.c
3.32 + Made changes to allow comment records in CSV files.
3.33 +
3.34 + * glpapi17.c
3.35 + Added and documented new API routine glp_cpp to solve Critical
3.36 + Path Problem.
3.37 +
3.38 +Sat Feb 20 12:00:00 2010 Andrew Makhorin <mao@gnu.org>
3.39 +
3.40 + * GLPK 4.43 (28:0:28) has been released
3.41 +
3.42 + * glplib.h, glplib.c, glpenv.h, glpenv.c
3.43 + The module glpenv was split into two modules glpenv and glplib.
3.44 +
3.45 + * glpenv01.c, glpenv03.c, glpenv04.c, glpenv06.c
3.46 + The following new API routines were added and documented:
3.47 + glp_init_env, glp_free_env, glp_open_tee, glp_close_tee,
3.48 + glp_error (macro), glp_difftime.
3.49 +
3.50 + * glpapi16.c
3.51 + New API routine glp_top_sort (topological sorting of ayclic
3.52 + digraph) was added and documented.
3.53 +
3.54 + * glpapi17.c
3.55 + A serious bug was fixed in the routine glp_asn_prob_hall.
3.56 +
3.57 + * glpnpp05.c
3.58 + A bug was fixed in the LP/MIP preprocessor (hidden covering
3.59 + inequalities).
3.60 +
3.61 + * glpsql.c
3.62 + Some improvements were made in the table driver (NULL data).
3.63 + Thanks to Xypron <xypron.glpk@gmx.de> for contribution.
3.64 +
3.65 + * configure.ac
3.66 + Changes were made to use .dylib rather than .so under Mac OS.
3.67 + Thanks to Noli Sicad <nsicad@gmail.com> for testing
3.68 +
3.69 +Wed Jan 13 12:00:00 2010 Andrew Makhorin <mao@gnu.org>
3.70 +
3.71 + * GLPK 4.42 (27:0:27) has been released
3.72 +
3.73 + * glpapi01.c, glpapi11.c, glpapi12.c, glpdmx.c
3.74 + The following new API routines were added and documented:
3.75 + glp_check_dup (check for duplicate elements in sparse matrix);
3.76 + glp_sort_matrix (sort elements of the constraint matrix);
3.77 + glp_read_prob (read problem data in GLPK format);
3.78 + glp_write_prob (write problem data in GLPK format);
3.79 + glp_analyze_bound (analyze active bound of non-basic variable);
3.80 + glp_analyze_coef (analyze obj. coefficient at basic variable);
3.81 + glp_print_ranges (print sensitivity analysis report; replaces
3.82 + lpx_print_sens_bnds).
3.83 +
3.84 + * glpapi20.c
3.85 + New command-line options were added to glpsol:
3.86 + --glp (read problem data in GLPK format);
3.87 + --wglp (write problem data in GLPK format);
3.88 + --lp (replaces --cpxlp);
3.89 + --wlp (replaces --wcpxlp);
3.90 + --ranges (print sensitivity analysis report).
3.91 +
3.92 + * glpapi06.c
3.93 + In the routine glp_init_smcp default value of the parameter
3.94 + out_frq was changed to 500 (it was 200).
3.95 +
3.96 + * glpipp.h, glpipp01.c, glpipp02.c
3.97 + The old MIP preprocessor module was removed.
3.98 +
3.99 + * glpapi09.c
3.100 + Now the MIP solver uses the new MIP preprocessor (NPP).
3.101 +
3.102 + * glplpx03.c
3.103 + lpx_write_opb was disabled due to replacing IPP with NPP.
3.104 +
3.105 + * glpnet09.c
3.106 + Kellerman's heuristic to cover edges by cliques was added.
3.107 +
3.108 + * glplib08.c
3.109 + Recognition of special filenames "/dev/stdin", "/dev/stdout",
3.110 + and "/dev/stderr" was added.
3.111 +
3.112 + * glpk.tex
3.113 + Chapter "Graph and network routines" was carried out from the
3.114 + reference manual as a separate document.
3.115 +
3.116 +Mon Dec 21 12:00:00 2009 Andrew Makhorin <mao@gnu.org>
3.117 +
3.118 + * GLPK 4.41 (26:0:26) has been released
3.119 +
3.120 + * glpapi12.c
3.121 + The following new API routines were added:
3.122 + glp_transform_row (replaces lpx_transform_row);
3.123 + glp_transform_col (replaces lpx_transform_col);
3.124 + glp_prim_rtest (replaces lpx_prim_ratio_test);
3.125 + glp_dual_rtest (replaces lpx_dual_ratio_test).
3.126 + Note that values returned by glp_prim_rtest and glp_dual_rtest
3.127 + differ from the ones retutned by the deprecated routines.
3.128 +
3.129 + * glpnpp*.*
3.130 + The LP/MIP preprocessor was essentially re-implemented.
3.131 +
3.132 + * glpios03.c
3.133 + The feature to remove inactive cuts from the active subproblem
3.134 + was implemented.
3.135 +
3.136 + * glpios11.c
3.137 + The feature processing cuts stored in the cut pool was improved
3.138 + (now it uses estimation of objective degradation).
3.139 +
3.140 + * glpscg.*
3.141 + Obsolete implemetation of the conflict graph was removed.
3.142 +
3.143 + * glpmpl.h, glpmpl03.c, glpmpl04.c
3.144 + FILE was replaced by XFILE to allow using GLPK I/O routines.
3.145 +
3.146 + * glpsql.c, examples/sql, doc/tables.tex
3.147 + The SQL table driver was changed to allow multiple arguments
3.148 + separated by semicolon in SQL statements. Thanks to Xypron
3.149 + <xypron.glpk@gmx.de>.
3.150 +
3.151 + * glpk.h, glpapi14.c
3.152 + New API routine glp_time was added (not documented yet).
3.153 +
3.154 + * glpapi20.c
3.155 + Two new options were added to glpsol: --seed value (initialize
3.156 + pseudo-random number generator used in MathProg model with
3.157 + specified seed value), and --ini filename (use as initial basis
3.158 + previously saved with -w option).
3.159 +
3.160 + * examples/xyacfs.mod
3.161 + Thanks to Nigel Galloway <nigel_galloway@operamail.com> for
3.162 + contribution.
3.163 +
3.164 + * examples/dbf/*.*
3.165 + Thanks to Noli Sicad <nsicad@gmail.com> for contribution.
3.166 +
3.167 + * w32/*.*, w64/*.*
3.168 + Scripts to build GLPK with Microsoft Visual Studio 2010 were
3.169 + added. Thanks to Xypron <xypron.glpk@gmx.de> for contribution
3.170 + and testing.
3.171 +
3.172 +Tue Nov 03 12:00:00 2009 Andrew Makhorin <mao@gnu.org>
3.173 +
3.174 + * GLPK 4.40 (25:0:25) has been released
3.175 +
3.176 + * glpdmx.c
3.177 + Two new API routines were added:
3.178 + glp_read_ccdata (read graph in DIMACS clique/coloring format);
3.179 + glp_write_ccdata (write graph in DIMACS clique/coloring format).
3.180 + Also an example file examples/sample.col was added.
3.181 +
3.182 + * glpapi19.c, glpnet08.c
3.183 + New API routine glp_wclique_exact was added. It is intended to
3.184 + find a maximum weight clique with the exact algorithm developed
3.185 + by Prof. P. Ostergard.
3.186 +
3.187 + * glpnpp02.c
3.188 + A bug was fixed in the LP preprocessor (routine npp_empty_col).
3.189 + Thanks to Stefan Vigerske <stefan@math.hu-berlin.de> for the
3.190 + bug report.
3.191 +
3.192 + * glpios10.c
3.193 + A bug was fixed and some improvements were made in the FPUMP
3.194 + heuristic module. Thanks to Xypron <xypron.glpk@gmx.de>.
3.195 +
3.196 + * glpapi12.c
3.197 + A bug was fixed in the API routine glp_warm_up (dual
3.198 + feasibility test was incorrect in maximization case). Thanks to
3.199 + Uday Venkatadri <Uday.Venkatadri@dal.ca> for the bug report.
3.200 +
3.201 + * glpapi16.c
3.202 + Two new API routines were added:
3.203 + glp_del_vertices (remove vertices from graph);
3.204 + glp_del_arc (remove arc from graph).
3.205 +
3.206 + * glpios09.c
3.207 + The hybrid pseudocost branching heuristic was included in the
3.208 + MIP solver. It is available on API level (iocp.br_tech should
3.209 + be set to GLP_BR_PCH) and in the stand-alone solver glpsol
3.210 + (via the command-line option --pcost). This heuristic may be
3.211 + useful on solving hard MIP instances.
3.212 +
3.213 + * glpios03.c
3.214 + The branching heuristic by Driebeck and Tomlin (used in the
3.215 + MIP solver by default) was changed to switch to branching on
3.216 + most fractional variable if an lower bound of degradation of
3.217 + the objective is close to zero for all branching candidates.
3.218 +
3.219 +Sun Jul 26 12:00:00 2009 Andrew Makhorin <mao@mai2.rcnet.ru>
3.220 +
3.221 + * GLPK 4.39 (24:0:24) has been released
3.222 +
3.223 + * glpsdf.c
3.224 + New API routines to read plain data files were added.
3.225 +
3.226 + * glpcpx.h, glpini.h, glpscl.h
3.227 + These headers were removed.
3.228 +
3.229 + * glpcpx.c
3.230 + API routines glp_read_lp and glp_write_lp to read/write files
3.231 + in CPLEX LP format were re-implemented. Now glp_write_lp
3.232 + correctly writes double-bounded (ranged) rows by introducing
3.233 + slack variables rather than by duplicating the rows. The data
3.234 + structure glp_cpxcp and routine glp_init_cpxcp were added.
3.235 +
3.236 + * amd/*
3.237 + The 'xfree(NULL)' bug was fixed in the AMD routines. Thanks to
3.238 + Niels Klitgord <niels@bu.edu> for the bug report.
3.239 +
3.240 + * glpapi16.c
3.241 + New API routines glp_set_vertex_name, glp_create_v_index,
3.242 + glp_find_vertex, and glp_delete_v_index were added.
3.243 +
3.244 + * glpdmx.c
3.245 + New API routines glp_read_asnprob, glp_write_asnprob,
3.246 + glp_read_ccformat, and glp_write_ccformat were added (the two
3.247 + latter routines are not documented yet).
3.248 +
3.249 + * glpapi18.c
3.250 + New API routines glp_check_asnprob, glp_asnprob_lp,
3.251 + glp_asnprob_okalg, and glp_asnprob_hall were added.
3.252 +
3.253 + * glpini01.c, glpini02.c
3.254 + The message "Crashing..." was changed to "Constructing initial
3.255 + basis..." due to suggestion by Thomas Kahle <tom111@gmx.de>.
3.256 +
3.257 + * glpapi14.c
3.258 + New API routines glp_printf, glp_vprintf, glp_malloc,
3.259 + glp_calloc, glp_free, and glp_assert were added.
3.260 +
3.261 + * glplpp.h, glplpp01.c, glplpp02.c
3.262 + Old LP presolver routines were removed. Now glp_simplex uses
3.263 + new preprocessing routines (see glpnpp).
3.264 +
3.265 + * glpapi12.c
3.266 + New API routine glp_warm_up was added; it replaces the routine
3.267 + lpx_warm_up.
3.268 +
3.269 +Sat May 02 12:00:00 2009 Andrew Makhorin <mao@mai2.rcnet.ru>
3.270 +
3.271 + * GLPK 4.38 (23:0:23) has been released
3.272 +
3.273 + * glpmps.c
3.274 + API routines to read/write MPS files were re-implemented.
3.275 +
3.276 + * glpspx02.c
3.277 + Some improvements were made in the dual simplex routine.
3.278 +
3.279 + * glpk.h
3.280 + New structure glp_iptcp was added.
3.281 +
3.282 + * glpnpp.h, glpnpp01.c, glpnpp02.c
3.283 + New LP/MIP preprocessor. Currently it includes only some basic
3.284 + routines and used only in the interior-point solver.
3.285 +
3.286 + * glpapi08.c
3.287 + API routine glp_interior was replaced by an improved version
3.288 + (new LP/MIP preprocessor, new ordering algorithms).
3.289 +
3.290 + New API routine glp_init_iptcp was added.
3.291 +
3.292 + API routine glp_ipt_status may return two new statuses due to
3.293 + changes in glp_interior.
3.294 +
3.295 + * glpsol.c
3.296 + New command-line options were added (ordering algorithm used in
3.297 + the interior-point solver).
3.298 +
3.299 + * amd/*.*, colamd/*.*
3.300 + Two external software modules AMD and COLAMD/SYMAMD used in the
3.301 + interior-point solver were included in the distribution.
3.302 +
3.303 + For details see amd/README and colamd/README.
3.304 +
3.305 + * glpnet03.c, glpnet04.c, glpnet05.c
3.306 + A minor bug was fixed (_G => G_). Thanks to Nelson H. F. Beebe
3.307 + <beebe@math.utah.edu> for bug report.
3.308 +
3.309 +Sun Mar 29 12:00:00 2009 Andrew Makhorin <mao@mai2.rcnet.ru>
3.310 +
3.311 + * GLPK 4.37 (22:0:22) has been released
3.312 +
3.313 + * glpk.h
3.314 + iocp.fp_heur was added to enable/disable fpump heuristic.
3.315 +
3.316 + * glpios10.c
3.317 + ios_feas_pump was added (feasibility pump heuristic).
3.318 +
3.319 + * glpsol.c
3.320 + --fpump command-line option was added.
3.321 +
3.322 + * glpsds.c
3.323 + Plain data set routines were added to facilitate reading plain
3.324 + data in application programs. Currently these routines are not
3.325 + in API, though declared in glpk.h.
3.326 +
3.327 + * glpapi08.c
3.328 + A bug was fixed in the internal routine restore. (Due to this
3.329 + bug dual solution components were computed incorrectly if the
3.330 + problem was scaled.)
3.331 +
3.332 + * glpapi10.c, glpapi11.c
3.333 + The following new API routines were added:
3.334 + glp_print_sol (replaces lpx_print_sol);
3.335 + glp_print_ipt (replaces lpx_print_ips);
3.336 + glp_print_mip (replaces lpx_print_mip);
3.337 + _glp_check_kkt (replaces lpx_check_kkt, lpx_check_int).
3.338 + Now the routine lpx_print_prob (deprecated) is equivalent to
3.339 + the routine glp_write_lp.
3.340 +
3.341 + * glpapi18.c, glpapi19.c
3.342 + The following new API routines were added:
3.343 + glp_read_graph (read graph from plain text file);
3.344 + glp_write_graph (write graph to plain text file);
3.345 + glp_weak_comp (find all weakly connected components);
3.346 + glp_strong_comp (find all strongly connected components).
3.347 +
3.348 + * configure.ac, Makefile.am
3.349 + Changes were made: (a) to allow using autoreconf/autoheader;
3.350 + (b) to allow building glpk in a directory other than its source
3.351 + directory. Thanks to Marco Atzeri <marco_atzeri@yahoo.it> for
3.352 + bug report.
3.353 +
3.354 + * examples/shiftcover.mod
3.355 + An example model in MathProg was added.
3.356 + Thanks to Larry D'Agostino <Larry.D'Agostino@gmacrescap.com>
3.357 + for contribution.
3.358 +
3.359 +Fri Feb 06 12:00:00 2009 Andrew Makhorin <mao@mai2.rcnet.ru>
3.360 +
3.361 + * GLPK 4.36 (21:0:21) has been released
3.362 +
3.363 + * glpnet06.c, glpnet07.c, glpapi19.c
3.364 + The following new API routines were added:
3.365 + glp_mincost_okalg find minimum-cost flow with out-of-kilter
3.366 + algorithm
3.367 + glp_maxflow_ffalg find maximal flow with Ford-Fulkerson
3.368 + algorithm
3.369 +
3.370 + * glpsol.c
3.371 + Two new command-line options were added:
3.372 + --mincost read min-cost flow data in DIMACS format
3.373 + --maxflow read maximum flow data in DIMACS format
3.374 +
3.375 + * doc/glpk.*
3.376 + New edition of the reference manual was included.
3.377 +
3.378 + * glpk.h
3.379 + Duplicate symbols were removed to allow using swig.
3.380 + Thanks to Kelly Westbrooks <kellywestbrooks@yahoo.com> and
3.381 + Nigel Galloway <nigel_galloway@operamail.com> for suggestion.
3.382 +
3.383 + * glpcpx.c
3.384 + A minor defect was fixed in the routine glp_write_lp.
3.385 + Thanks to Sebastien Briais <sbriais@free.fr> for bug report.
3.386 +
3.387 + * glpsql.c
3.388 + A minor bug was fixed. Thanks to Xypron <xypron.glpk@gmx.de>
3.389 + for patch.
3.390 +
3.391 + * examples/hashi.mod, examples/shikaku.mod
3.392 + Two example models in MathProg were added. Thanks to Sebastian
3.393 + Nowozin <nowozin@gmail.com> for contribution.
3.394 +
3.395 + * examples/qfit.mod, examples/yacfs.mod
3.396 + Two example models in MathProg were added. Thanks to Nigel
3.397 + Galloway <nigel_galloway@operamail.com> for contribution.
3.398 +
3.399 +Fri Jan 09 12:00:00 2009 Andrew Makhorin <mao@mai2.rcnet.ru>
3.400 +
3.401 + * GLPK 4.35 (20:0:20) has been released
3.402 +
3.403 + * glpk.h, glpapi.c, glpnet.c
3.404 + The following new API routines were added:
3.405 + glp_create_graph create graph
3.406 + glp_set_graph_name assign (change) graph name
3.407 + glp_add_vertices add new vertices to graph
3.408 + glp_add_arc add new arc to graph
3.409 + glp_erase_graph erase graph content
3.410 + glp_delete_graph delete graph
3.411 + glp_read_mincost read minimum cost flow problem data in
3.412 + DIMACS format
3.413 + glp_write_mincost write minimum cost flow problem data in
3.414 + DIMACS format
3.415 + glp_mincost_lp convert minimum cost flow problem to LP
3.416 + glp_netgen Klingman's network problem generator
3.417 + glp_gridgen grid-like network problem generator
3.418 + glp_read_maxflow read maximum flow problem data in DIMACS
3.419 + format
3.420 + glp_write_maxflow write maximum flow problem data in DIMACS
3.421 + format
3.422 + glp_maxflow_lp convert maximum flow problem to LP
3.423 + glp_rmfgen Goldfarb's maximum flow problem generator
3.424 +
3.425 + * doc/glpk.*
3.426 + New edition of the reference manual was included.
3.427 +
3.428 + * examples/sample.min, examples/sample.max
3.429 + Two example data files in DIMACS format were added.
3.430 +
3.431 + * glplib04.c
3.432 + The statement "if (c = '\n') fflush(stdout)" was added to the
3.433 + internal routine xputc to provide "real-time" terminal output.
3.434 + Thanks to Luiz Bettoni <bettoni@cpgei.ct.utfpr.edu.br> for
3.435 + suggestion.
3.436 +
3.437 + * glpmpl05.c
3.438 + A minor bug was fixed in the internal routine mpl_fn_time2str.
3.439 + Thanks to Stefan Vigerske <stefan@vigerske.de> for bug report.
3.440 +
3.441 + * w32/makefile, w64/makefile
3.442 + The flag -O2 (/O2) was added to some makefiles.
3.443 +
3.444 +Thu Dec 04 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
3.445 +
3.446 + * GLPK 4.34 (19:0:19) has been released
3.447 +
3.448 + * src/glpios03.c
3.449 + A bug was fixed in the internal routine branch_on. Thanks to
3.450 + Nigel Galloway <nigel_galloway@operamail.com> for bug report.
3.451 +
3.452 + * src/glpmpl05.c
3.453 + Three new MathProg functions were included:
3.454 + gmtime obtaining current calendar time
3.455 + str2time converting character string to calendar time
3.456 + time2str converting calendar time to character string
3.457 + Thanks to Xypron <xypron.glpk@gmx.de>.
3.458 +
3.459 + * doc/glpk.*, doc/gmpl.*
3.460 + A new edition of the GLPK reference manual and GNU MathProg
3.461 + language description were included.
3.462 +
3.463 +Thu Oct 30 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
3.464 +
3.465 + * GLPK 4.33 (18:0:18) has been released
3.466 +
3.467 + * glpapi*.*
3.468 + The following new API routines were added:
3.469 + glp_copy_prob copy problem object content
3.470 + glp_exact solve LP in exact arithmetic
3.471 + (makes lpx_exact deprecated)
3.472 + glp_get_unbnd_ray determine variable causing unboundedness
3.473 + (makes lpx_get_ray_info deprecated)
3.474 + glp_interior solve LP with interior-point method
3.475 + (makes lpx_interior deprecated)
3.476 +
3.477 + * glpapi*.*
3.478 + The following new API routines for processing models written in
3.479 + the GNU Mathprog language were added to the package:
3.480 + glp_mpl_alloc_wksp allocate the translator workspace
3.481 + glp_mpl_read_model read and translate model section
3.482 + glp_mpl_read_data read and translate data section
3.483 + glp_mpl_generate generate the model
3.484 + glp_mpl_build_prob build LP/MIP instance from the model
3.485 + glp_mpl_postsolve postsolve the model
3.486 + glp_mpl_free_wksp deallocate the translator workspace
3.487 + (These routines make lpx_read_model deprecated.)
3.488 +
3.489 + * src/glpapi17.c, examples/glpsol.c
3.490 + The stand-alone solver glpsol was re-implemented with new API
3.491 + routines.
3.492 +
3.493 + * src/glpsql.c
3.494 + Some bugs were fixed in the SQL table driver. Thanks to Xypron
3.495 + <xypron.glpk@gmx.de>.
3.496 +
3.497 + * examples/cplex/*.*
3.498 + A crude implementation of CPLEX-like interface to GLPK API was
3.499 + added to the package. See examples/cplex/README.
3.500 +
3.501 +Fri Oct 03 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
3.502 +
3.503 + * GLPK 4.32 (17:0:17) has been released
3.504 +
3.505 + * glpmpl01.c
3.506 + A bug was fixed. Due to this bug iterated expressions having
3.507 + an indexing expression whose dummy indices are bound to some
3.508 + values, i.e. like sum{(i+1,j,k-1) in E} x[i,j,k] are evaluated
3.509 + incorrectly. Namely, current value of such expressions is not
3.510 + invalidated when corresponding dummy indices (like i and k in
3.511 + the example above) are changed, that erroneously results in the
3.512 + same value evaluated for the first time.
3.513 +
3.514 + * glpios03.c
3.515 + Euclidean reduction of the local objective bound was added in
3.516 + the routine glpios03.c.
3.517 +
3.518 + * glpapi11.c
3.519 + The following new branch-and-cut API routines were added:
3.520 + glp_ios_row_attr determine additional row attributes;
3.521 + glp_ios_pool_size determine current size of the cut pool;
3.522 + glp_ios_add_row add constraint to the cut pool;
3.523 + glp_ios_del_row delete constraint from the cut pool;
3.524 + glp_ios_clear_pool delete all constraints from the cut pool.
3.525 +
3.526 + * glpapi08.c
3.527 + The following new features were included in the branch-and-cut
3.528 + solver (the API routine glp_intopt):
3.529 + MIP presolver;
3.530 + mixed cover cut generator;
3.531 + clique cut generator.
3.532 + Due to the MIP presolver glp_intopt may additionally return
3.533 + GLP_ENOPFS and GLP_ENODFS, if primal or dual infeasibility of
3.534 + LP relaxation is detected by the presolver. Also the return
3.535 + code GLP_EMIPGAP was introduced to correctly indicate that the
3.536 + mip gap tolerance is reached.
3.537 +
3.538 + * glplpx01.c
3.539 + Now the obsolete API routines lpx_integer and lpx_intopt are
3.540 + completely superseded by the API routine glp_intopt that makes
3.541 + them deprecated.
3.542 +
3.543 + * glpmpl05.c
3.544 + Now the table driver name "iODBC" can be specified as "ODBC".
3.545 +
3.546 + * glpmpl03.c
3.547 + A bug fixed in the routine free_dca.
3.548 + Thanks to Xypron <xypron.glpk@gmx.de>.
3.549 +
3.550 + * glpsql.c
3.551 + A bug was fixed in the SQL table driver.
3.552 + Thanks to Xypron <xypron.glpk@gmx.de>.
3.553 +
3.554 + * examples/glpsol.c
3.555 + Changes were made to allow multiple MathProg data files.
3.556 +
3.557 + * doc/glpk.*
3.558 + A new edition of the GLPK reference manual was included.
3.559 +
3.560 + * doc/tables.*
3.561 + A new edition of the supplement "Using data tables in the GNU
3.562 + MathProg language" was included.
3.563 +
3.564 +Tue Sep 02 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
3.565 +
3.566 + * GLPK 4.31 (16:0:16) has been released
3.567 +
3.568 + * glpspx.h, glpspx01.c, glpspx02.c, glpapi06.c
3.569 + The dual simplex solver (spx_dual_opt) was replaced by a new
3.570 + implementation of the two-phase dual simplex method (spx_dual).
3.571 + Old simplex method routines (spx_prim_opt, spx_prim_feas, and
3.572 + spx_dual_opt) were removed from the package.
3.573 +
3.574 + * glpk.h, glpscl.h, glpscl.c, glpapi04.c
3.575 + New API routine glp_scale_prob was added. It replaces routine
3.576 + lpx_scale_prob which is deprecated.
3.577 +
3.578 + * glpk.h, glpini.h, glpini01.c, glpini02.c, glpapi05.c
3.579 + New API routines glp_std_basis, glp_adv_basis, glp_cpx_basis
3.580 + were added. They replace routines lpx_std_basis, lpx_adv_basis,
3.581 + lpx_cpx_basis which are deprecated.
3.582 +
3.583 + * glpdmp.c
3.584 + 8-byte data alignment was added to the module (sufficient for
3.585 + both ILP32 and LP64 environments).
3.586 +
3.587 + * glplib07.c
3.588 + 16-byte data alignment was added to the module to provide
3.589 + compatibility with LP64 environment (8-byte is not sufficient
3.590 + due to jmp_buf; thanks to Xypron for investigation).
3.591 +
3.592 + * glplpx16.c
3.593 + New version of the routine lpx_write_pb was added. Thanks to
3.594 + Oscar Gustafsson <oscarg@isy.liu.se> for the contribution.
3.595 +
3.596 + * w32/VC9, w64/VC9
3.597 + Makefiles and batch files were added to build GLPK under 32-
3.598 + and 64-bit Windows with Microsoft Visual Studio Express 2008.
3.599 + Thanks to Heinrich Schuchardt <heinrich.schuchardt@gmx.de> for
3.600 + the contribution and testing.
3.601 +
3.602 + * w32/DM, w32/OWC
3.603 + Makefiles and batch files were added to build GLPK with Digital
3.604 + Mars C/C++ 8.50 and Open Watcom C/C++ 1.6 (32-bit Windows).
3.605 +
3.606 +Wed Aug 13 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
3.607 +
3.608 + * GLPK 4.30 (15:0:15) has been released
3.609 +
3.610 + * glpspx.h, glpspx03.c, glpapi06.c
3.611 + The primal simplex solver (spx_prim_opt, spx_prim_feas) was
3.612 + replaced by a new implementation (spx_primal), which currently
3.613 + provides the same features as the old version.
3.614 +
3.615 + * glpmpl01.c, glpmpl03.c
3.616 + Some changes were made in the MathProg translator to allow <,
3.617 + <=, >=, and > on comparing symbolic values. Thanks to Heinrich
3.618 + Schuchardt <heinrich.schuchardt@gmx.de> for patches.
3.619 +
3.620 + * glplpx10.c
3.621 + Internal routine set_d_eps in the exact LP solver was changed
3.622 + to prevent approximation errors in case of integral data.
3.623 + Thanks to Markus Pilz <pilz@cs.uni-bonn.de> for bug report.
3.624 +
3.625 +XXX XXX XX 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
3.626 +
3.627 + * GLPK 4.29 (14:0:14) has been released
3.628 +
3.629 + * configure.ac
3.630 + The configure script was changed to disable optional features
3.631 + by default. For details see file INSTALL.
3.632 +
3.633 + * glpipp02.c
3.634 + A bug was fixed in the internal routine reduce_bounds. Thanks
3.635 + to Anne-Laurence Putz <anne-laurence.putz@eurodecision.com> for
3.636 + the bug report.
3.637 +
3.638 + * glpapi01.c
3.639 + New API routine glp_erase_prob was added.
3.640 +
3.641 + * glpapi13.c
3.642 + New API routines glp_read_mps and glp_write_mps were added.
3.643 + They replace API routines lpx_read_mps, lpx_read_freemps,
3.644 + lpx_write_mps, and lpx_write_freemps, which are deprecated.
3.645 +
3.646 + * glpapi14.c
3.647 + New API routines glp_read_lp and glp_write_lp were added. They
3.648 + replace API routines lpx_read_cpxlp and lpx_write_cpxlp, which
3.649 + are deprecated.
3.650 +
3.651 + * glpsql.c
3.652 + Minor bug was fixed. Thanks to Xypron <xypron.glpk@gmx.de> for
3.653 + the bug report.
3.654 +
3.655 +Tue Mar 25 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
3.656 +
3.657 + * GLPK 4.28 (13:0:13) has been released
3.658 +
3.659 + * glplib.h, glplib.c
3.660 + Three wrapper routines xdlopen, xdlsym, and xdlclose, which
3.661 + provide the shared library support, were added. A particular
3.662 + version of these routines depends on the option --enable-dl
3.663 + passed to the configure script (see file INSTALL for details).
3.664 + Thanks to Rafael Laboissiere <rafael@debian.org> for useful
3.665 + advices concerning the shared library support.
3.666 +
3.667 + * glpsql.c
3.668 + A static linking to iODBC and MySQL libraries used in the
3.669 + MathProg table drivers was replaced by a dynamic linking to
3.670 + corresponding shared libraries.
3.671 + Many thanks to Heinrich Schuchardt <heinrich.schuchardt@gmx.de>
3.672 + for the contribution and to Vijay Patil <vijay.patil@gmail.com>
3.673 + for testing this feature under Windows XP.
3.674 +
3.675 + * glpgmp.h, glpgmp.c
3.676 + A bug (which appeared only on 64-bit platforms) was fixed.
3.677 + Thanks to Axel Simon <Axel.Simon@ens.fr> for the bug report.
3.678 +
3.679 + * glpapi.c
3.680 + A bug was fixed in the api routine glp_add_cols. (If the basis
3.681 + is valid, adding column keeps it valid, however, col->bind was
3.682 + set to -1 rather to 0.)
3.683 + Thanks to Cedric[FR] <fox2113@wanadoo.fr> for the bug report.
3.684 +
3.685 + * glplib.c
3.686 + 64-bit unsigned int type glp_ulong and corresponding routines
3.687 + were replaced by 64-bit signed int type xlong_t.
3.688 +
3.689 + * glpk.h, glpapi.c
3.690 + The type glp_ulong was replaced by glp_long. This affects only
3.691 + the api routine glp_mem_usage.
3.692 +
3.693 + * glplib.c
3.694 + Compressed data file support was added. This feature requires
3.695 + the zlib data compression libraries and allows compressing and
3.696 + decompressing .gz files "on the fly".
3.697 +
3.698 + * glpcli.h, glpcli.c
3.699 + Command-line interface routines were added. (This feature is
3.700 + incomplete so far.)
3.701 +
3.702 +Sun Mar 02 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
3.703 +
3.704 + * GLPK 4.27 (12:0:12) has been released
3.705 +
3.706 + * glpsql.h, glpsql.c
3.707 + Two MathProg table drivers for iODBC and MySQL contributed by
3.708 + Heinrich Schuchardt <heinrich.schuchardt@gmx.de> were added to
3.709 + the package.
3.710 +
3.711 + * glpmpl05.c
3.712 + Mathprog table driver for xBASE was added to the package.
3.713 +
3.714 + * glpmpl03.c
3.715 + A minor was fixed in the MathProg translator (if some field
3.716 + specified in the table statement is missing in corresponding
3.717 + input table, the bug causes abnormal termination). Thanks to
3.718 + Heinrich Schuchardt <heinrich.schuchardt@gmx.de> for the bug
3.719 + report.
3.720 +
3.721 + * glpmpl.h, glpmpl.c
3.722 + STRING data type was replaced by plain character strings.
3.723 +
3.724 +Sun Feb 17 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
3.725 +
3.726 + * GLPK 4.26 (11:0:11) has been released
3.727 +
3.728 + * glpmpl.h, glpmpl01.c, glpmpl03.c, glpmpl05.c
3.729 + The table statement was implemented. Description of this new
3.730 + feature is given in file doc/tables.txt.
3.731 +
3.732 + * glpios03.c
3.733 + A bug causing zero divide error on computing euclidean norm of
3.734 + the cut coefficient vector was fixed.
3.735 +
3.736 +Wed Dec 19 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
3.737 +
3.738 + * GLPK 4.25 (10:0:10) has been released
3.739 +
3.740 + * glpapi10.c
3.741 + Routines lpx_eval_tab_row and lpx_eval_tab_col were replaced by
3.742 + glp_eval_tab_row and glp_eval_tab_col.
3.743 +
3.744 + * glpios03.c, glpios05.c
3.745 + Gomory's mixed integer cuts were implemented.
3.746 +
3.747 + * glpscs.h, glpscs.c
3.748 + Segmented character string routines are no longer used and were
3.749 + removed from the package.
3.750 +
3.751 +Wed Nov 21 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
3.752 +
3.753 + * GLPK 4.24 (9:0:9) has been released
3.754 +
3.755 + * src/glplpx16.c
3.756 + A bug was fixed in the routine lpx_write_cpxlp. If a variable
3.757 + x has upper bound and no lower bound, it should appear in the
3.758 + bounds section as "-inf <= x <= u", not as "x <= u". Thanks to
3.759 + Enric Rodriguez <erodri@lsi.upc.edu> for the bug report.
3.760 +
3.761 + * src/glpios03.c, src/glpios04.c, src/glpios05.c
3.762 + MIR (mixed integer rounding) cuts were implemented.
3.763 +
3.764 +Sun Oct 28 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
3.765 +
3.766 + * GLPK 4.23 (8:0:8) has been released
3.767 +
3.768 + * src/glplib05.c, configure.ac
3.769 + Check for vsnprintf was added.
3.770 +
3.771 + * include/glppds.h, src/glppds.c
3.772 + A module to scan plain data was added.
3.773 +
3.774 + * src/glpapi09.c
3.775 + The following new API routines were added:
3.776 + glp_read_sol read basic solution from text file;
3.777 + glp_write_sol write basic solution to text file;
3.778 + glp_read_ipt read interior-point solution from text file;
3.779 + glp_write_ipt write interior-point solution to text file;
3.780 + glp_read_mip read MIP solution from text file;
3.781 + glp_write_mip write MIP solution to text file.
3.782 +
3.783 + * src/glpapi12.c
3.784 + Advanced API routine glp_free_env was added.
3.785 +
3.786 + * examples/glpsol.c
3.787 + The following three command-line options were added:
3.788 + --mipgap tol set relative MIP gap tolerance
3.789 + -r filename read solution from filename
3.790 + -w filename write solution to filename
3.791 +
3.792 +Wed Sep 19 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
3.793 +
3.794 + * GLPK 4.22 (7:0:7) has been released
3.795 +
3.796 + * src/glpios02.c
3.797 + A bug was fixed in the MIP preprocessor (ios_preprocess_node).
3.798 + Thanks to Roberto Bagnara <bagnara@cs.unipr.it> (Department of
3.799 + Mathematics, University of Parma, Italy) for the bug report.
3.800 +
3.801 + * src/glpios02.c
3.802 + A bug was fixed in the MIP preprocessor (col_implied_bounds),
3.803 + due to which constraint coefficients with small magnitude could
3.804 + lead to wrong implied bounds of structural variables.
3.805 +
3.806 + * src/glpipp02.c
3.807 + A similar bug was fixed in the routine reduce_bounds.
3.808 +
3.809 + * src/glpapi01.c
3.810 + A bug was fixed in the routines glp_set_mat_row and
3.811 + glp_set_mat_col. (The bug appeared due to incorrect removing
3.812 + zero elements from the row/column lists.)
3.813 +
3.814 + * src/glplpx14.c
3.815 + A bug was fixed in the API routines lpx_read_mps and
3.816 + lpx_read_freemps, due to which bounds of type LI specified in
3.817 + BOUNDS section were incorrectly processed.
3.818 +
3.819 + * src/glplib05.c
3.820 + A call to standard function vsprintf was replaced by a call to
3.821 + vsnprintf for security reasons. Many thanks to Peter T. Breuer
3.822 + <ptb@inv.it.uc3m.es> and Rafael Laboissiere <rafael@debian.org>.
3.823 +
3.824 +Tue Aug 28 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
3.825 +
3.826 + * GLPK 4.21 (6:0:6) has been released
3.827 +
3.828 + * glpscg.h, glpscg.c
3.829 + Routines to maintain sparse cliqued graph were added.
3.830 +
3.831 + * glpios02.c
3.832 + MIP preprocessing routines were added.
3.833 +
3.834 + * glpk.h, glpios.h, glpios03.c
3.835 + New reasons for calling the callback routine were introduced
3.836 + in the MIP solver.
3.837 +
3.838 + * glpapi08.c
3.839 + Default backtracking strategy was changed to best local bound.
3.840 +
3.841 + * glpapi11.c
3.842 + New API routine glp_term_out to enable/disable terminal output
3.843 + was added.
3.844 +
3.845 + * glprng.h, glprng02.c
3.846 + Two routines to generate uniformly distributed pseudo-random
3.847 + floating-point numbers were added.
3.848 +
3.849 +Thu Jul 26 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
3.850 +
3.851 + * GLPK 4.20 (5:0:5) has been released
3.852 +
3.853 + * glpk.h, glpapi08.c
3.854 + The routine lpx_integer was replaced by an equivalent routine
3.855 + glp_intopt. Also new API routine glp_init_iocp was added.
3.856 +
3.857 + * glpiet.h, glpiet.c
3.858 + Routines implementing the implicit enumeration tree are
3.859 + no longer used and therefore were removed from the package.
3.860 +
3.861 + * glpios.h, glpios01.c, glpios02, glpios03
3.862 + Routines implementing the integer optimization suite being
3.863 + replaced by a new version were removed from the package.
3.864 +
3.865 + * glpmip.h, glpmip01.c, glpmip02.c
3.866 +
3.867 + Routines implementing the B&B method being replaced by a new
3.868 + version were removed from the package.
3.869 +
3.870 + * glpios.h, glpios01.c, glpios02.c
3.871 +
3.872 + Routines implementing a new version of the integer optimization
3.873 + suite (IOS) based on the B&B method were added to the package.
3.874 +
3.875 + * glpk.h, glpapi10.c
3.876 + Branch-and-bound interface routines were added to the package.
3.877 +
3.878 + * examples/tspsol.c
3.879 + The TSP solver based on old version of the integer optimization
3.880 + suite is no more supported and was removed from the package.
3.881 +
3.882 + * glpipp02.c
3.883 + An error in the routine reduce_bounds was fixed; thanks to
3.884 + Graham Rockwell <bionomicron@gmail.com> for the bug report.
3.885 +
3.886 + * glpk.latex
3.887 + A new edition of the reference manual was included.
3.888 +
3.889 +Thu Jul 05 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
3.890 +
3.891 + * GLPK 4.19 (4:0:4) has been released
3.892 +
3.893 + The principal change is upgrading to GPLv3.
3.894 +
3.895 + * glpapi01.c
3.896 + A serious bug in the routine glp_del_cols was fixed; thanks to
3.897 + Cedric[FR] <fox2113@wanadoo.fr> for the bug report. The bug
3.898 + appeared because on deleting non-basic columns the basis header
3.899 + remained valid, however, contained invalid (old) column ordinal
3.900 + numbers.
3.901 +
3.902 + * glpapi10.c
3.903 + A new advanced API routine glp_mem_limit was added.
3.904 +
3.905 + * glplpx01.c
3.906 + The case GLP_EBOUND was added to the routine lpx_simplex.
3.907 + Thanks to Cameron Kellough <Cameron.Kellough@sri.com> for the
3.908 + bug report.
3.909 +
3.910 + * glplpx19.c
3.911 + An API routine lpx_write_pb to write the problem instance in
3.912 + OPB (pseudo boolean) format format was added. Thanks to Oscar
3.913 + Gustafsson <oscarg@isy.liu.se> for the contribution.
3.914 +
3.915 + * glpsol.c
3.916 + Two new options --wpb and --wnpb were added to glpsol to write
3.917 + the problem instance in OPB format.
3.918 +
3.919 +Mon Jun 25 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
3.920 +
3.921 + * GLPK 4.18 (3:0:3) has been released
3.922 +
3.923 + * glplib.h
3.924 + Type names ulong_t and uldiv_t were changed to glp_ulong and
3.925 + glp_uldiv to avoid conflicts with standard type names on some
3.926 + platforms. Thanks to Boris Wirtz <Boris.Wirtz@uni-oldenburg.de>
3.927 + for the bug report.
3.928 +
3.929 + * glpbfd.*, glpfhv.*, glplpf.*
3.930 + LP basis factorization routines were made tidy.
3.931 +
3.932 + * glpk.h, glpapi04.c
3.933 + The following API routines were added:
3.934 + glp_set_rii, glp_set_sjj, glp_get_rii, glp_get_sjj.
3.935 +
3.936 + * glpk.h, glpapi06.c
3.937 + The routine lpx_simplex was replaced by an equivalent routine
3.938 + glp_simplex. Also new API routine glp_init_smcp was added.
3.939 +
3.940 + * glpk.h, glpapi09.c
3.941 + The following advanced API routines were added:
3.942 + glp_bf_exists, glp_factorize, glp_bf_updated, glp_get_bfcp,
3.943 + glp_set_bfcp, glp_get_bhead, glp_get_row_bind, glp_get_col_bind,
3.944 + glp_ftran, glp_btran.
3.945 +
3.946 + * glpk.latex
3.947 + A new edition of the reference manual was included.
3.948 +
3.949 + * examples/dea.mod, examples/food.mod, examples/food2.mod
3.950 + Three examples in the MathProg language were added.
3.951 + Thanks to Sebastian Nowozin <nowozin@gmail.com>.
3.952 +
3.953 +Sat May 26 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
3.954 +
3.955 + * GLPK 4.17 (2:0:2) has been released
3.956 +
3.957 + * glpdmp.h, glpdmp.c
3.958 + Memory pool routines were replaced by a new version.
3.959 +
3.960 + * glpscs.h, glpscs.c
3.961 + Segmented string routines were replaced by a new version.
3.962 +
3.963 + * glplpx08.c, glplpx09.c
3.964 + Now the MIP problem may have no integer columns.
3.965 +
3.966 + * glpapi01.c
3.967 + The routines glp_set_mat_row, glp_set_mat_col, and glp_load_mat
3.968 + were modified to allow zero elements (which are not stored in
3.969 + the constraint matrix).
3.970 +
3.971 + * glpscf.h, glpscf.c
3.972 + Schur complement factorization routines were implemented.
3.973 +
3.974 + * glplpf.h, glplpf.c
3.975 + LP basis factorization routines based on LU-factorization and
3.976 + Schur complement were implemented.
3.977 +
3.978 + * glplpx02.c, glplpx03.c
3.979 + New control parameter LPX_K_BFTYPE was introduced to choose the
3.980 + basis factorization type used by the simplex method routines.
3.981 +
3.982 + * glpsol.c
3.983 + Three new command-line options were added to choose the basis
3.984 + factorization type used by the simplex method routines: --luf,
3.985 + --cbg, and --cgr.
3.986 +
3.987 + * glpk.latex
3.988 + A new edition of the reference manual was included.
3.989 +
3.990 +Sat May 05 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
3.991 +
3.992 + * GLPK 4.16 (1:0:1) has been released
3.993 +
3.994 + * glpk.h, glpapi.c, glplpx01.c, glplpx02.c
3.995 + Names of a number basic api routines were changed and now have
3.996 + the prefix 'glp_'. To keep backward compatibility these routines
3.997 + are also available via their old names prefixed with 'lpx_'.
3.998 +
3.999 + * glplpx19.c
3.1000 + Three new api routines were added: glp_version, glp_term_hook,
3.1001 + and glp_mem_usage.
3.1002 +
3.1003 + * glpk.latex, gmpl.texi
3.1004 + A new edition of the reference manuals was included.
3.1005 +
3.1006 + * lpglpk40.c
3.1007 + This example program is no longer supported and therefore was
3.1008 + removed from the package.
3.1009 +
3.1010 +Sun Feb 18 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1011 +
3.1012 + * GLPK 4.15 (0:0:0) has been released
3.1013 +
3.1014 + * configure.ac, Makefile.am
3.1015 + Autotools specification files were changed to use GNU Libtool
3.1016 + that allows building the static as well as shared GLPK library.
3.1017 + Thanks to Rafael Laboissiere <rafael@debian.org>.
3.1018 +
3.1019 +Mon Feb 05 08:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1020 +
3.1021 + * GLPK 4.14 has been released
3.1022 + Now GLPK conforms to ILP32, LLP64, and LP64 programming models
3.1023 + (the latter seems to be the ultimate choice regarding 64-bit
3.1024 + architectures). Note that GLPK itself is a 32-bit application,
3.1025 + and the conformity only means that the package works correctly
3.1026 + on all these arenae. Nevertheless, on 64-bit platforms it is
3.1027 + possible to use more than 4GB of memory, if necessary.
3.1028 +
3.1029 + * Makefile
3.1030 + Starting from this release only the header glpk.h is needed to
3.1031 + be installed.
3.1032 +
3.1033 + * glplib01.c
3.1034 + Two routines bigmul and bigdiv which performs multiplication
3.1035 + and division of unsigned integers of arbitrary precision were
3.1036 + added.
3.1037 +
3.1038 + * glplib02.c
3.1039 + A set of 64-bit arithmetic routines were added.
3.1040 +
3.1041 + * glplib04.c
3.1042 + Some low-level library routines were improved and renamed.
3.1043 +
3.1044 + * glpcfg.h
3.1045 + The macro GLP_TM_SPEC were introduced to specify a version of
3.1046 + the time routine depending on the host environment.
3.1047 +
3.1048 +Mon Nov 13 12:00:00 2006 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1049 +
3.1050 + * GLPK 4.13 has been released
3.1051 +
3.1052 + * configure.in
3.1053 + '-lm' bug was fixed.
3.1054 +
3.1055 + * glpbfx.h, glpbfx.c
3.1056 + Basis factorization interface routines based on exact (bignum)
3.1057 + arithmetic were implemented.
3.1058 +
3.1059 + * glpssx.h, glpssx1.c, glpssx2.c
3.1060 + Simplex method routines based on exact (bignum) arithmetic were
3.1061 + implemented.
3.1062 +
3.1063 + * glplpx6e.c
3.1064 + The routine lpx_exact, which is an easy-to-use driver to the
3.1065 + exact simplex method, was added.
3.1066 +
3.1067 + * glpsol.c
3.1068 + Two command-line options were added: '--exact' and '--xcheck'.
3.1069 +
3.1070 +Wed Nov 08 12:00:00 2006 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1071 +
3.1072 + * GLPK 4.12 has been released
3.1073 +
3.1074 + * glpcfg.h
3.1075 + The package configuration file was added.
3.1076 +
3.1077 + * glplib2.c
3.1078 + Alternative version of the routines umalloc, ucalloc, and ufree
3.1079 + was provided. It does not limit the amount of allocated memory
3.1080 + to INT_MAX bytes and therefore can be used on platforms where
3.1081 + sizeof(void *) > sizeof(int). To enable this version one should
3.1082 + define the preprocessor variable GLP_HUGE_MEM.
3.1083 +
3.1084 + * glprng.c
3.1085 + The routine rng_create_rand was changed to initialize the
3.1086 + generator using seed = 1, not 0, to conform ISO C requirements.
3.1087 +
3.1088 + * glpgmp.h, glpgmp.c
3.1089 + A set of bignum arithmetic routines implementing operations on
3.1090 + integers and rationals was added. These routines are compatible
3.1091 + with the GNU MP library.
3.1092 +
3.1093 + NOTE: To attain a much better performance it is recommended to
3.1094 + use, if possible, the original GNU MP library rather than the
3.1095 + GLPK version, by defining the preprocessor variable GLP_USE_GMP.
3.1096 +
3.1097 + * glplux.h, glplux.c
3.1098 + A tentative implementation of sparse LU-factorization based on
3.1099 + exact (bignum) arithmetic was added.
3.1100 +
3.1101 + * glpssx.h, glpssx.c
3.1102 + A tentative implementation of some simplex method routines based
3.1103 + on exact (bignum) arithmetic was added.
3.1104 +
3.1105 + * glplpx6f.c
3.1106 + A preliminary implementation of the routine lpx_exact_check was
3.1107 + added. This routine checks the current basis for primal and dual
3.1108 + feasibility using exact (bignum) arithmetic.
3.1109 +
3.1110 + * examples/glpsol.c
3.1111 + The command-line option '--xcheck' was introduced to check the
3.1112 + current basis for feasibility using exact (bignum) arithmetic.
3.1113 +
3.1114 +Tue Jul 25 12:00:00 2006 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1115 +
3.1116 + * GLPK 4.11 has been released.
3.1117 +
3.1118 + * include/glpbfi.h, src/glpbfi.c
3.1119 + Basis factorization interface routines were added.
3.1120 +
3.1121 + * include/glpluf.h, src/glpluf1.c
3.1122 + Hypersparse solution routines were added.
3.1123 +
3.1124 + * include/glpinv.h, src/glpinv1.c
3.1125 + Hypersparse solution routines (fake version) were added.
3.1126 +
3.1127 + * include/glpmpl.h, src/glpmpl.c
3.1128 + Built-in functions card, length, and substr were implemented.
3.1129 + Output redirection in the printf statement was implemented.
3.1130 +
3.1131 + * examples/graph.mod, examples/crypto.mod
3.1132 + Two example models illustrating new features of the modeling
3.1133 + language were included.
3.1134 +
3.1135 +Thu May 11 12:00:00 2006 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1136 +
3.1137 + * GLPK 4.10 has been released.
3.1138 +
3.1139 + * src/glplpx8a.c
3.1140 + A fragment was added to the routines lpx_read_mps and
3.1141 + lpx_read_freemps to accept LI bound type (it is similar to LO,
3.1142 + however, additionally marks the column as integer).
3.1143 +
3.1144 + * include/glpbfi.h, src/glpbfi.c
3.1145 + The module glpbfi which implements the basis factorization
3.1146 + interface (BFI) was added.
3.1147 +
3.1148 + * src/glplpx7a.c
3.1149 + The routine lpx_cover_cut to generate mixed cover cuts was
3.1150 + added.
3.1151 +
3.1152 + * src/glplpx7b.c
3.1153 + The routine lpx_clique_cut to generate clique cuts and related
3.1154 + routines to maintain the conflict graph were added.
3.1155 +
3.1156 + * include/glplpx.h, src/glplpx5.c
3.1157 + The routine lpx_cpx_basis implementing Bixby's algorithm to
3.1158 + construct an initial LP basis was added.
3.1159 +
3.1160 + * examples/glpsol.c
3.1161 + Command-line option '--bib' was added which allows building
3.1162 + an initial LP basis using Bixby's algorithm.
3.1163 + Default command-line option '--mps' was changed to '--freemps'.
3.1164 +
3.1165 + * examples/cf12a.mod, examples/cf12b.mod
3.1166 + Two examples in MathProg (curve fitting problem) were added.
3.1167 + Thanks to Dr. Harley Mackenzie <hjm@hardsoftware.com>.
3.1168 +
3.1169 +Tue Jan 17 12:00:00 2006 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1170 +
3.1171 + * GLPK 4.9 has been released.
3.1172 +
3.1173 + * glpipp.h, glpipp1.c, glpipp2.c
3.1174 + A MIP presolver were implemented (currently incomplete). It is
3.1175 + used internally in the routine lpx_intopt (see below).
3.1176 +
3.1177 + * glplpx6d.c, glplpx7a.c
3.1178 + An advanced branch-and-bound solver (the routine lpx_intopt)
3.1179 + were implemented.
3.1180 +
3.1181 + * glplpx6c.c
3.1182 + The routine lpx_check_int to check MIP feasibility conditions
3.1183 + was added.
3.1184 +
3.1185 + * glplpx8a.c
3.1186 + The routine lpx_print_mip was changed to print MIP feasibility
3.1187 + conditions.
3.1188 +
3.1189 + * glpmpl.h, glpmpl1.c, glpmpl3.c
3.1190 + The built-in functions sin, cos, atan, and atan2 were added to
3.1191 + the MathProg language.
3.1192 +
3.1193 + * doc/lang.*
3.1194 + Some typos were fixed.
3.1195 + Thanks to Minh Ha Duong <haduong@centre-cired.fr> (CIRED, CNRS).
3.1196 +
3.1197 +Wed Jan 12 12:00:00 2005 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1198 +
3.1199 + * GLPK 4.8 has been released.
3.1200 +
3.1201 + * glpspx.h, glpspx1.c, glpspx2.c, glplpx6a.c
3.1202 + Simplex method routines were changed due to a new format of the
3.1203 + constraint matrix.
3.1204 +
3.1205 + * glpmat.h, glpmat.c
3.1206 + Sparse matrix routines were re-implemented using storage-by-rows
3.1207 + format.
3.1208 +
3.1209 + * glpipm.h, glpipm.c, glplpx6b.c
3.1210 + Interior-point method routines were changed due to a new format
3.1211 + of sparse matrices.
3.1212 +
3.1213 + * glpchol.h, glpchol.c
3.1214 + Old version of Cholesky factorization routines being replaced by
3.1215 + a new one (see glpmat.c) was removed from the package.
3.1216 +
3.1217 + * glplpx8c.c
3.1218 + Minor bug was fixed in api routine lpx_read_cpxlp.
3.1219 +
3.1220 +Mon Aug 23 12:00:00 2004 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1221 +
3.1222 + * GLPK 4.7 has been released.
3.1223 +
3.1224 + * glplpx.h, glplpx1.c
3.1225 + New core API routines were added (but not documented yet):
3.1226 + lpx_order_matrix, lpx_create_index, lpx_find_row, lpx_find_col,
3.1227 + lpx_delete_index.
3.1228 +
3.1229 + * glplpx8a.c
3.1230 + API routine lpx_read_mps was re-implemented, and two new API
3.1231 + routines lpx_read_freemps and lpx_write_freemps were added to
3.1232 + support free MPS format.
3.1233 +
3.1234 + * glplpx8c.c
3.1235 + Two API routines lpx_read_cpxlp and lpx_write_cpxlp (formerly
3.1236 + named lpx_read_lpt and lpx_write_lpt) were re-implemented.
3.1237 +
3.1238 + * glpmps.h, glpmps.c
3.1239 + This module formerly used in lpx_read_mps was removed from the
3.1240 + package.
3.1241 +
3.1242 + * glplpt.h, glplpt.c
3.1243 + This module formerly used in lpx_read_lpt was removed from the
3.1244 + package.
3.1245 +
3.1246 + * glpmip.h, glpmip1.h, glpmip2.h
3.1247 + New MIP routines mip_best_node and mip_relative_gap were added
3.1248 + due to suggestion of Brady Hunsaker <hunsaker@engr.pitt.edu>.
3.1249 +
3.1250 + * glpsol.c
3.1251 + The following new command-options were added:
3.1252 + --freemps to read problem data in free MPS format
3.1253 + --wfreemps to write problem data in free MPS format
3.1254 + --cpxlp to read problem data in CPLEX LP format
3.1255 + --wcpxlp to write problem data in CPLEX LP format
3.1256 + --bas to read LP basis from a text file in MPS format
3.1257 + --wbas to write LP basis to a text file in MPS format
3.1258 + --mostf to use "most fractional" branching heuristic
3.1259 + --bestb to use "best bound" backtracking heuristic
3.1260 +
3.1261 + * contrib/deli/*.*
3.1262 + GLPK Delphi interface module was temporarily removed from the
3.1263 + distribution due to licensing problems.
3.1264 +
3.1265 + * contrib/glpkmex/*.*
3.1266 + GLPK Matlab interface module was temporarily removed from the
3.1267 + distribution due to licensing problems.
3.1268 +
3.1269 + * contrib/jni/*.*
3.1270 + GLPK Java interface module was temporarily removed from the
3.1271 + distribution due to licensing problems.
3.1272 +
3.1273 +Wed Aug 04 12:00:00 2004 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1274 +
3.1275 + * GLPK 4.6 has been released.
3.1276 +
3.1277 + * glpmpl.h, glpmpl1.c, glpmpl2.c, glpmpl3.c, glpmpl4.c
3.1278 + Three new statements were implemented in the GNU MathProg
3.1279 + language: solve, printf, and for. Also some bugs were fixed.
3.1280 +
3.1281 + * glplpx.h, glplpx8e.c
3.1282 + Two API routines were added: lpx_read_prob and lpx_write_prob,
3.1283 + which allow reading and writing problem data in GNU LP format.
3.1284 +
3.1285 + * glpsol.c
3.1286 + Three new command-line options were added: --glp (to read
3.1287 + problem data in GNU LP format), --wglp (to write problem data
3.1288 + in GNU LP format), and --name (to change problem name).
3.1289 +
3.1290 + * glprng.h, glprng.c
3.1291 + A portable pseudo-random number generator was implemented as a
3.1292 + separate module.
3.1293 +
3.1294 + * glplib4.c
3.1295 + The old implementation of a pseudo-random number generator was
3.1296 + removed from the package.
3.1297 +
3.1298 + * doc/lang.*, doc/refman.*
3.1299 + New edition of the GLPK documentation was included.
3.1300 +
3.1301 + * contrib/glpkmex/*.*
3.1302 + A new version of GLPKMEX was included in the distribution. For
3.1303 + more details see contrib/glpkmex/ChangeLog.
3.1304 +
3.1305 +Mon Jul 19 12:00:00 2004 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1306 +
3.1307 + * GLPK 4.5 has been released.
3.1308 +
3.1309 + * glpmip.h, glpmip1.c, glpmip2.c, glplpx6c.c
3.1310 + New implementation of the branch-and-bound method was added.
3.1311 + It replaces the old implementation, which was removed from the
3.1312 + package.
3.1313 +
3.1314 + * glpies.h, glpies1.c, glpies2.c, glpies3.c
3.1315 + Modules used in the old implementation of the branch-and-bound
3.1316 + method were removed from the package.
3.1317 +
3.1318 + * glplib2.c
3.1319 + Now if the preprocessor variable GLPHUGEMEM is defined, other
3.1320 + version of the routines umalloc, ucalloc, and ufree is used on
3.1321 + compiling the package. This allows avoiding memory allocation
3.1322 + problems on platforms where sizeof(void *) > sizeof(int), for
3.1323 + example, where addresses are 64-bit while integers are 32-bit.
3.1324 + The modification was made due to a bug report provided by Karel
3.1325 + Zimmermann <kzimm@diamant.jouy.inra.fr> and Christophe Caron
3.1326 + <caron@diamant.jouy.inra.fr>.
3.1327 +
3.1328 +Sat Jan 17 12:00:00 2004 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1329 +
3.1330 + * GLPK 4.4 has been released.
3.1331 +
3.1332 + * glplpx.h, glplpx*.c
3.1333 + All API routines were re-implemented using new data structures.
3.1334 + Some new API routines were added and some existing API routines
3.1335 + became obsolete as shown below:
3.1336 +
3.1337 + Obsolete API routine Equivalent new API routine
3.1338 + lpx_check_name (no more supported)
3.1339 + lpx_set_obj_c0 lpx_set_obj_coef
3.1340 + lpx_set_row_coef (no more supported)
3.1341 + lpx_set_col_coef lpx_set_obj_coef
3.1342 + lpx_load_mat (no more supported)
3.1343 + lpx_load_mat3 lpx_load_matrix
3.1344 + lpx_unmark_all (no more supported)
3.1345 + lpx_mark_row (no more supported)
3.1346 + lpx_mark_col (no more supported)
3.1347 + lpx_clear_mat (no more supported)
3.1348 + lpx_del_items lpx_del_rows, lpx_del_cols
3.1349 + lpx_get_row_bnds lpx_get_row_type, lpx_get_row_lb,
3.1350 + lpx_get_row_ub
3.1351 + lpx_get_col_bnds lpx_get_col_type, lpx_get_col_lb,
3.1352 + lpx_get_col_ub
3.1353 + lpx_get_obj_c0 lpx_get_obj_coef
3.1354 + lpx_get_row_coef (no more supported)
3.1355 + lpx_get_col_coef lpx_get_obj_coef
3.1356 + lpx_get_row_mark (no more supported)
3.1357 + lpx_get_col_mark (no more supported)
3.1358 + lpx_get_row_info lpx_get_row_stat, lpx_get_row_prim,
3.1359 + lpx_get_row_dual
3.1360 + lpx_get_col_info lpx_get_col_stat, lpx_get_col_prim,
3.1361 + lpx_get_col_dual
3.1362 + lpx_get_ips_stat lpx_ipt_status
3.1363 + lpx_get_ips_row lpx_ipt_row_prim, lpx_ipt_row_dual
3.1364 + lpx_get_ips_col lpx_ipt_col_prim, lpx_ipt_col_dual
3.1365 + lpx_get_ips_obj lpx_ipt_obj_val
3.1366 + lpx_get_mip_stat lpx_mip_status
3.1367 + lpx_get_mip_row lpx_mip_row_val
3.1368 + lpx_get_mip_col lpx_mip_col_val
3.1369 + lpx_get_mip_obj lpx_mip_obj_val
3.1370 +
3.1371 + Obsolete API routines were kept for backward compatibility,
3.1372 + however, they will be removed in the future.
3.1373 +
3.1374 + * doc/refman.*
3.1375 + New edition of the GLPK reference manual containing description
3.1376 + of all new API routines was included.
3.1377 +
3.1378 + * contrib/glpkmex/*.*
3.1379 + GLPKMEX, a Matlab MEX interface to GLPK package, contributed by
3.1380 + Nicolo Giorgetti <giorgetti@dii.unisi.it> was included.
3.1381 +
3.1382 + * doc/GLPK_FAQ.txt
3.1383 + GLPK FAQ contributed by Harley Mackenzie <hjm@bigpond.com> was
3.1384 + included.
3.1385 +
3.1386 +Fri Dec 12 12:00:00 2003 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1387 +
3.1388 + * GLPK 4.3 has been released.
3.1389 +
3.1390 + * configure.in
3.1391 + The bug, due to which the standard math library is not linked on
3.1392 + some platforms, was fixed.
3.1393 +
3.1394 + * glpmpl3.c
3.1395 + The bug (0 ** y) was fixed in the routine fp_power.
3.1396 +
3.1397 + * glpmpl.h, glpmpl1.c, glpmpl3.c
3.1398 + Some new built-in functions (round, trunc, Irand224, Uniform01,
3.1399 + Uniform, Normal01, Normal) were added to the MathProg language.
3.1400 +
3.1401 + * glpmpl1.c
3.1402 + The MathProg syntax was changed to allow writing 'subj to'.
3.1403 +
3.1404 + * glplpx.h, glplpx1.c, glplpx2.c
3.1405 + The new api routine lpx_get_ray_info was added.
3.1406 +
3.1407 + * glplpx8a.c
3.1408 + The api routine lpx_print_sol was changed to print the number of
3.1409 + non-basic variable, which causes primal unboundness.
3.1410 +
3.1411 + * glpmps.c
3.1412 + The code was changed to avoid errors on compiling the package on
3.1413 + Mac OS X. Thanks to Andre Girard <andre@inrs-emt.uquebec.ca> for
3.1414 + the bug report.
3.1415 +
3.1416 + * doc/lang.*, doc/refman.*
3.1417 + Several typos were fixed and some new material was added in the
3.1418 + glpk documentation.
3.1419 +
3.1420 +Fri Nov 14 12:00:00 2003 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1421 +
3.1422 + * GLPK 4.2 has been released.
3.1423 +
3.1424 + * glpiet.h, glpiet.c, glpios.h, glpios1.c, glpios2.c, glpios3.c
3.1425 + A preliminary implementation of the Integer Optimization Suite
3.1426 + (IOS) was included in the package. Eventually IOS will replace
3.1427 + the Implicit Enumeration Suite (IES).
3.1428 +
3.1429 + * glplpx.h, glplpx6d.c
3.1430 + A dummy version of the integer optimization routine lpx_intopt
3.1431 + was included in the package. Later this routine will replace the
3.1432 + routine lpx_integer.
3.1433 +
3.1434 + * examples/glpsol.c
3.1435 + A new command-line option --int-opt was added to the solver to
3.1436 + call lpx_intopt rather than lpx_integer.
3.1437 +
3.1438 + * glpbcs.h, glpbcs1.c, glpbcs2.c
3.1439 + Being replaced by IOS routines (see above) the Branch-and-Cut
3.1440 + Framework (BCS) routines were removed from the package.
3.1441 +
3.1442 + * examples/tspsol.c
3.1443 + Stand-alone Symmetric TSP solver was completely re-programmed
3.1444 + using IOS routines.
3.1445 +
3.1446 + * glplib.h, glplib2.c, glplib4.c
3.1447 + The random-number generator was implemented. It is based on the
3.1448 + module GB_FLIB from the Stanford GraphBase originally developed
3.1449 + by Donald Knuth.
3.1450 +
3.1451 + * glphbsm.c, glplpx8a.c, glpmps.c
3.1452 + All calls to fopen/fclose were replaced by corresponding calls
3.1453 + to ufopen/ufclose due to bug reports provided by Morten Welinder
3.1454 + <terra@gnu.org> and <jpark@sfwmd.gov>.
3.1455 +
3.1456 + * glpmps.c
3.1457 + The code was made re-entrant.
3.1458 +
3.1459 + * glplpx8b.c
3.1460 + API routine lpx_print_sens_bnds for bounds sensitivity analysis
3.1461 + contributed by Brady Hunsaker <hunsaker@engr.pitt.edu> was added
3.1462 + to the package. This feature is also available in glpsol via the
3.1463 + command-line option --bounds.
3.1464 +
3.1465 + * contrib/jni/*.*
3.1466 + New version of GLPK JNI (Java Native Interface) contributed by
3.1467 + Chris Rosebrugh <cpr@pobox.com> was added to the package.
3.1468 +
3.1469 + * contrib/deli/*.*
3.1470 + GLPK DELI (Delphi Interface) contributed by Ivo van Baren
3.1471 + <i.van.baren@freeler.nl> was added to the package.
3.1472 +
3.1473 + * glplpx3.c
3.1474 + Default method to scale the problem was changed to equilibration
3.1475 + scaling (lp->scale = 1 in lpx_reset_parms).
3.1476 +
3.1477 + * glplpx6a.c
3.1478 + Two minor (non-critical) typos were fixed due to report provided
3.1479 + by Andrew Hamilton-Wright <andrewhw@ieee.org>.
3.1480 +
3.1481 + * glplpp2.c
3.1482 + An untested case (line 941) had been tested due to bug report
3.1483 + provided by Jiri Spitz <jiri.spitz@telecom.cz>.
3.1484 +
3.1485 + * w32bc5.mak, w32vc6.mak, w32vc6d.mak, d32dmc.mak
3.1486 + Several makefiles were added to allow building GLPK library for
3.1487 + some non-GNU 32-bit platforms.
3.1488 +
3.1489 +Sat Aug 23 12:00:00 2003 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1490 +
3.1491 + * GLPK 4.1 has been released.
3.1492 +
3.1493 + * glpmpl1.c, glpmpl3.c
3.1494 + Some bugs were fixed in the MathProg translator due to the bug
3.1495 + reports provided by Giles Thompson <gwpt1@cus.cam.ac.uk>:
3.1496 + conditional set expressions were incorrectly parsed;
3.1497 + dimen attribute was not set by default when a set was used
3.1498 + recursively in its own declaration;
3.1499 + logical expressions ... in if ... then ... else ... did not
3.1500 + work;
3.1501 + displaying set expressions did not free memory allocated for
3.1502 + temporary results.
3.1503 +
3.1504 + * glpmpl3.c (reduce_terms)
3.1505 + Implementation of summation of linear forms over domain was
3.1506 + improved to reduce complexity of that operation from O(n*n) to
3.1507 + O(n*log n). The improvement was made due to a report provided
3.1508 + by Sebastien de Menten <sdementen@hotmail.com>.
3.1509 +
3.1510 + * glplpx6a.c (line 1056), glpmip1.c (line 641)
3.1511 + Two minor bugs were fixed due to the bug report provided by
3.1512 + Kendall Demaree <kendal.demaree@verizon.net>.
3.1513 +
3.1514 + * glplpx.h, glplpx6a.c
3.1515 + The method of one artificial variable implemented in the routine
3.1516 + lpx_prim_art and used on the phase I in the glpk simplex solver
3.1517 + has a serious defect: for some lp instances it erroneously
3.1518 + reports that the problem has no primal feasible solution. This
3.1519 + error appears when the column of the artificial variable, which
3.1520 + enters the basis to make it primal feasible, has large
3.1521 + constraint coefficients, that leads to small reduced costs of
3.1522 + non-basic variables and premature termination of the search,
3.1523 + i.e. to wrong conclusion that the problem has no primal feasible
3.1524 + solution. To avoid this defect the routine lpx_prim_feas was
3.1525 + included. It implements the method of implicit artifical
3.1526 + variables (based on minimization of the sum of infeasibilities),
3.1527 + which is a bit slower but much more robust. The routine
3.1528 + lpx_prim_feas having the same functionality now is used instead
3.1529 + the routine lpx_prim_art.
3.1530 +
3.1531 + * glpinv.h, glpinv.c
3.1532 + The test used in the routine inv_update to detect low accuracy
3.1533 + after updating LU-factorization of the basis matrix was replaced
3.1534 + by a new, more robust test.
3.1535 +
3.1536 + * glplpx6c.c
3.1537 + Selecting an active node to be solved next in the routine
3.1538 + btrack_bestp was changed. Now, if any integer feasible solution
3.1539 + has not been found yet, the routine chooses an active node which
3.1540 + has the minimal sum of integer infeasibilities.
3.1541 +
3.1542 + * glpmip.h, glpmip1.c
3.1543 + The additional flag int_obj was included in the structure
3.1544 + MIPTREE used by the branch-and-bound. This flag is set in the
3.1545 + routine mip_create_tree and used in the routine is_better. It
3.1546 + means that the objective is integral, i.e. depends only on
3.1547 + integer variables with integer objective coefficients. The test
3.1548 + used in the routine check_integrality was also replaced by a
3.1549 + new, more reasonable one.
3.1550 +
3.1551 + * glplpx1.c
3.1552 + A minor bug was fixed in the routine lpx_check_name.
3.1553 +
3.1554 + * glpmpl.h, glpmpl4.c, glplpx8d.c
3.1555 + The flag skip_data was added to the parameter list of the
3.1556 + routine mpl_read_model. If this flag is set, the data section
3.1557 + in the model file is ignored. Corresponding change was made in
3.1558 + the routine lpx_read_model. Now, if both model and data files
3.1559 + are specified, the data section in the model file is ignored.
3.1560 +
3.1561 + * glplpx8c.c
3.1562 + A minor bug (wrong format used for writing free columns) in the
3.1563 + routine lpx_write_lpt was fixed due to the bug report provided
3.1564 + by Bernhard Schmidt <schmidt@math.uni-augsburg.de>
3.1565 +
3.1566 + * sample/glpsol.c
3.1567 + The command-line parameter --tmlim, which allows limiting the
3.1568 + solution time, was added.
3.1569 +
3.1570 + * doc/lang.*, doc/refman.*
3.1571 + New edition of the GLPK documentation was included.
3.1572 +
3.1573 + * java-binding/*.*
3.1574 + New version of the GLPK JNI (Java Native Interface) package was
3.1575 + included in the distribution.
3.1576 +
3.1577 + * sample/lpglpk40.c
3.1578 + A non-trivial example was added. It allows using GLPK as a base
3.1579 + LP solver for Concorde, a program for solving Traveling Salesman
3.1580 + Problem (TSP). For details see comments in lpglpk40.c.
3.1581 +
3.1582 + * sample/*.mod
3.1583 + Some examples of LP and MIP models written in GNU MathProg were
3.1584 + added.
3.1585 +
3.1586 +Tue May 06 12:00:00 2003 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1587 +
3.1588 + * GLPK 4.0 has been released.
3.1589 +
3.1590 + * glpmpl.h, glpmpl1.c, glpmpl2.c, glpmpl3.c, glpmpl4.c
3.1591 + The model translator for the GNU MathProg modeling language was
3.1592 + implemented and included in the package.
3.1593 +
3.1594 + * glplpx.h, glplpx8d.c
3.1595 + The api routine lpx_read_model, which is an interface to the
3.1596 + MathProg translator, was included in the package.
3.1597 +
3.1598 + * glplpx.h, glplpx8a.c
3.1599 + The api routine lpx_print_prob for writing LP/MIP problem data
3.1600 + in plain text format was included in the package.
3.1601 +
3.1602 + * sample/glpsol.c
3.1603 + New version of the GLPK stand-alone LP/MIP solver that supports
3.1604 + the GNU MathProg modeling language was implemented.
3.1605 +
3.1606 + * doc/lang.latex, doc/lang.dvi, doc/lang.ps
3.1607 + The document "GLPK: Modeling Language GNU MathProg" was included
3.1608 + in the package.
3.1609 +
3.1610 + * doc/refman.latex, doc/refman.dvi, doc/refman.ps
3.1611 + New edition of the GLPK Reference Manual was included in the
3.1612 + package.
3.1613 +
3.1614 + * glplpx8c.c
3.1615 + A bug in the api routine lpx_write_lpt was fixed. Due to that
3.1616 + bug an addressing error occured in the routine if the objective
3.1617 + function has the non-zero constant term.
3.1618 +
3.1619 + * glplan.h, glplan1.c, glplan2.c, glplan3.c, glplan4.c,
3.1620 + * glplan5.c, glplan6.c, glplan7.c, glplan8.c, glplpx8b.c
3.1621 + All modules of the translator for the GLPK/L modeling language
3.1622 + were removed from the package, because GLPK/L being completely
3.1623 + superseded by GNU MathProg is no more supported.
3.1624 +
3.1625 +Tue Mar 25 12:00:00 2003 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1626 +
3.1627 + * GLPK 3.3 has been released.
3.1628 +
3.1629 + * glplpp.h, glplpp1.c, glplpp2.c
3.1630 + An implementation of the built-in LP presolver was added to the
3.1631 + package.
3.1632 +
3.1633 + * glplpx.h
3.1634 + The flag presol was added to the structure LPX. This flag tells
3.1635 + the lpx_simplex whether the built-in LP presolver should be used
3.1636 + or not. By default this flag is off. Also three macros (namely
3.1637 + LPX_E_NOPFS, LPX_E_NODFS, and LPX_K_PRESOL) that concern using
3.1638 + the LP presolver were introduced.
3.1639 +
3.1640 + * glplpx3.c, glplpx6a.c
3.1641 + These modules was changed to use the built-in LP presolver.
3.1642 +
3.1643 + * sample/glpsol.c
3.1644 + Command line options --presol and --nopresol that concern using
3.1645 + the LP presolver were added to the stand-alone LP/MIP solver.
3.1646 +
3.1647 + * glplan1.c
3.1648 + This module was changed to allow declaring sets like A[1:10] in
3.1649 + the models written in the GLPK/L modeling language.
3.1650 +
3.1651 + * doc/refman.latex, doc/lang.latex
3.1652 + New editions of the documents "GLPK User's Guide" and "GLPK/L
3.1653 + Modeling Language" were included in the distribution.
3.1654 +
3.1655 + * java-binding/*.*
3.1656 + The package GLPK JNI (Java Native Interface) implementing Java
3.1657 + binding for GLPK was included in the distribution. This package
3.1658 + was developed and programmed by Yuri Victorovich <yuri@gjt.org>.
3.1659 +
3.1660 +Tue Feb 18 12:00:00 2003 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1661 +
3.1662 + * GLPK 3.2.4 has been released.
3.1663 +
3.1664 + * glplpx6b.c
3.1665 + The code was changed to allow auxiliary variables have non-zero
3.1666 + objective coefficients.
3.1667 +
3.1668 + Also a minor bug was fixed (the constant term was not considered
3.1669 + on displaying the objective function value).
3.1670 +
3.1671 + * sample/glpsol.c
3.1672 + The code was changed to fix a bug (the command-line option 'bfs'
3.1673 + was not recognized). The bug was fixed due to report provided by
3.1674 + Olivier <odwl@skynet.be>.
3.1675 +
3.1676 + * glplpt.c
3.1677 + The code was changed to fix a bug (binary variables were treated
3.1678 + erroneously as integer ones).
3.1679 +
3.1680 + * glplpx6b.c
3.1681 + The code was changed to fix a bug (variables that have no lower
3.1682 + bounds were incorrectly processed on converting to the standard
3.1683 + formulation). The bug was fixed due to report kindly provided by
3.1684 + Kjell Eikland <kjell.eikland@broadpark.no>.
3.1685 +
3.1686 +Mon Nov 11 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1687 +
3.1688 + * GLPK 3.2.3 has been released.
3.1689 +
3.1690 + * glpmip.h, glpmip1.c
3.1691 + A preliminary implementation of the branch-and-bound driver
3.1692 + based on the implicit enumeration suite (glpies) was added to
3.1693 + the package. This module is not documented yet.
3.1694 +
3.1695 + * glplpx6c.c
3.1696 + A new implementation of the api routine lpx_integer which now
3.1697 + is based on the b&b driver (see glpmip above) was included in
3.1698 + the package. This new implementation has exactly the same
3.1699 + functionality as the old version and therefore all changes are
3.1700 + transparent to the api user.
3.1701 +
3.1702 + * glpbbm.h, glpbbm.c
3.1703 + * glprsm.h, glprsm1.c, glprsm2.c
3.1704 + * glplp.h, glplp.c
3.1705 + These modules were removed from the package, because they were
3.1706 + used only in the old version of the routine lpx_integer, which
3.1707 + was replaced by the new version (see glplpx6c above).
3.1708 +
3.1709 + * glplpx.h, glplpx6a.c
3.1710 + The api routine lpx_check_kkt was included in the package and
3.1711 + its description was added in the reference manual. This routine
3.1712 + allows checking Karush-Kuhn-Tucker optimality conditions for an
3.1713 + LP solution.
3.1714 +
3.1715 + * glplpx.h, glplpx8a.c
3.1716 + Now the api routine lpx_print_sol also prints information about
3.1717 + "solution quality" obtained via the api routine lpx_check_kkt.
3.1718 +
3.1719 + * glplpx.h, glplpx8a.c
3.1720 + New api routines lpx_read_bas and lpx_write_bas were included
3.1721 + in the package and documented. The routine lpx_write_bas allows
3.1722 + writing a current basis from an LP object to a text file in the
3.1723 + MPS format. The routine lpx_read_bas allows reading a basis
3.1724 + prepared in the MPS format from a text file into an LP object.
3.1725 +
3.1726 + * glplpt.c
3.1727 + The parsing routine which reads LP problem data prepared in the
3.1728 + CPLEX LP format was modified to allow specifying lower bounds
3.1729 + of variables also in the form 'variable >= lower bound' (in the
3.1730 + bounds section). This modification was made due to a notice
3.1731 + provided by Ivan Luzzi <iluzzi@libero.it>.
3.1732 +
3.1733 + * glplpx.h, glplpx8c.c
3.1734 + The api routine lpx_write_lpt which allows writing LP problem
3.1735 + data from an LP object to a text file using the CPLEX LP format
3.1736 + was included in the package and documented.
3.1737 +
3.1738 + * glplpx.h, glplpx3.c
3.1739 + The control parameter LPX_K_LPTORIG that affects the behavior
3.1740 + of the api routine lpx_write_lpt was introduced.
3.1741 +
3.1742 + * glplan6.c
3.1743 + The semantics of the language GLPK/L was changed to allow
3.1744 + selection in case when not all mute letters of a predicate (the
3.1745 + operand that follows the keyword 'where') are presented in a
3.1746 + parameter (the operand that precedes the keyword 'where'), i.e.
3.1747 + to allow writing something like this:
3.1748 + y[j] := sum(i, x[i] where p[i,j]);
3.1749 + The paragraph "Selection" in the langauge description (page 25)
3.1750 + was also correspondingly changed. This change of the language
3.1751 + semantics was undertaken due to a notice provided by Peter Lee
3.1752 + <plee@kinggee.com.au>.
3.1753 +
3.1754 + * sample/hwd.lpm
3.1755 + A nice example of LP model written in GLPK/L and contributed by
3.1756 + Peter Lee <plee@kinggee.com.au> was included in the package.
3.1757 +
3.1758 + * glplpx6b.c
3.1759 + The api routine lpx_interior was modified: a) to compute dual
3.1760 + values for all structural as well as auxiliary variables; b) to
3.1761 + allow specifying non-zero objective coefficients at auxiliary
3.1762 + variables.
3.1763 +
3.1764 + * sample/glpsol.c
3.1765 + Three new command-line options were added to the solver, which
3.1766 + are: --plain, --orig, and --wrlpt.
3.1767 +
3.1768 +Mon Oct 14 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1769 +
3.1770 + * GLPK 3.2.2 has been released.
3.1771 +
3.1772 + * glplpt.h, glplpt.c
3.1773 + A module that reads LP/MIP problem data in CPLEX LP format was
3.1774 + implemented.
3.1775 +
3.1776 + * glplpx8c.c
3.1777 + An api routine lpx_read_lpt that reads LP/MIP problem data in
3.1778 + CPLEX LP format was implemented.
3.1779 +
3.1780 + * sample/glpsol.c, sample/plan.lpt
3.1781 + A new command-line option '--lpt' that allows reading LP/MIP
3.1782 + problem data in CPLEX LP format was added to the solver.
3.1783 +
3.1784 + * doc/refman.latex, doc/refman.dvi, doc/refman.ps
3.1785 + A new edition of the Reference Manual was included.
3.1786 +
3.1787 + * source/*.c
3.1788 + Casting to (unsigned char) was added in some calls to the
3.1789 + classification functions (isalpha, etc.). The bug was fixed due
3.1790 + to report provided by Morten Welinder <terra@diku.dk>.
3.1791 +
3.1792 + * glplpx8a.c
3.1793 + The local routine mps_numb used in the routine lpx_write_mps
3.1794 + was modified to correctly format floating-point numbers that
3.1795 + have two digits in the decimal exponent. The bug was fixed due
3.1796 + to report provided by Vlahos Kiriakos <Kiriakos.Vlahos@gs.com>.
3.1797 +
3.1798 + * glplan.h, glplan1.c, ..., glplan8.c
3.1799 + Several serious bugs were fixed in the language processor due
3.1800 + to reports provided by <NORBERT.PIOTROWSKI@LHSYSTEMS.COM>:
3.1801 + (a) a static search tree used to find sparse array elements was
3.1802 + sometimes overwritten that caused the message 'assertion failed'
3.1803 + to appear; the bug was fixed by creating separate search trees
3.1804 + in parsing routines; (b) a variable declared using the
3.1805 + predicate-controlled variable declaration statement had wrong
3.1806 + order of domain sets, because the variable array was built as
3.1807 + a copy of the predicate array; the bug was fixed by using the
3.1808 + internal routine transpose that coordinates mute letters (and
3.1809 + therefore domain sets) on copying sparse arrays; (c) sometimes
3.1810 + assignment statements like x[#a,#b,#c] := ... was incorrectly
3.1811 + processed; the bug was fixed by including an appropriate check
3.1812 + into the internal routine assign_stmt.
3.1813 +
3.1814 + * glp_simplex.c
3.1815 + An additional check to see if all lower bounds are not greater
3.1816 + than corresponding upper bounds was included in the routine to
3.1817 + prevent wrong results to appear. Such incorrectness sometimes
3.1818 + was not detected, namely, when variables with such bounds were
3.1819 + non-basic and never entered the basis.
3.1820 +
3.1821 + * glpspx1.c
3.1822 + Maximal number of simplex iterations before reinversion was
3.1823 + decreased from 100 to 50. This allowed to improve accuracy and,
3.1824 + that is more important, to reduce the solution time for many
3.1825 + serial lp problems approximately 1.5--2 times.
3.1826 +
3.1827 + * glpspx2.c
3.1828 + A check to see if all elements in the column chosen to enter
3.1829 + the basis are close to zero in the routine spx_prim_chuzr was
3.1830 + temporarily removed because this check gave wrong conclusion in
3.1831 + case when the corresponding non-basic variable had zero column
3.1832 + in the constraint matrix. An analogous check to see if all
3.1833 + elements in the row chosen to leave the basis are close to zero
3.1834 + in the routine spx_dual_chuzc was also temporarily removed on
3.1835 + the same reason. The bug was fixed due to reports provided by
3.1836 + Flavio Keidi Miyazawa <fkm@ic.unicamp.br> and Vlahos Kiriakos
3.1837 + <Kiriakos.Vlahos@gs.com>.
3.1838 +
3.1839 +Mon Aug 12 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1840 +
3.1841 + * GLPK 3.2.1 has been released.
3.1842 +
3.1843 + * glpbcs.h, glpbcs1.c, glpbcs2.c
3.1844 + * glpies.h, glpies1.c, glpies2.c, glpies3.c
3.1845 + A preliminary implementation of the branch-and-cut framework
3.1846 + was included in the package.
3.1847 +
3.1848 + * doc/brcut.txt
3.1849 + The document "GLPK: A Preliminary Implementation of the
3.1850 + Branch-And-Cut Framework" was included in the distribution.
3.1851 +
3.1852 + * sample/tspsol.c
3.1853 + An illustrative program for solving symmetric TSP based on the
3.1854 + branch-and-cut method was included in the package.
3.1855 +
3.1856 + * glpdmp.h, glpdmp.c
3.1857 + A new, re-enterable version of routines for managing dynamic
3.1858 + memory pools was included in the package.
3.1859 +
3.1860 + * glpavl.h, glpavl.c
3.1861 + A new, re-enterable version of routines for managing AVL search
3.1862 + trees was included in the package.
3.1863 +
3.1864 + * glplib.h, glplib2.c
3.1865 + Two new low-level routines ufopen and ufclose were included in
3.1866 + the package.
3.1867 +
3.1868 + * glplpx.h, glplpx7.c
3.1869 + The following new api routines were added: lpx_eval_activity,
3.1870 + lpx_eval_red_cost, lpx_reduce_form, lpx_mixed_gomory.
3.1871 +
3.1872 + * glptsp.h, glptsp.c
3.1873 + A module for reading TSP data using TSPLIB format was included
3.1874 + in the package.
3.1875 +
3.1876 +Mon Jul 15 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1877 +
3.1878 + * GLPK 3.2 has been released.
3.1879 +
3.1880 + * glplpx.h, glplpx1.c, glplpx2.c
3.1881 + The identifier 'class' (used as a member name in the structure
3.1882 + LPX and as an argument name in the routine lpx_set_class) was
3.1883 + changed to 'clss' in order to avoid conflicts with C++ reserved
3.1884 + words.
3.1885 +
3.1886 + * glpk.h, glplpx.h, glplpx1.c, glplpx2.c, glplpx6a.c,
3.1887 + * glplpx6b.c, glplpx6c.c, glplpx7.c, glplpx8.c
3.1888 + The following new api routines were added: lpx_set_obj_name,
3.1889 + lpx_get_obj_name, lpx_get_row_mark, lpx_get_col_mark,
3.1890 + lpx_transform_row, lpx_transform_col, lpx_prim_ratio_test,
3.1891 + lpx_dual_ratio_test, lpx_interior, lpx_get_ips_stat,
3.1892 + lpx_get_ips_row, lpx_get_ips_col, lpx_get_ips_obj, lpx_read_lpm,
3.1893 + lpx_write_mps, lpx_print_ips.
3.1894 +
3.1895 + * glpsol.c
3.1896 + The solver was completely re-programmed using new api routines.
3.1897 +
3.1898 + * lang.latex, lang.dvi, lang.ps
3.1899 + New edition of the document "GLPK: Modeling Language GLPK/L"
3.1900 + was included in the distribution.
3.1901 +
3.1902 + * refman.latex, refman.dvi, refman.ps
3.1903 + New edition of the document "GLPK: Reference Manual" (which
3.1904 + contains descriptions of all new api routines) was included in
3.1905 + the distribution.
3.1906 +
3.1907 + * glpapi.h, glpapi1.c, glpapi2.c, glpapi3.c, glpapi4.c
3.1908 + These files (which contain old api routines) were removed from
3.1909 + the package.
3.1910 +
3.1911 + * glpipm1.c, glpipm2.c
3.1912 + The file glpipm1.c was renamed to glpipm.c. The file glpipm2.c
3.1913 + was used only by old api routines and therefore was removed from
3.1914 + the package.
3.1915 +
3.1916 + * language.texinfo
3.1917 + Old version of the document "GLPK: Modeling Language GLPK/L" was
3.1918 + removed from the distribution.
3.1919 +
3.1920 +Mon May 27 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1921 +
3.1922 + * GLPK 3.1 has been released.
3.1923 +
3.1924 + * glplpx.h, glplpx1.c, glplpx2.c, glplpx3.c, glplpx4.c,
3.1925 + * glplpx5.c, glplpx6.c, glplpx7.c, glplpx8.c
3.1926 + A preliminary implementation of new API routines was completed.
3.1927 +
3.1928 + * refman.latex, refman.dvi, refman.ps
3.1929 + A draft edition of the document "GLPK Reference Manual", which
3.1930 + describes new API routines, was included.
3.1931 +
3.1932 + * glplib3.c
3.1933 + A bug in measuring long time intervals was fixed up.
3.1934 +
3.1935 + * glprsm3.c
3.1936 + This module contains some obsolete routines not longer used and
3.1937 + therefore it was removed from the package (into the subdirectory
3.1938 + 'oldsrc').
3.1939 +
3.1940 + * glprsm.h
3.1941 + Some declarations related to the module 'glprsm3.c' (see above)
3.1942 + were removed.
3.1943 +
3.1944 + * guide.texinfo
3.1945 + The document "GLPK User's Guide" describing old API routines was
3.1946 + removed from the package (into the subdirectory 'oldsrc').
3.1947 +
3.1948 + * newapi.txt
3.1949 + The document "New GLPK API Routines" was removed at all, because
3.1950 + it is superseded by the new reference manual (see above).
3.1951 +
3.1952 +Mon May 13 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1953 +
3.1954 + * GLPK 3.0.8 has been released.
3.1955 +
3.1956 + * glplpx.h, glplpx1.c, glplpx2.c, glplpx3.c, glplpx4.c,
3.1957 + * glplpx5.c, glplpx6.c, glplpx7.c
3.1958 + A preliminary (currently incomplete) implementation of new api
3.1959 + routines was included.
3.1960 +
3.1961 + * sample/newsamp.c
3.1962 + A sample program for the new api routines was included.
3.1963 +
3.1964 + * newapi.txt
3.1965 + A draft of the document "New GLPK API Routines" was included.
3.1966 +
3.1967 + * glpapi2.c, glpapi5.c, glpapi6.c
3.1968 + These modules (which contain the api routines glp_call_rsm1,
3.1969 + glp_simplex1, glp_pivot_in, glp_pivot_out) were removed from the
3.1970 + package (to the subdirectory 'oldsrc') since these routines are
3.1971 + functionally superseded by the new api routines.
3.1972 +
3.1973 + * glpk.h, glpapi2.c, glpapi3.c, glpapi4.c
3.1974 + The api routines glp_simplex2, glp_call_ipm1, glp_call_bbm1 were
3.1975 + renamed to glp_simplex, glp_interior, glp_integer, respectively.
3.1976 +
3.1977 + * sample/glpsol.c
3.1978 + Some command-line options (which got obsolete due to the recent
3.1979 + changes in api) were excluded.
3.1980 +
3.1981 + * doc/guide.texinfo
3.1982 + New edition of the document "GLPK User's Guide" was included in
3.1983 + the distribution to reflect the changes in some api routines.
3.1984 +
3.1985 + * doc/libref.texinfo
3.1986 + This document was removed from the package (to the subdirectory
3.1987 + 'oldsrc') since it describes the library routines, most of which
3.1988 + got obsolete and no longer used.
3.1989 +
3.1990 + * Makefile.in
3.1991 + A minor bug was fixed up due to bug report from Hans Schwengeler
3.1992 + <Hans.Schwengeler@unibas.ch>.
3.1993 +
3.1994 +Mon Apr 22 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
3.1995 +
3.1996 + * GLPK 3.0.7 has been released.
3.1997 +
3.1998 + * glpduff.h, glpduff.c, glpspx.h, glpspx1.c, glpspx2.c,
3.1999 + * glpapi7.c
3.2000 + These modules were replaced by a new implementation of the
3.2001 + simplex method and therefore they were removed from the package
3.2002 + (however they still can be found in the subdirectory 'oldsrc').
3.2003 +
3.2004 + * glprsm1.c
3.2005 + The routine crash_aa was replaced by a new implementation and
3.2006 + therefore it was removed from the file 'glprsm1.c'.
3.2007 +
3.2008 + * glplpx.h, glplpx.c, glpspx.h, glpspx1.c, glpspx2.c, glpspx3.c,
3.2009 + * glpspx4.c, glpapi7.c
3.2010 + New (currently incomplete) implementation of the simplex method
3.2011 + components was included in the package.
3.2012 +
3.2013 +Thu Mar 28 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
3.2014 +
3.2015 + * GLPK 3.0.6 has been released.
3.2016 +
3.2017 + * glpluf.h, glpluf.c, glpinv.h, glpinv.c
3.2018 + New version of LU-factorization and basis maintenance routines
3.2019 + (based on Forrest-Tomlin updating technique) was implemented.
3.2020 +
3.2021 + * glpeta.h, glpeta.c, glpfhv.h, glpfhv.c, glpgel.h, glpgel.c,
3.2022 + * glppfi.h, glppfi.c, glprfi.h, glprfi.c
3.2023 + These routines implement some other forms of the basis matrix.
3.2024 + Now they became obsolete being functionally superseded by the
3.2025 + new version of basis maintenance routines (see above) and were
3.2026 + removed from the package (however they still can be found in the
3.2027 + subdirectory 'oldsrc').
3.2028 +
3.2029 + * glpbbm.c, glprsm.h, glprsm1.h, glprsm2.h, glpspx.h, glpspx2.c,
3.2030 + * glprsm2.c, glpsol.c
3.2031 + Necessary changes were made in order to use the new version of
3.2032 + basis maintenance routines.
3.2033 +
3.2034 +Tue Jan 29 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
3.2035 +
3.2036 + * GLPK 3.0.5 has been released.
3.2037 + Structure of the package was re-organized in order to simplify
3.2038 + its maintenance.
3.2039 +
3.2040 + * doc/guide.texinfo
3.2041 + New edition of the document "GLPK User's Guide" was included in
3.2042 + the distribution. Now the document includes descriptions of some
3.2043 + additional API routines recently added to the package.
3.2044 +
3.2045 + * doc/newapi.txt
3.2046 + The document "Additional GLPK API Routines" was removed from the
3.2047 + distribution, because the corresponding material was included in
3.2048 + the user's guide (see above).
3.2049 +
3.2050 +Mon Dec 10 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
3.2051 +
3.2052 + * GLPK 3.0.4 has been released.
3.2053 +
3.2054 + * glpspx.h, glpspx1.c, glpspx2.c, glpapi/glp_simplex2.h
3.2055 + A new, more efficient version of the two-phase primal simplex
3.2056 + method was implemented (advanced initial basis, projected
3.2057 + steepest edge, recursive computations of solution components).
3.2058 +
3.2059 + * glpapi/glp_call_bbm1.c
3.2060 + Now LP relaxation can be solved either using rsm1_driver(), or
3.2061 + using glp_simplex2(). The choice is controlled by the parameter
3.2062 + 'meth' (a member of struct bbm1).
3.2063 +
3.2064 + * sample/glpsol.c
3.2065 + The new implementation of the simplex method is now used by
3.2066 + default. The old version is available via --old-sim option.
3.2067 +
3.2068 + * glpmat/gm_scaling.c
3.2069 + Now this routine displays only two lines: an initial "quality"
3.2070 + and a final "quality".
3.2071 +
3.2072 + * glplp/prepro_lp.c
3.2073 + Identifiers 'fmin' and 'fmax' renamed to 'f_min' and 'f_max' in
3.2074 + order to avoid conflict with <math.h>. The bug was fixed due to
3.2075 + report provided by Sami Farin <sfarin@ratol.fi>.
3.2076 +
3.2077 +Wed Oct 03 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
3.2078 +
3.2079 + * GLPK 3.0.3 has been released.
3.2080 +
3.2081 + * glprsm/harris_row.c, glprsm/harris_col.c
3.2082 + The relative tolerance used on the first pass of the two-pass
3.2083 + ratio test was replaced by the absolute tolerance.
3.2084 +
3.2085 + * glprsm/rsm_primal.c, glprsm/rsm_feas.c, glprsm/rsm_dual.c
3.2086 + The absolute tolerance passed to the two-pass ratio test routine
3.2087 + was decaresed (for both primal and dual simplex).
3.2088 +
3.2089 + These changes were made in order to improve numerical stability
3.2090 + of the simplex method.
3.2091 +
3.2092 + * glprsm/glp_call_rsm1.c, glprsm/glp_call_bbm1.c,
3.2093 + * glprsm/glp_simplex1, glprsm/glp_pivoting.c
3.2094 + Default form of the inverse was changed from RFI to AFI.
3.2095 +
3.2096 +Mon Sep 24 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
3.2097 +
3.2098 + * GLPK 3.0.2 has been released.
3.2099 +
3.2100 + * glpfhv.h, glpfhv.c
3.2101 + New version of the basis maintaining routines was implemented.
3.2102 + These routines, which are based on so called FHV-factorization
3.2103 + (a variety of LU-factorization) and Gustavson's data structures,
3.2104 + perform the main operations on the basis matrix faster at the
3.2105 + expense of some worsening numerical accuracy.
3.2106 +
3.2107 + * glprsm.h, glprsm/afi.c
3.2108 + The routines, which implement AFI (Advanced Form of the
3.2109 + Inverse) based on FHV-factorization, were added to the package.
3.2110 + This new form is available via the parameter form = 3 (on API
3.2111 + level) or via the option --afi (in GLPSOL solver).
3.2112 +
3.2113 + * EFI was renamed to PFI
3.2114 + In order to correct terminology the acronym EFI (Elimination
3.2115 + Form of the Inverse) was replaced by PFI (Product Form of the
3.2116 + Inverse) everywhere in the source code and the documentation.
3.2117 +
3.2118 + * glpset/umalloc.c, glpset/ucalloc.c
3.2119 + * glpset/get_atom.c, glpset/get_atomv.c
3.2120 + These memory management routines were changed in order *not* to
3.2121 + clear allocated memory blocks by binary zeros.
3.2122 +
3.2123 +Wed Aug 01 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
3.2124 +
3.2125 + * GLPK 3.0.1 has been released.
3.2126 +
3.2127 + * glpapi/old_api.c, glplp/extract_lp.c, store_lpsol.c
3.2128 + Old API routines were deleted from the package.
3.2129 +
3.2130 + * include/glpk.h, include/glpapi.h, include/glplp.h
3.2131 + Specifications of old API routines and data structures were
3.2132 + removed from the headers.
3.2133 +
3.2134 + * sample/glpsol.c
3.2135 + New version of the stand-alone solver GLPSOL that now uses new
3.2136 + API routines was implemented.
3.2137 +
3.2138 + * glpapi/glp_set_row_fctr.c, glpapi/glp_set_col_fctr.c,
3.2139 + * glpapi/glp_get_row_fctr.c, glpapi/glp_get_col_fctr.c,
3.2140 + * glpapi/glp_scale_prob.c
3.2141 + Scaling routines were added.
3.2142 +
3.2143 + * glpapi/glp_write_mps.c
3.2144 + The routine for writing problem data in MPS format was added.
3.2145 +
3.2146 + * glpapi/glp_simplex1.c
3.2147 + Comprehensive driver to the simplex method was added.
3.2148 +
3.2149 + * glpapi/glp_pivoting.c
3.2150 + The routines glp_pivot_in() and glp_pivot_out() intended for
3.2151 + basis maintaining were added.
3.2152 +
3.2153 + * glprsm/create_rsm.c, glprsm/delete_rsm.c, glprsm/scale_rsm.c,
3.2154 + * glprsm/build_basis.c
3.2155 + Additional low level routines related to the simplex method
3.2156 + were added.
3.2157 +
3.2158 + * glpk.h, glpapi.h, glprsm.h
3.2159 + Additional specifications for new routines and data structures
3.2160 + were added.
3.2161 +
3.2162 + * sample/lpglpk30.c
3.2163 + A non-trivial example was added. It allows using GLPK as a base
3.2164 + LP solver for Concorde, a program for solving Traveling Salesman
3.2165 + Problem (TSP). For details see comments in 'lpglpk30.c'.
3.2166 +
3.2167 + * doc/newapi.txt
3.2168 + The document "Additional GLPK API Routines" that describes some
3.2169 + new API routines was included.
3.2170 +
3.2171 +Thu Jul 19 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
3.2172 +
3.2173 + * GLPK 3.0 has been released.
3.2174 +
3.2175 + Now GLPK is provided with new API, which is intended for using
3.2176 + the package in more complex algorithmic schemes.
3.2177 +
3.2178 + * glpapi/old_api.c
3.2179 + All routines related to old API were gathered in one file named
3.2180 + 'old_api.c'.
3.2181 +
3.2182 + * glpapi/*.c
3.2183 + These routines that implement new API were added to the package.
3.2184 +
3.2185 + * include/glpk.h, include/glpapi.h
3.2186 + Specifications of new API routines and data structures were
3.2187 + added to these headers. Specifications of old API routines and
3.2188 + data structures were locked by #ifdef GLP_OLD_API directive.
3.2189 +
3.2190 + * doc/guide.texinfo
3.2191 + New edition of the document "GLPK User's Guide" that correspond
3.2192 + to new API was included.
3.2193 +
3.2194 +Thu Jun 14 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
3.2195 +
3.2196 + * GLPK 2.4.1 has been released.
3.2197 +
3.2198 + * doc/glpk_ml.texinfo
3.2199 + The new document "Modeling Language GLPK/L" was included.
3.2200 +
3.2201 + * doc/glpk_ug.texinfo
3.2202 + New edition of the document "GLPK User's Guide" was included.
3.2203 +
3.2204 + * doc/language.txt
3.2205 + The preliminary document "GLPK/L Modeling Language: A Brief
3.2206 + description" was removed from the distribution, because it has
3.2207 + been replaced by the new document "Modeling Language GLPK/L".
3.2208 +
3.2209 + * glplang/l_spar.c
3.2210 + The routine comparison() was re-programmed in order to
3.2211 + implement the relation operation as specified in the language
3.2212 + description.
3.2213 +
3.2214 + * glpmip.h, glpmip/*.c
3.2215 + The partition 'glpmip' was renamed to 'glpbbm'.
3.2216 +
3.2217 +Thu May 10 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
3.2218 +
3.2219 + * GLPK 2.4 has been released.
3.2220 +
3.2221 + Now GLPK includes an implementation of a preliminary version of
3.2222 + the GLPK/L modeling language.
3.2223 +
3.2224 + * glplang.h, glplang/*.c
3.2225 + The header 'glplang.h' and a set of routines that implements
3.2226 + the GLPK/L language processor (the partition 'glplang') were
3.2227 + added to the package.
3.2228 +
3.2229 + * doc/language.txt
3.2230 + The document "GLPK/L Modeling Language: A Brief Description
3.2231 + (Supplement to GLPK User's Guide)" in plain text format was
3.2232 + included in the package (see the file 'language.txt' in the
3.2233 + subdirectory 'doc' of the distribution).
3.2234 +
3.2235 + * ex/model1.lpm, ex/model2.lpm
3.2236 + Two examples of model descriptions written in GLPK/L were added
3.2237 + to the package.
3.2238 +
3.2239 + * sample/glpsol.c
3.2240 + This program was modified in order: a) to allow processing
3.2241 + model description written in GLPK/L; b) to allow solving pure
3.2242 + LP problem using the interior point method.
3.2243 +
3.2244 + * sample/glpipm.c
3.2245 + This program was removed from the package, because its function
3.2246 + was passed to the GLPSOL solver.
3.2247 +
3.2248 + * Makefile.in
3.2249 + This file was changed in order to install the GLPSOL solver
3.2250 + executable.
3.2251 +
3.2252 +Mon Apr 09 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
3.2253 +
3.2254 + * GLPK 2.3 has been released.
3.2255 +
3.2256 + * glpmip.h, glpmip/*.c
3.2257 + These routines (that implement the branch-and-bound method) were
3.2258 + re-programmed in order to improve robustness of implementation.
3.2259 + In particular, heuristic routines were carried out from the main
3.2260 + driver routine.
3.2261 +
3.2262 + Additional GLPK API routines were documented.
3.2263 +
3.2264 + New edition of the document "GLPK User's Guide" was included in
3.2265 + the package.
3.2266 +
3.2267 + The preliminary document "Mixed Integer Programming Using GLPK
3.2268 + Version 2.2 (Supplement to GLPK User's Guide)" was removed from
3.2269 + the package, because this material was included in GLPK User's
3.2270 + Guide.
3.2271 +
3.2272 +Thu Mar 15 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
3.2273 +
3.2274 + * GLPK 2.2 has been released.
3.2275 +
3.2276 + Now GLPK includes a tentative implementation of the
3.2277 + branch-and-bound procedure based on the dual simplex method for
3.2278 + mixed integer linear programming (MIP).
3.2279 +
3.2280 + The preliminary document "Mixed Integer Programming Using GLPK
3.2281 + Version 2.2 (Supplement to GLPK User's Guide)" was included into
3.2282 + the package in plain text format (see the file 'mip.txt' in the
3.2283 + subdirectory 'doc' of the distribution).
3.2284 +
3.2285 + * glpmip.h, glpmip/*.c, glpapi/glp_integer.c
3.2286 + These routines (that implement the branch-and-bound method) were
3.2287 + added to the package.
3.2288 +
3.2289 + * sample/glpsol.c
3.2290 + This program was modified in order to allow solving LP and MIP
3.2291 + problems.
3.2292 +
3.2293 + * glprsm/rsm_primal.c, glprsm/rsm_dual.c, glprsm/rsm_feas.c,
3.2294 + * glprsm/rsm1_driver.c
3.2295 + These routines (which are drivers to basic components of the
3.2296 + revised simplex method) were added to the package.
3.2297 +
3.2298 +Mon Feb 19 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
3.2299 +
3.2300 + * GLPK 2.1 has been released.
3.2301 +
3.2302 + * glprsm.h, glprsm/*.c
3.2303 + These routines (that implement components of the revised simplex
3.2304 + method) were re-programmed and documented.
3.2305 +
3.2306 + The document "GLPK Implementation of the Revised Simplex Method"
3.2307 + was included into the package.
3.2308 +
3.2309 +Thu Jan 25 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
3.2310 +
3.2311 + * GLPK 2.0 has been released.
3.2312 +
3.2313 + Now GLPK includes a tentative implementation of the primal-dual
3.2314 + interior point method for large-scale linear programming (for
3.2315 + more details see the file `NEWS' in the distribution). A number
3.2316 + of routines related to the interior point method were added to
3.2317 + the package.
3.2318 +
3.2319 + * insist.c
3.2320 + The routine `insist' and the macro of the same name were
3.2321 + introduced into the package in order to replace the standard
3.2322 + macro `assert'. Some routines require the expression specified
3.2323 + in the `assert' macro to be evaluated, but compiling the package
3.2324 + with NDEBUG option prevents from that. This bug was fixed due to
3.2325 + bug report provided by Peter A. Huegler <phuegler@bsco.com>.
3.2326 +
3.2327 + * Makefile.in
3.2328 + Minor bug was fixed due to a patch provided by Alexandre Oliva
3.2329 + <oliva@lsd.ic.unicamp.br>.
3.2330 +
3.2331 +Wed Jan 10 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
3.2332 +
3.2333 + * GLPK 1.1.2 has been released.
3.2334 +
3.2335 + * umalloc.c, ufree.c, create_pool.c, get_atom.c, get_atomv.c
3.2336 + These routines were changed in order to fix a bug due to
3.2337 + report provided by Andrew Hood <ajhood@fl.net.au>. Because of
3.2338 + this bug data alignment error occured on the Sparc computer.
3.2339 +
3.2340 +Tue Dec 14 12:00:00 2000 Andrew Makhorin <mao@mai2.rcnet.ru>
3.2341 +
3.2342 + * GLPK 1.1.1 has been released.
3.2343 +
3.2344 + Minor bug was fixed in `Makefile.in'.
3.2345 +
3.2346 + GLPK Library Reference was included.
3.2347 +
3.2348 +Mon Nov 27 12:00:00 2000 Andrew Makhorin <mao@mai2.rcnet.ru>
3.2349 +
3.2350 + * GLPK 1.1 has been released.
3.2351 +
3.2352 + Minor changes were made in order to co-ordinate GLPK routines
3.2353 + and their descriptions.
3.2354 +
3.2355 + GLPK User's Guide was included.
3.2356 +
3.2357 +Fri Oct 20 12:00:00 2000 Andrew Makhorin <mao@mai2.rcnet.ru>
3.2358 +
3.2359 + * GLPK 1.0 has been released.
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/INSTALL Mon Dec 06 13:09:21 2010 +0100
4.3 @@ -0,0 +1,209 @@
4.4 +INSTALLING GLPK ON YOUR COMPUTER
4.5 +********************************
4.6 +
4.7 +Unpacking the distribution file
4.8 +-------------------------------
4.9 +The GLPK package (like all other GNU software) is distributed in the
4.10 +form of a packed archive. It is one file named `glpk-X.Y.tar.gz', where
4.11 +`X' is the major version number and `Y' is the minor version number;
4.12 +for example, the archive name might be `glpk-4.15.tar.gz'.
4.13 +
4.14 +In order to prepare the distribution for installation you should:
4.15 +
4.16 +1. Copy the GLPK distribution file to a working directory.
4.17 +
4.18 +2. Unpack the distribution file with the following command:
4.19 +
4.20 + gzip -d glpk-X.Y.tar.gz
4.21 +
4.22 + After unpacking the distribution file is automatically renamed to
4.23 + `glpk-X.Y.tar'.
4.24 +
4.25 +3. Unarchive the distribution file with the following command:
4.26 +
4.27 + tar -x < glpk-X.Y.tar
4.28 +
4.29 + It automatically creates the subdirectory `glpk-X.Y' containing the
4.30 + GLPK distribution.
4.31 +
4.32 +Configuring the package
4.33 +-----------------------
4.34 +After unpacking and unarchiving the GLPK distribution you should
4.35 +configure the package, i.e. automatically tune it for your platform.
4.36 +
4.37 +Normally, you should just `cd' to the directory `glpk-X.Y' and run the
4.38 +`configure' script, e.g.
4.39 +
4.40 + ./configure
4.41 +
4.42 +The `configure' shell script attempts to guess correct values for
4.43 +various system-dependent variables used during compilation. It uses
4.44 +those values to create a `Makefile' in each directory of the package.
4.45 +It also creates file `config.h' containing platform-dependent
4.46 +definitions. Finally, it creates a shell script `config.status' that
4.47 +you can run in the future to recreate the current configuration, a file
4.48 +`config.cache' that saves the results of its tests to speed up
4.49 +reconfiguring, and a file `config.log' containing compiler output
4.50 +(useful mainly for debugging `configure').
4.51 +
4.52 +Running `configure' takes about a few seconds. While it is running, it
4.53 +displays some messages that tell you what it is doing. If you don't want
4.54 +to see the messages, run `configure' with its standard output redirected
4.55 +to `dev/null'; for example, `./configure > /dev/null'.
4.56 +
4.57 +By default both static and shared versions of the GLPK library will be
4.58 +compiled. Compilation of the shared librariy can be turned off by
4.59 +specifying the `--disable-shared' option to `configure', e.g.
4.60 +
4.61 + ./configure --disable-shared
4.62 +
4.63 +If you encounter problems building the library try using the above
4.64 +option, because some platforms do not support shared libraries.
4.65 +
4.66 +The GLPK package has some optional features listed below. By default
4.67 +all these features are disabled. To enable a feature the corresponding
4.68 +option should be passed to the configure script.
4.69 +
4.70 +--with-gmp Enable using the GNU MP bignum library
4.71 +
4.72 + This feature allows the exact simplex solver to use the GNU MP
4.73 + bignum library. If it is disabled, the exact simplex solver uses the
4.74 + GLPK bignum module, which provides the same functionality as GNU MP,
4.75 + however, it is much less efficient.
4.76 +
4.77 + For details about the GNU MP bignum library see its web page at
4.78 + <http://gmplib.org/>.
4.79 +
4.80 +--with-zlib Enable using the zlib data compression library
4.81 +
4.82 + This feature allows GLPK API routines and the stand-alone solver to
4.83 + read and write compressed data files performing compression and
4.84 + decompression "on the fly" (compressed data files are recognized by
4.85 + suffix `.gz' in the file name). It may be useful in case of large
4.86 + MPS files to save the disk space.
4.87 +
4.88 + For details about the zlib compression library see its web page at
4.89 + <http://www.zlib.net/>.
4.90 +
4.91 +--enable-dl The same as --enable-dl=ltdl
4.92 +--enable-dl=ltdl Enable shared library support (GNU)
4.93 +--enable-dl=dlfcn Enable shared library support (POSIX)
4.94 +
4.95 + Currently this feature is only needed to provide dynamic linking to
4.96 + ODBC and MySQL shared libraries (see below).
4.97 +
4.98 + For details about the GNU shared library support see the manual at
4.99 + <http://www.gnu.org/software/libtool/manual/>.
4.100 +
4.101 +--enable-odbc Enable using ODBC table driver (libiodbc)
4.102 +--enable-odbc=unix Enable using ODBC table driver (libodbc)
4.103 +
4.104 + This feature allows transmitting data between MathProg model objects
4.105 + and relational databases accessed through ODBC.
4.106 +
4.107 + For more details about this feature see the supplement "Using Data
4.108 + Tables in the GNU MathProg Modeling Language" (doc/tables.*).
4.109 +
4.110 +--enable-mysql Enable using MySQL table driver (libmysql)
4.111 +
4.112 + This feature allows transmitting data between MathProg model objects
4.113 + and MySQL relational databases.
4.114 +
4.115 + For more details about this feature see the supplement "Using Data
4.116 + Tables in the GNU MathProg Modeling Language" (doc/tables.*).
4.117 +
4.118 +Compiling the package
4.119 +---------------------
4.120 +Normally, you can compile (build) the package by typing the command:
4.121 +
4.122 + make
4.123 +
4.124 +It reads `Makefile' generated by `configure' and performs all necessary
4.125 +jobs.
4.126 +
4.127 +If you want, you can override the `make' variables CFLAGS and LDFLAGS
4.128 +like this:
4.129 +
4.130 + make CFLAGS=-O2 LDFLAGS=-s
4.131 +
4.132 +To compile the package in a different directory from the one containing
4.133 +the source code, you must use a version of `make' that supports `VPATH'
4.134 +variable, such as GNU `make'. `cd' to the directory where you want the
4.135 +object files and executables to go and run the `configure' script.
4.136 +`configure' automatically checks for the source code in the directory
4.137 +that `configure' is in and in `..'. If for some reason `configure' is
4.138 +not in the source code directory that you are configuring, then it will
4.139 +report that it can't find the source code. In that case, run `configure'
4.140 +with the option `--srcdir=DIR', where DIR is the directory that contains
4.141 +the source code.
4.142 +
4.143 +Some systems require unusual options for compilation or linking that
4.144 +the `configure' script does not know about. You can give `configure'
4.145 +initial values for variables by setting them in the environment. Using
4.146 +a Bourne-compatible shell, you can do that on the command line like
4.147 +this:
4.148 +
4.149 + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
4.150 +
4.151 +Or on systems that have the `env' program, you can do it like this:
4.152 +
4.153 + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
4.154 +
4.155 +Here are the `make' variables that you might want to override with
4.156 +environment variables when running `configure'.
4.157 +
4.158 +For these variables, any value given in the environment overrides the
4.159 +value that `configure' would choose:
4.160 +
4.161 +CC: C compiler program. The default is `cc'.
4.162 +
4.163 +INSTALL: Program used to install files. The default value is `install'
4.164 + if you have it, otherwise `cp'.
4.165 +
4.166 +For these variables, any value given in the environment is added to the
4.167 +value that `configure' chooses:
4.168 +
4.169 +DEFS: Configuration options, in the form `-Dfoo -Dbar ...'.
4.170 +
4.171 +LIBS: Libraries to link with, in the form `-lfoo -lbar ...'.
4.172 +
4.173 +Checking the package
4.174 +--------------------
4.175 +To check the package, i.e. to run some tests included in the package,
4.176 +you can use the following command:
4.177 +
4.178 + make check
4.179 +
4.180 +Installing the package
4.181 +----------------------
4.182 +Normally, to install the GLPK package you should type the following
4.183 +command:
4.184 +
4.185 + make install
4.186 +
4.187 +By default, `make install' will install the package's files in
4.188 +`usr/local/bin', `usr/local/lib', etc. You can specify an installation
4.189 +prefix other than `/usr/local' by giving `configure' the option
4.190 +`--prefix=PATH'. Alternately, you can do so by consistently giving a
4.191 +value for the `prefix' variable when you run `make', e.g.
4.192 +
4.193 + make prefix=/usr/gnu
4.194 + make prefix=/usr/gnu install
4.195 +
4.196 +After installing you can remove the program binaries and object files
4.197 +from the source directory by typing `make clean'. To remove all files
4.198 +that `configure' created (`Makefile', `config.status', etc.), just type
4.199 +`make distclean'.
4.200 +
4.201 +The file `configure.ac' is used to create `configure' by a program
4.202 +called `autoconf'. You only need it if you want to remake `configure'
4.203 +using a newer version of `autoconf'.
4.204 +
4.205 +Uninstalling the package
4.206 +------------------------
4.207 +To uninstall the GLPK package, i.e. to remove all the package's files
4.208 +from the system places, you can use the following command:
4.209 +
4.210 + make uninstall
4.211 +
4.212 +========================================================================
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/Makefile.am Mon Dec 06 13:09:21 2010 +0100
5.3 @@ -0,0 +1,7 @@
5.4 +## Process this file with automake to produce Makefile.in ##
5.5 +
5.6 +ACLOCAL_AMFLAGS=-I m4
5.7 +
5.8 +SUBDIRS = include src examples
5.9 +
5.10 +## eof ##
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/Makefile_MMIX Mon Dec 06 13:09:21 2010 +0100
6.3 @@ -0,0 +1,149 @@
6.4 +# Build GLPK for MMIX with GCC cross-compiler
6.5 +
6.6 +#**********************************************************************#
6.7 +# You can use this Makefile to build GLPK with GCC cross-compiler for #
6.8 +# MMIX. No configuring is needed. #
6.9 +# #
6.10 +# MMIX is a 64-bit RISC computer for the third millennium designed by #
6.11 +# Prof. Donald Knuth. For details see: #
6.12 +# #
6.13 +# http://www-cs-faculty.stanford.edu/~knuth/mmix.html #
6.14 +# http://en.wikipedia.org/wiki/MMIX #
6.15 +# http://www.malgil.com/mmix #
6.16 +# #
6.17 +# The GNU MMIX compiler tool-suite (GCC backend, binutils, and newlib) #
6.18 +# was developed by Hans-Peter Nilsson. You may follow his instructions #
6.19 +# to build and install the MMIX tools; see: #
6.20 +# #
6.21 +# http://bitrange.com/mmix/install.html #
6.22 +#**********************************************************************#
6.23 +
6.24 +GCC = mmix-gcc
6.25 +AR = mmix-ar
6.26 +MMIX = mmix
6.27 +CFLAGS = -O2
6.28 +
6.29 +OBJSET = \
6.30 +src/glpapi01.o \
6.31 +src/glpapi02.o \
6.32 +src/glpapi03.o \
6.33 +src/glpapi04.o \
6.34 +src/glpapi05.o \
6.35 +src/glpapi06.o \
6.36 +src/glpapi07.o \
6.37 +src/glpapi08.o \
6.38 +src/glpapi09.o \
6.39 +src/glpapi10.o \
6.40 +src/glpapi11.o \
6.41 +src/glpapi12.o \
6.42 +src/glpapi13.o \
6.43 +src/glpapi14.o \
6.44 +src/glpapi15.o \
6.45 +src/glpapi16.o \
6.46 +src/glpapi17.o \
6.47 +src/glpapi18.o \
6.48 +src/glpapi19.o \
6.49 +src/glpavl.o \
6.50 +src/glpbfd.o \
6.51 +src/glpbfx.o \
6.52 +src/glpcpx.o \
6.53 +src/glpdmp.o \
6.54 +src/glpdmx.o \
6.55 +src/glpenv01.o \
6.56 +src/glpenv02.o \
6.57 +src/glpenv03.o \
6.58 +src/glpenv04.o \
6.59 +src/glpenv05.o \
6.60 +src/glpenv06.o \
6.61 +src/glpenv07.o \
6.62 +src/glpenv08.o \
6.63 +src/glpfhv.o \
6.64 +src/glpgmp.o \
6.65 +src/glphbm.o \
6.66 +src/glpini01.o \
6.67 +src/glpini02.o \
6.68 +src/glpios01.o \
6.69 +src/glpios02.o \
6.70 +src/glpios03.o \
6.71 +src/glpios04.o \
6.72 +src/glpios05.o \
6.73 +src/glpios06.o \
6.74 +src/glpios07.o \
6.75 +src/glpios08.o \
6.76 +src/glpios09.o \
6.77 +src/glpios10.o \
6.78 +src/glpios11.o \
6.79 +src/glpios12.o \
6.80 +src/glpipm.o \
6.81 +src/glplib01.o \
6.82 +src/glplib02.o \
6.83 +src/glplib03.o \
6.84 +src/glplpf.o \
6.85 +src/glplpx01.o \
6.86 +src/glplpx02.o \
6.87 +src/glplpx03.o \
6.88 +src/glpluf.o \
6.89 +src/glplux.o \
6.90 +src/glpmat.o \
6.91 +src/glpmpl01.o \
6.92 +src/glpmpl02.o \
6.93 +src/glpmpl03.o \
6.94 +src/glpmpl04.o \
6.95 +src/glpmpl05.o \
6.96 +src/glpmpl06.o \
6.97 +src/glpmps.o \
6.98 +src/glpnet01.o \
6.99 +src/glpnet02.o \
6.100 +src/glpnet03.o \
6.101 +src/glpnet04.o \
6.102 +src/glpnet05.o \
6.103 +src/glpnet06.o \
6.104 +src/glpnet07.o \
6.105 +src/glpnet08.o \
6.106 +src/glpnet09.o \
6.107 +src/glpnpp01.o \
6.108 +src/glpnpp02.o \
6.109 +src/glpnpp03.o \
6.110 +src/glpnpp04.o \
6.111 +src/glpnpp05.o \
6.112 +src/glpqmd.o \
6.113 +src/glprgr.o \
6.114 +src/glprng01.o \
6.115 +src/glprng02.o \
6.116 +src/glpscf.o \
6.117 +src/glpscl.o \
6.118 +src/glpsdf.o \
6.119 +src/glpspm.o \
6.120 +src/glpspx01.o \
6.121 +src/glpspx02.o \
6.122 +src/glpsql.o \
6.123 +src/glpssx01.o \
6.124 +src/glpssx02.o \
6.125 +src/glptsp.o \
6.126 +src/amd/amd_1.o \
6.127 +src/amd/amd_2.o \
6.128 +src/amd/amd_aat.o \
6.129 +src/amd/amd_control.o \
6.130 +src/amd/amd_defaults.o \
6.131 +src/amd/amd_dump.o \
6.132 +src/amd/amd_info.o \
6.133 +src/amd/amd_order.o \
6.134 +src/amd/amd_post_tree.o \
6.135 +src/amd/amd_postorder.o \
6.136 +src/amd/amd_preprocess.o \
6.137 +src/amd/amd_valid.o \
6.138 +src/colamd/colamd.o
6.139 +
6.140 +.c.o:
6.141 + $(GCC) $(CFLAGS) -Iinclude -Isrc -o $@ -c $<
6.142 +
6.143 +all: libglpk.a glpsol.mmo
6.144 +
6.145 +libglpk.a: $(OBJSET)
6.146 + $(AR) cru libglpk.a $(OBJSET)
6.147 +
6.148 +glpsol.mmo: examples/glpsol.o libglpk.a
6.149 + $(GCC) $(CFLAGS) -o glpsol.mmo examples/glpsol.o libglpk.a -lm
6.150 +
6.151 +check: glpsol.mmo
6.152 + $(MMIX) glpsol.mmo --mps examples/plan.mps
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/NEWS Mon Dec 06 13:09:21 2010 +0100
7.3 @@ -0,0 +1,1532 @@
7.4 +GLPK 4.45 (release date: Dec 05, 2010)
7.5 +
7.6 + This is a bug-fix release.
7.7 +
7.8 + Several bugs/typos were fixed. Thanks to
7.9 + Xypron <xypron.glpk@gmx.de>,
7.10 + Robbie Morrison <robbie@actrix.co.nz>, and
7.11 + Ali Baharev <ali.baharev@gmail.com> for reports.
7.12 +
7.13 + Some glpk documents was re-formatted and merged into a single
7.14 + document. Now the glpk documentation consists of the following
7.15 + three main documents (all included in the distribution):
7.16 +
7.17 + GLPK: Reference Manual
7.18 +
7.19 + GLPK: Graph and Network Routines
7.20 +
7.21 + Modeling Language GNU MathProg: Language Reference
7.22 +
7.23 +GLPK 4.44 (release date: Jun 03, 2010)
7.24 +
7.25 + The following suffixes for variables and constraints were
7.26 + implemented in the MathProg language:
7.27 +
7.28 + .lb (lower bound),
7.29 + .ub (upper bound),
7.30 + .status (status in the solution),
7.31 + .val (primal value), and
7.32 + .dual (dual value).
7.33 +
7.34 + Thanks to Xypron <xypron.glpk@gmx.de> for draft implementation
7.35 + and testing.
7.36 +
7.37 + Now the MathProg language allows comment records (marked by
7.38 + '#' in the very first position) in CSV data files read with the
7.39 + table statements. Note that the comment records may appear only
7.40 + in the beginning of a CSV data file.
7.41 +
7.42 + The API routine glp_cpp to solve the Critical Path Problem was
7.43 + added and documented.
7.44 +
7.45 +GLPK 4.43 (release date: Feb 20, 2010)
7.46 +
7.47 + This is a maintainer release.
7.48 +
7.49 + `configure.ac' was changed to allow building the package under
7.50 + Mac OS and Darwin with ODBC support.
7.51 + Thanks to Xypron <xypron.glpk@gmx.de> for suggestions and Noli
7.52 + Sicad <nsicad@gmail.com> for testing.
7.53 +
7.54 + The SQL table driver was improved to process NULL data. Thanks
7.55 + to Xypron <xypron.glpk@gmx.de>.
7.56 +
7.57 + Some bugs were fixed in the LP/MIP preprocessor.
7.58 +
7.59 +GLPK 4.42 (release date: Jan 13, 2010)
7.60 +
7.61 + The following new API routines were added:
7.62 +
7.63 + glp_check_dup check for duplicate elements in sparse
7.64 + matrix
7.65 + glp_sort_matrix sort elements of the constraint matrix
7.66 + glp_read_prob read problem data in GLPK format
7.67 + glp_write_prob write problem data in GLPK format
7.68 + glp_analyze_bound analyze active bound of non-basic variable
7.69 + glp_analyze_coef analyze objective coefficient at basic
7.70 + variable
7.71 + glp_print_ranges print sensitivity analysis report (this
7.72 + routine replaces lpx_print_sens_bnds and
7.73 + makes it deprecated)
7.74 +
7.75 + For description of these new routines and the GLPK LP/MIP
7.76 + format see a new edition of the reference manual included in
7.77 + the distribution. (Chapter "Graph and network API routines" was
7.78 + carried out from the main reference manual and included in the
7.79 + distribution as a separate document.)
7.80 +
7.81 + The following new command-line options were added to the stand-
7.82 + alone solver glpsol:
7.83 + --glp filename read problem data in GLPK format
7.84 + --wglp filename write problem data in GLPK format
7.85 + --ranges filename print sensitivity analysis report (this
7.86 + option replaces --bounds)
7.87 +
7.88 + Now all GLPK routines performing file I/O support special
7.89 + filenames "/dev/stdin", "/dev/stdout", and "/dev/stderr", which
7.90 + can be specified in the same way as regular filenames. This
7.91 + feature is plaform-independent.
7.92 +
7.93 +GLPK 4.41 (release date: Dec 21, 2009)
7.94 +
7.95 + The following new API routies were added:
7.96 +
7.97 + glp_transform_row transform explicitly specified row
7.98 + glp_transform_col transform explicitly specified column
7.99 + glp_prim_rtest perform primal ratio test
7.100 + glp_dual_rtest perform dual ratio test
7.101 +
7.102 + For description of these new routines see a new edition of the
7.103 + reference manual included in the distribution.
7.104 +
7.105 + The following API routines are deprecated: lpx_transform_row,
7.106 + lpx_transform_col, lpx_prim_ratio_test, lpx_dual_ratio_test.
7.107 +
7.108 + Some improvements were made in the MIP solver (glp_intopt).
7.109 +
7.110 + The SQL table driver used to read/write data in MathProg models
7.111 + was changed to allow multiple arguments separated by semicolon
7.112 + in SQL statements. Thanks to Xypron <xypron.glpk@gmx.de>.
7.113 +
7.114 + Two new options were added to the glpsol stand-alone solver:
7.115 + --seed value (to initialize the pseudo-random number generator
7.116 + used in MathProg models with specified value), and
7.117 + --ini filename (to use a basis previously saved with -w option
7.118 + as an initial basis on solving similar LP's).
7.119 +
7.120 + Two new MathProg example models were included. Thanks to
7.121 + Nigel Galloway <nigel_galloway@operamail.com> and Noli Sicad
7.122 + <nsicad@gmail.com> for contribution.
7.123 +
7.124 + Scripts to build GLPK with Microsoft Visual Studio 2010 for
7.125 + both 32-bit and 64-bit Windows were included. Thanks to Xypron
7.126 + <xypron.glpk@gmx.de> for contribution and testing.
7.127 +
7.128 +GLPK 4.40 (release date: Nov 03, 2009)
7.129 +
7.130 + The following new API routines were added:
7.131 +
7.132 + glp_del_vertices remove vertices from graph
7.133 + glp_del_arc remove arc from graph
7.134 + glp_wclique_exact find maximum weight clique with the exact
7.135 + algorithm developed by Prof. P. Ostergard
7.136 + glp_read_ccdata read graph in DIMACS clique/coloring
7.137 + format
7.138 + glp_write_ccdata write graph in DIMACS clique/coloring
7.139 + format
7.140 +
7.141 + For description of these new routines see a new edition of the
7.142 + reference manual included in the distribution.
7.143 +
7.144 + The hybrid pseudocost branching heuristic was included in the
7.145 + MIP solver. It is available on API level (iocp.br_tech should
7.146 + be set to GLP_BR_PCH) and in the stand-alone solver glpsol
7.147 + (via the command-line option --pcost). This heuristic may be
7.148 + useful on solving hard MIP instances.
7.149 +
7.150 + The branching heuristic by Driebeck and Tomlin (used in the
7.151 + MIP solver by default) was changed to switch to branching on
7.152 + most fractional variable if an lower bound of degradation of
7.153 + the objective is close to zero for all branching candidates.
7.154 +
7.155 + A bug was fixed in the LP preprocessor (routine npp_empty_col).
7.156 + Thanks to Stefan Vigerske <stefan@math.hu-berlin.de> for the
7.157 + bug report.
7.158 +
7.159 + A bug was fixed and some improvements were made in the FPUMP
7.160 + heuristic module. Thanks to Xypron <xypron.glpk@gmx.de>.
7.161 +
7.162 + A bug was fixed in the API routine glp_warm_up (dual
7.163 + feasibility test was incorrect in maximization case). Thanks to
7.164 + Uday Venkatadri <Uday.Venkatadri@dal.ca> for the bug report.
7.165 +
7.166 +GLPK 4.39 (release date: Jul 26, 2009)
7.167 +
7.168 + The following new API routines were added:
7.169 +
7.170 + glp_warm_up "warm up" LP basis
7.171 + glp_set_vertex_name assign (change) vertex name
7.172 + glp_create_v_index create vertex name index
7.173 + glp_find_vertex find vertex by its name
7.174 + glp_delete_v_index delete vertex name index
7.175 + glp_read_asnprob read assignment problem data in DIMACS
7.176 + format
7.177 + glp_write_asnprob write assignment problem data in DIMACS
7.178 + format
7.179 + glp_check_asnprob check correctness of assignment problem
7.180 + data
7.181 + glp_asnprob_lp convert assignment problem to LP
7.182 + glp_asnprob_okalg solve assignment problem with the
7.183 + out-of-kilter algorithm
7.184 + glp_asnprob_hall find bipartite matching of maxumum
7.185 + cardinality with Hall's algorithm
7.186 +
7.187 + Also were added some API routines to read plain data files.
7.188 +
7.189 + The API routines glp_read_lp and glp_write_lp to read/write
7.190 + files in CPLEX LP format were re-implemented. Now glp_write_lp
7.191 + correctly writes double-bounded (ranged) rows by introducing
7.192 + slack variables rather than by duplicating the rows.
7.193 +
7.194 + For description of these new routines see a new edition of the
7.195 + reference manual included in the distribution.
7.196 +
7.197 + The 'xfree(NULL)' bug was fixed in the AMD routines. Thanks to
7.198 + Niels Klitgord <niels@bu.edu> for bug report.
7.199 +
7.200 + The message "Crashing..." was changed to "Constructing initial
7.201 + basis..." due to suggestion by Thomas Kahle <tom111@gmx.de>.
7.202 +
7.203 + Some typos were corrected in glpsol output messages. Thanks to
7.204 + Xypron <xypron.glpk@gmx.de> for patch.
7.205 +
7.206 +GLPK 4.38 (release date: May 02, 2009)
7.207 +
7.208 + API routines glp_read_mps and glp_write_mps were improved.
7.209 +
7.210 + Some improvements were made in the dual simplex routines.
7.211 +
7.212 + Two external software modules AMD and COLAMD were included in
7.213 + the distribution (for more details please see src/amd/README
7.214 + and src/colamd/README). Now they are used in the interior-point
7.215 + solver to reorder the matrix prior to Cholesky factorization.
7.216 +
7.217 + API routine glp_ipt_status may return two new statuses due to
7.218 + changes in the routine glp_interior. For details please see the
7.219 + reference manual included in the distribution.
7.220 +
7.221 + A minor bug was fixed in the graph/network routines. Thanks to
7.222 + Nelson H. F. Beebe <beebe@math.utah.edu> for bug report.
7.223 +
7.224 +GLPK 4.37 (release date: Mar 29, 2009)
7.225 +
7.226 + The 0-1 Feasibility Pump heuristic was included in the GLPK
7.227 + integer optimizer glp_intopt. On API level the heuristic can be
7.228 + enabled by setting the parameter fp_heur in glp_iocp to GLP_ON.
7.229 + This feature is also available in the solver glpsol through
7.230 + command-line option '--fpump'. For more details please see the
7.231 + reference manual included in the distribution.
7.232 +
7.233 + The following new API routines were added:
7.234 +
7.235 + glp_print_sol write basic solution in printable format
7.236 + glp_print_ipt write interior-point solution in printable
7.237 + format
7.238 + glp_print_mip write MIP solution in printable format
7.239 + glp_read_graph read (di)graph from plain text file
7.240 + glp_write_graph write (di)graph to plain text file
7.241 + glp_weak_comp find all weakly connected components
7.242 + glp_strong_comp find all strongly connected components
7.243 +
7.244 + The following API routines are deprecated: lpx_print_sol,
7.245 + lpx_print_ips, lpx_print_mip, lpx_print_prob (the latter is
7.246 + equivalent to glp_write_lp).
7.247 +
7.248 + A bug was fixed in the interior-point solver (glp_interior) to
7.249 + correctly compute dual solution components when the problem is
7.250 + scaled.
7.251 +
7.252 + The files configure.ac and Makefile.am were changed:
7.253 + (a) to allow using autoreconf/autoheader;
7.254 + (b) to allow building the package in a directory other than its
7.255 + source directory.
7.256 + Thanks to Marco Atzeri <marco_atzeri@yahoo.it> for bug report.
7.257 +
7.258 + An example model in the GNU MathProg language was added.
7.259 + Thanks to Larry D'Agostino <Larry.D'Agostino@gmacrescap.com> for
7.260 + contribution.
7.261 +
7.262 +GLPK 4.36 (release date: Feb 06, 2009)
7.263 +
7.264 + The following new API routines were added to the package:
7.265 +
7.266 + glp_mincost_okalg find minimum-cost flow with out-of-kilter
7.267 + algorithm
7.268 + glp_maxflow_ffalg find maximal flow with Ford-Fulkerson
7.269 + algorithm
7.270 +
7.271 + For detailed description of these new routines and related data
7.272 + structures see chapter "Graph and Network API Routines" in a new
7.273 + edition of the reference manual included in the distribution.
7.274 +
7.275 + The following two new command-line options were added to the
7.276 + solver glpsol:
7.277 +
7.278 + --mincost read min-cost flow data in DIMACS format
7.279 + --maxflow read maximum flow data in DIMACS format
7.280 +
7.281 + Duplicate symbols in the header glpk.h were removed to allow
7.282 + using swig.
7.283 + Thanks to Kelly Westbrooks <kellywestbrooks@yahoo.com> and
7.284 + Nigel Galloway <nigel_galloway@operamail.com> for suggestion.
7.285 +
7.286 + A minor defect was fixed in the routine glp_write_lp.
7.287 + Thanks to Sebastien Briais <sbriais@free.fr> for bug report.
7.288 +
7.289 + A minor bug was fixed in the SQL module.
7.290 + Thanks to Xypron <xypron.glpk@gmx.de> for patch.
7.291 +
7.292 + Some new example models in the GNU MathProg modeling language
7.293 + were added. Thanks to Sebastian Nowozin <nowozin@gmail.com> and
7.294 + Nigel Galloway <nigel_galloway@operamail.com> for contribution.
7.295 +
7.296 +GLPK 4.35 (release date: Jan 09, 2009)
7.297 +
7.298 + The following new API routines were added to the package:
7.299 +
7.300 + glp_create_graph create graph
7.301 + glp_set_graph_name assign (change) graph name
7.302 + glp_add_vertices add new vertices to graph
7.303 + glp_add_arc add new arc to graph
7.304 + glp_erase_graph erase graph content
7.305 + glp_delete_graph delete graph
7.306 + glp_read_mincost read minimum cost flow problem data in
7.307 + DIMACS format
7.308 + glp_write_mincost write minimum cost flow problem data in
7.309 + DIMACS format
7.310 + glp_mincost_lp convert minimum cost flow problem to LP
7.311 + glp_netgen Klingman's network problem generator
7.312 + glp_gridgen grid-like network problem generator
7.313 + glp_read_maxflow read maximum flow problem data in DIMACS
7.314 + format
7.315 + glp_write_maxflow write maximum flow problem data in DIMACS
7.316 + format
7.317 + glp_maxflow_lp convert maximum flow problem to LP
7.318 + glp_rmfgen Goldfarb's maximum flow problem generator
7.319 +
7.320 + For detailed description of these new routines and related data
7.321 + structures see chapter "Graph and Network API Routines" in a new
7.322 + edition of the reference manual included in the distribution.
7.323 +
7.324 + A minor change were made in the internal routine xputc. Thanks
7.325 + to Luiz Bettoni <bettoni@cpgei.ct.utfpr.edu.br> for suggestion.
7.326 +
7.327 + A minor bug was fixed in the internal routine mpl_fn_time2str.
7.328 + Thanks to Stefan Vigerske <stefan@vigerske.de> for bug report.
7.329 +
7.330 +GLPK 4.34 (release date: Dec 04, 2008)
7.331 +
7.332 + The GNU MathProg modeling language was supplemented with three
7.333 + new built-in functions:
7.334 +
7.335 + gmtime obtaining current calendar time
7.336 + str2time converting character string to calendar time
7.337 + time2str converting calendar time to character string
7.338 +
7.339 + (Thanks to Xypron <xypron.glpk@gmx.de>.)
7.340 +
7.341 + For detailed description of these functions see Appendix A in
7.342 + the document "Modeling Language GNU MathProg", a new edition of
7.343 + which was included in the distribution.
7.344 +
7.345 + A bug was fixed in the MIP solver. Thanks to Nigel Galloway
7.346 + <nigel_galloway@operamail.com> for bug report.
7.347 +
7.348 + A new makefile was added to build the GLPK DLL with Microsoft
7.349 + Visual Studio Express 2008 for 64-bit Windows. Thanks to Xypron
7.350 + <xypron.glpk@gmx.de> for contribution and testing.
7.351 +
7.352 +GLPK 4.33 (release date: Oct 30, 2008)
7.353 +
7.354 + The following new API routines were added to the package:
7.355 + glp_copy_prob copy problem object content
7.356 + glp_exact solve LP in exact arithmetic
7.357 + (makes lpx_exact deprecated)
7.358 + glp_get_unbnd_ray determine variable causing unboundedness
7.359 + (makes lpx_get_ray_info deprecated)
7.360 + glp_interior solve LP with interior-point method
7.361 + (makes lpx_interior deprecated)
7.362 +
7.363 + The following new API routines for processing models written in
7.364 + the GNU Mathprog language were added to the package:
7.365 + glp_mpl_alloc_wksp allocate the translator workspace
7.366 + glp_mpl_read_model read and translate model section
7.367 + glp_mpl_read_data read and translate data section
7.368 + glp_mpl_generate generate the model
7.369 + glp_mpl_build_prob build LP/MIP instance from the model
7.370 + glp_mpl_postsolve postsolve the model
7.371 + glp_mpl_free_wksp deallocate the translator workspace
7.372 + (These routines make lpx_read_model deprecated.)
7.373 +
7.374 + For description of all these new API routines see the reference
7.375 + manual included in the distribution.
7.376 +
7.377 + A crude implementation of CPLEX-like interface to GLPK API was
7.378 + added to the package. Currently it allows using GLPK as a core
7.379 + LP solver for Concorde, a well known computer code for solving
7.380 + the symmetric TSP. For details see examples/cplex/README.
7.381 +
7.382 + Some bugs were fixed in the SQL table driver. Thanks to Xypron
7.383 + <xypron.glpk@gmx.de>.
7.384 +
7.385 +GLPK 4.32 (release date: Oct 03, 2008)
7.386 +
7.387 + The following new features were included in the MIP solver
7.388 + (the API routine glp_intopt):
7.389 +
7.390 + * MIP presolver
7.391 + * mixed cover cut generator
7.392 + * clique cut generator
7.393 + * Euclidean reduction of the objective value
7.394 +
7.395 + Due to changes the routine glp_intopt may additionally return
7.396 + GLP_ENOPFS, GLP_ENODFS, and GLP_EMIPGAP.
7.397 +
7.398 + The API routines lpx_integer are lpx_intopt are deprecated,
7.399 + since they are completely superseded by glp_intopt.
7.400 +
7.401 + The following new branch-and-cut API routines were added:
7.402 + glp_ios_row_attr determine additional row attributes
7.403 + glp_ios_pool_size determine current size of the cut pool
7.404 + glp_ios_add_row add constraint to the cut pool
7.405 + glp_ios_del_row delete constraint from the cut pool
7.406 + glp_ios_clear_pool delete all constraints from the cut pool
7.407 +
7.408 + For description of these new routines see the reference manual
7.409 + included in the distribution.
7.410 +
7.411 + The stand-alone solver glpsol was changed to allow multiple
7.412 + data files.
7.413 +
7.414 + A new edition of the supplement "Using Data Tables in the GNU
7.415 + MathProg Modeling Language" was included.
7.416 +
7.417 + As usual, some bugs were fixed (in the MathProg translator).
7.418 + Thanks to Xypron <xypron.glpk@gmx.de>.
7.419 +
7.420 +GLPK 4.31 (release date: Sep 02, 2008)
7.421 +
7.422 + The core LP solver based on the dual simplex method was
7.423 + re-implemented and now it provides both phases I and II.
7.424 +
7.425 + The following new API routines were added:
7.426 + glp_scale_prob automatic scaling of problem data
7.427 + glp_std_basis construct standard initial LP basis
7.428 + glp_adv_basis construct advanced initial LP basis
7.429 + glp_cpx_basis construct Bixby's initial LP basis
7.430 +
7.431 + For description of these new routines see the reference manual
7.432 + included in the distribution.
7.433 +
7.434 + The following API routines are deprecated:
7.435 + lpx_scale_prob, lpx_std_basis, lpx_adv_basis, lpx_cpx_basis.
7.436 +
7.437 + Necessary changes were made in memory allocation routines to
7.438 + resolve portability issues for 64-bit platforms.
7.439 +
7.440 + New version of the routine lpx_write_pb to write problem data
7.441 + in OPB (pseudo boolean format) was added to the package. Thanks
7.442 + to Oscar Gustafsson <oscarg@isy.liu.se> for the contribution.
7.443 +
7.444 + Two new makefiles were added to build the package for 32- and
7.445 + 64-bit Windows with Microsoft Visual Studio Express 2008.
7.446 + Thanks to Heinrich Schuchardt <heinrich.schuchardt@gmx.de> (aka
7.447 + Xypron) for the contribution and testing.
7.448 +
7.449 + Two new makefiles were added to build the package with Digital
7.450 + Mars C/C++ 8.50 and Open Watcom C/C++ 1.6 (for 32-bit Windows).
7.451 +
7.452 +GLPK 4.30 (release date: Aug 13, 2008)
7.453 +
7.454 + The core LP solver based on the primal simplex method was
7.455 + re-implemented to allow its further improvements. Currently the
7.456 + new version provides the same features as the old one, however,
7.457 + it is a bit faster and more numerically stable.
7.458 +
7.459 + Some changes were made in the MathProg translator to allow <,
7.460 + <=, >=, and > on comparing symbolic values. Thanks to Heinrich
7.461 + Schuchardt <heinrich.schuchardt@gmx.de> for patches.
7.462 +
7.463 + Internal routine set_d_eps in the exact LP solver was changed
7.464 + to prevent approximation errors in case of integral data.
7.465 + Thanks to Markus Pilz <pilz@cs.uni-bonn.de> for bug report.
7.466 +
7.467 +GLPK 4.29 (release date: Jul 06, 2008)
7.468 +
7.469 + The configure script was changed to disable all optional
7.470 + features by default. For details please see file INSTALL.
7.471 +
7.472 + The following new API routines were added:
7.473 + glp_erase_prob erase problem object content
7.474 + glp_read_mps read problem data in MPS format
7.475 + glp_write_mps write problem data in MPS format
7.476 + glp_read_lp read problem data in CPLEX LP format
7.477 + glp_write_lp write problem data in CPLEX LP format
7.478 +
7.479 + For description of these new routines see the reference manual
7.480 + included in the distribution.
7.481 +
7.482 + The following API routines are deprecated:
7.483 + lpx_read_mps, lpx_read_freemps, lpx_write_mps,
7.484 + lpx_write_freemps, lpx_read_cpxlp, and lpx_write_cpxlp.
7.485 +
7.486 + Two bugs were fixed. Thanks to
7.487 + Anne-Laurence Putz <anne-laurence.putz@eurodecision.com> and
7.488 + Xypron <xypron.glpk@gmx.de> for bug report.
7.489 +
7.490 +GLPK 4.28 (release date: Mar 25, 2008)
7.491 +
7.492 + The iODBC and MySQL table drivers, which allows transmitting
7.493 + data between MathProg model objects and relational databases,
7.494 + were re-implemented to replace a static linking by a dynamic
7.495 + linking to corresponding shared libraries.
7.496 + Many thanks to Heinrich Schuchardt <heinrich.schuchardt@gmx.de>
7.497 + for the contribution, Rafael Laboissiere <rafael@debian.org>
7.498 + for useful advices concerning the shared library support under
7.499 + GNU/Linux, and Vijay Patil <vijay.patil@gmail.com> for testing
7.500 + this feature under Windows XP.
7.501 +
7.502 + A new optional feature was added to the package. This feature
7.503 + is based on the zlib data compression library and allows GLPK
7.504 + API routines and the stand-alone solver to read and write
7.505 + compressed data files performing compression/decompression "on
7.506 + the fly" (compressed data files are recognized by suffix `.gz'
7.507 + in the file name). It may be useful in case of large MPS files
7.508 + to save the disk space (up to ten times).
7.509 +
7.510 + The `configure' script was re-implemented. Now it supports the
7.511 + following specific options:
7.512 +
7.513 + --with-gmp Enable using the GNU MP bignum library
7.514 + --without-gmp Disable using the GNU MP bignum library
7.515 + --with-zlib Enable using the zlib data compression
7.516 + library
7.517 + --without-zlib Disable using the zlib data compression
7.518 + library
7.519 + --enable-dl Enable shared library support (auto check)
7.520 + --enable-dl=ltdl Enable shared library support (GNU)
7.521 + --enable-dl=dlfcn Enable shared library support (POSIX)
7.522 + --disable-dl Disable shared library support
7.523 + --enable-odbc Enable using ODBC table driver
7.524 + --disable-odbc Disable using ODBC table driver
7.525 + --enable-mysql Enable using MySQL table driver
7.526 + --disable-mysql Disable using MySQL table driver
7.527 +
7.528 + For more details please see file INSTALL.
7.529 +
7.530 +GLPK 4.27 (release date: Mar 02, 2008)
7.531 +
7.532 + Three new table drivers were added to the MathProg translator:
7.533 +
7.534 + xBASE built-in table driver, which allows reading and writing
7.535 + data in .dbf format (only C and N fields are supported);
7.536 +
7.537 + MySQL table driver, which provides connection to a MySQL
7.538 + database;
7.539 +
7.540 + iODBC table driver, which provides connection to a database
7.541 + through ODBC.
7.542 +
7.543 + The MySQL and iODBC table drivers were contributed to GLPK by
7.544 + Heinrich Schuchardt <heinrich.schuchardt@gmx.de>.
7.545 +
7.546 + The table driver is a program module which allows transmitting
7.547 + data between MathProg model objects and external data tables.
7.548 +
7.549 + For detailed description of the table statement and table
7.550 + drivers see the document "Using Data Tables in the GNU MathProg
7.551 + Modeling Language" (file doc/tables.txt) included in the
7.552 + distribution. Some examples which demonstrate using MySQL and
7.553 + iODBC table drivers can be found in subdirectory examples/sql.
7.554 +
7.555 +GLPK 4.26 (release date: Feb 17, 2008)
7.556 +
7.557 + The table statement was implemented in the GNU MathProg
7.558 + modeling language. This new feature allows reading data from
7.559 + external tables into model objects such as sets and parameters
7.560 + as well as writing results of computations to external tables.
7.561 +
7.562 + A table is a (unordered) set of records, where each record
7.563 + consists of the same number of fields, and each field is
7.564 + provided with a unique symbolic name called the field name.
7.565 +
7.566 + Currently the GLPK package has the only built-in table driver,
7.567 + which supports tables in the CSV (comma-separated values) file
7.568 + format. This format is very simple and supported by almost all
7.569 + spreadsheets and database management systems.
7.570 +
7.571 + Detailed description of the table statement and CSV format can
7.572 + be found in file doc/tables.txt, included in the distribution.
7.573 +
7.574 +GLPK 4.25 (release date: Dec 19, 2007)
7.575 +
7.576 + A tentative implementation of Gomory's mixed integer cuts was
7.577 + included in the branch-and-cut solver. To enable generating
7.578 + Gomory's cuts the control parameter gmi_cuts passed to the
7.579 + routine glp_intopt should be set to GLP_ON. This feature is
7.580 + also available in the solver glpsol through command-line option
7.581 + '--gomory'. For more details please see the reference manual
7.582 + included in the distribution.
7.583 +
7.584 +GLPK 4.24 (release date: Nov 21, 2007)
7.585 +
7.586 + A tentative implementation of MIR (mixed integer rounding) cuts
7.587 + was included in the MIP solver. To enable generating MIR cuts
7.588 + the control parameter mir_cuts passed to the routine glp_intopt
7.589 + should be set to GLP_ON. This feature is also available in the
7.590 + stand-alone solver glpsol via command-line option '--mir'. For
7.591 + more details please see the reference manual included in the
7.592 + distribution.
7.593 +
7.594 + The implementation is mainly based on the following two papers:
7.595 +
7.596 + 1. H. Marchand and L. A. Wolsey. Aggregation and mixed integer
7.597 + rounding to solve MIPs. CORE discussion paper 9839, CORE,
7.598 + Universite catholique de Louvain, June 1998.
7.599 +
7.600 + 2. G. Andreello, A. Caprara, and M. Fischetti. Embedding cuts
7.601 + in a Branch&Cut framework. Preliminary draft, October 2003.
7.602 +
7.603 + MIR cuts can be generated on any level of the search tree that
7.604 + makes the GLPK MIP solver to be a real branch-and-cut solver.
7.605 +
7.606 + A bug was fixed in the routine lpx_write_cpxlp. If a variable
7.607 + x has upper bound and no lower bound, it should appear in the
7.608 + bounds section as "-inf <= x <= u", not as "x <= u". Thanks to
7.609 + Enric Rodriguez <erodri@lsi.upc.edu> for the bug report.
7.610 +
7.611 +GLPK 4.23 (release date: Oct 28, 2007)
7.612 +
7.613 + The following new API routines were added:
7.614 +
7.615 + glp_read_sol read basic solution from text file
7.616 + glp_write_sol write basic solution to text file
7.617 + glp_read_ipt read interior-point solution from text file
7.618 + glp_write_ipt write interior-point solution to text file
7.619 + glp_read_mip read MIP solution from text file
7.620 + glp_write_mip write MIP solution to text file
7.621 +
7.622 + For description of these routines and corresponding file
7.623 + formats see Chapter "API Routines", Section "Utility routines"
7.624 + in the reference manual included in the distribution.
7.625 +
7.626 + Advanced API routine glp_free_env was added. It may be used by
7.627 + the application program to free all resources allocated by GLPK
7.628 + routines.
7.629 +
7.630 + The following three new command-line options were added to the
7.631 + solver glpsol:
7.632 +
7.633 + --mipgap tol set relative MIP gap tolerance
7.634 + -r filename read solution from filename
7.635 + -w filename write solution to filename
7.636 +
7.637 +GLPK 4.22 (release date: Sep 19, 2007)
7.638 +
7.639 + This is a maintainer release.
7.640 +
7.641 + A bug was fixed in the MIP preprocessor (ios_preprocess_node).
7.642 + Thanks to Roberto Bagnara <bagnara@cs.unipr.it> (Department of
7.643 + Mathematics, University of Parma, Italy) for the bug report.
7.644 +
7.645 + A bug was fixed in the MIP preprocessor (col_implied_bounds),
7.646 + due to which constraint coefficients with small magnitude could
7.647 + lead to wrong implied bounds of structural variables.
7.648 +
7.649 + A similar bug was fixed in the routine reduce_bounds.
7.650 +
7.651 + A bug was fixed in the routines glp_set_mat_row and
7.652 + glp_set_mat_col. (The bug appeared due to incorrect removing
7.653 + zero elements from the row/column lists.)
7.654 +
7.655 + A bug was fixed in the API routines lpx_read_mps and
7.656 + lpx_read_freemps, due to which bounds of type LI specified in
7.657 + BOUNDS section were incorrectly processed.
7.658 +
7.659 + A call to standard function vsprintf was replaced by a call to
7.660 + vsnprintf for security reasons. Many thanks to Peter T. Breuer
7.661 + <ptb@inv.it.uc3m.es> and Rafael Laboissiere <rafael@debian.org>.
7.662 +
7.663 +GLPK 4.21 (release date: Aug 28, 2007)
7.664 +
7.665 + Additional reasons for calling the callback routine used in the
7.666 + MIP solver (glp_intopt) were introduced. Currently the following
7.667 + reasons are supported:
7.668 +
7.669 + * request for subproblem selection
7.670 + * request for preprocessing
7.671 + * request for row generation
7.672 + * request for heuristic solution
7.673 + * request for cut generation
7.674 + * request for branching
7.675 + * better integer solution found
7.676 +
7.677 + A basic preprocessing component used to improve subproblem
7.678 + formulations by tightening bounds of variables was included in
7.679 + the MIP solver. Depending on the control parameter pp_tech
7.680 + passed to the routine glp_intopt the preprocessing can be
7.681 + performed either on the root level or on all levels (default)
7.682 + or can be disabled.
7.683 +
7.684 + Backtracking heuristic used by default in the MIP solver was
7.685 + changed to the "best local bound".
7.686 +
7.687 + For more details see Chapter "Advanced API routines", Section
7.688 + "Branch-and-bound interface routines" in a new edition of the
7.689 + reference manual included in the distribution.
7.690 +
7.691 +GLPK 4.20 (release date: Jul 26, 2007)
7.692 +
7.693 + API routine lpx_integer was replaced by API routine glp_intopt,
7.694 + which provides equivalent functionality and additionally allows
7.695 + the application to control the solution process by means of the
7.696 + user-written callback routine, which is called by the solver at
7.697 + various points of the branch-and-bound algorithm. Besides, the
7.698 + new MIP solver allows generating "lazy" constraints and cutting
7.699 + planes on all levels of the branch-and-bound tree, not only on
7.700 + the root level. The routine lpx_integer is also still available
7.701 + for the backward compatibility.
7.702 +
7.703 + The following new advanced API routines, which may be called
7.704 + from the B&B callback routine, were included in the package:
7.705 +
7.706 + glp_ios_reason determine reason for calling callback
7.707 + routine
7.708 + glp_ios_get_prob access the problem object
7.709 + glp_ios_tree_size determine size of the branch-and-bound tree
7.710 + glp_ios_curr_node determine current active subproblem
7.711 + glp_ios_next_node determine next active subproblem
7.712 + glp_ios_prev_node determine previous active subproblem
7.713 + glp_ios_up_node determine parent subproblem
7.714 + glp_ios_node_level determine subproblem level
7.715 + glp_ios_node_bound determine subproblem local bound
7.716 + glp_ios_mip_gap compute relative MIP gap
7.717 + glp_ios_heur_sol provide solution found by heuristic
7.718 + glp_ios_terminate terminate the solution process
7.719 +
7.720 + For description of these routines see Chapter "Advanced API
7.721 + routines", Section "Branch-and-bound interface routines" in a
7.722 + new edition of the reference manual, which was included in the
7.723 + distribution.
7.724 +
7.725 + Old version of the integer optimization suite (IOS) as well as
7.726 + TSP solver tspsol based on it are no longer supported and were
7.727 + removed from the package.
7.728 +
7.729 + A minor error in the MIP presolver was fixed; thanks to Graham
7.730 + Rockwell <bionomicron@gmail.com> for the bug report.
7.731 +
7.732 +GLPK 4.19 (release date: Jul 05, 2007)
7.733 +
7.734 + The principal change is upgrading to GPLv3.
7.735 +
7.736 + A serious bug in the routine glp_del_cols was fixed; thanks to
7.737 + Cedric[FR] <fox2113@wanadoo.fr> for the bug report. The bug
7.738 + appeared because on deleting non-basic columns the basis header
7.739 + remained valid, however, contained invalid (old) column ordinal
7.740 + numbers.
7.741 +
7.742 + A new advanced API routine glp_mem_limit was added.
7.743 +
7.744 + The case GLP_EBOUND was added to the routine lpx_simplex.
7.745 + Thanks to Cameron Kellough <Cameron.Kellough@sri.com> for the
7.746 + bug report.
7.747 +
7.748 + An API routine lpx_write_pb to write the problem instance in
7.749 + OPB (pseudo boolean) format format was added. Thanks to Oscar
7.750 + Gustafsson <oscarg@isy.liu.se> for the contribution.
7.751 +
7.752 + Two new options --wpb and --wnpb were added to glpsol to write
7.753 + the problem instance in OPB format.
7.754 +
7.755 +GLPK 4.18 (release date: Jun 25, 2007)
7.756 +
7.757 + The following new API routines were added:
7.758 +
7.759 + glp_set_rii set (change) row scale factor
7.760 + glp_set_sjj set (change) column scale factor
7.761 + glp_get_rii retrieve row scale factor
7.762 + glp_get_sjj retrieve column scale factor
7.763 + glp_simplex solve LP problem with the simplex method
7.764 + (this routine replaces lpx_simplex, which is
7.765 + also available for backward compatibility)
7.766 + glp_init_smcp initialize simplex method control params
7.767 + glp_bf_exists check if the basis factorization exists
7.768 + glp_factorize compute the basis factorization
7.769 + glp_bf_updated check if the basis factorization has been
7.770 + updated
7.771 + glp_get_bfcp retrieve basis factorization control params
7.772 + glp_set_bfcp change basis factorization control params
7.773 + glp_get_bhead retrieve the basis header information
7.774 + glp_get_row_bind retrieve row index in the basis header
7.775 + glp_get_col_bind retrieve column index in the basis header
7.776 + glp_ftran perform forward transformation
7.777 + glp_btran perform backward transformation
7.778 +
7.779 + For description of all these routines see a new edition of the
7.780 + reference manual included in the distribution.
7.781 +
7.782 + Type names ulong_t and uldiv_t were changed to glp_ulong and
7.783 + glp_uldiv to avoid conflicts with standard type names on some
7.784 + platforms. Thanks to Boris Wirtz <Boris.Wirtz@uni-oldenburg.de>
7.785 + for the bug report.
7.786 +
7.787 + Some new examples in the MathProg language were added. Thanks
7.788 + to Sebastian Nowozin <nowozin@gmail.com>.
7.789 +
7.790 +GLPK 4.17 (release date: May 26, 2007)
7.791 +
7.792 + API routines glp_set_mat_row, glp_set_mat_col, and glp_load_mat
7.793 + were modified to allow zero constraint coefficients (which are
7.794 + not stored in the constraint matrix). Note that constraint
7.795 + coefficients with duplicate row/column indices are not allowed.
7.796 +
7.797 + Another form of LP basis factorization was implemented in the
7.798 + package. It is based on LU-factorization of an initial basis
7.799 + and Schur complement to reflect changes in the basis. Currently
7.800 + the implementation is incomplete and provides only updating the
7.801 + factorization on replacing a column of the basis matrix. On API
7.802 + level the user can set the control parameter LPX_K_BFTYPE to
7.803 + choose between the folloiwng forms of LP basis factorization to
7.804 + be used in the simplex method routines:
7.805 + 1) LU + Forrest-Tomlin update;
7.806 + 2) LU + Schur complement + Bartels-Golub update;
7.807 + 3) LU + Schur complement + Givens rotation update.
7.808 + The GLPK implementation is similar to LUSOL/LUMOD developed by
7.809 + Michael A. Saunders.
7.810 +
7.811 + The user can choose the form of LP basis factorzation used by
7.812 + the simplex method routines by specifying the folloiwng options
7.813 + of glpsol: --luf, --cbg, --cgr.
7.814 +
7.815 +GLPK 4.16 (release date: May 05, 2007)
7.816 +
7.817 + A number of basic GLPK API routines, which now are in the
7.818 + stable stable, were renamed to be prefixed with 'glp_'. Note
7.819 + that all these routines are available via their old names
7.820 + prefixed with 'lpx_' that keeps the downward compatibility with
7.821 + older versions of the package.
7.822 +
7.823 + Three new GLPK API routines were added to the package:
7.824 + glp_version, glp_term_hook, and glp_mem_usage; for more details
7.825 + see a new edition of the GLPK reference manual included in the
7.826 + distribution. The routine glp_version reports the actual version
7.827 + of the GLPK library and also can be used (along with the header
7.828 + glpk.h) in Autotools specification files to check if the GLPK
7.829 + library has been installed.
7.830 +
7.831 + The header glpk.h was changed to conform to C++ environment.
7.832 +
7.833 +GLPK 4.15 (release date: Feb 18, 2007)
7.834 +
7.835 + Autotools specification files (configure.ac, Makefile.am) were
7.836 + changed to use GNU Libtool. This allows building the static as
7.837 + well as shared GLPK library.
7.838 +
7.839 +GLPK 4.14 (release date: Feb 05, 2007)
7.840 +
7.841 + Now GLPK conforms to ILP32, LLP64, and LP64 programming models
7.842 + (the latter seems to be the ultimate choice regarding 64-bit
7.843 + architectures). Note that GLPK itself is a 32-bit application,
7.844 + and the conformity only means that the package works correctly
7.845 + on all these arenae. Nevertheless, on 64-bit platforms it is
7.846 + possible to use more than 4GB of memory, if necessary.
7.847 +
7.848 +GLPK 4.13 (release date: Nov 13, 2006)
7.849 +
7.850 + A tentative implementation of the "exact" simplex method based
7.851 + on bignum (rational) arithmetic was included in the package.
7.852 +
7.853 + On API level this new feature is available through the routine
7.854 + lpx_exact, which is similar to the routine lpx_simplex.
7.855 +
7.856 + In the solver glpsol this feature is available through two new
7.857 + command-line options: --exact and --xcheck. If the '--exact'
7.858 + option is specified, glpsol solves LP instance using the exact
7.859 + simplex method; in case of MIP it is used to obtain optimal
7.860 + solution of LP relaxation. If the --xcheck option is specified,
7.861 + LP instance (or LP relaxation) is solved using the standard
7.862 + (floating-point) simplex method, however, then glpsol calls the
7.863 + exact simplex routine to make sure that the final LP basis is
7.864 + exactly optimal, and if it is not, to perform some additional
7.865 + simplex iterations in exact arithmetic.
7.866 +
7.867 +GLPK 4.12 (release date: Nov 08, 2006)
7.868 +
7.869 + A tentative implementation of some simplex method routines
7.870 + based on exact (bignum) arithmetic was included in the package.
7.871 + Currently these routines provide computing LU-factorization of
7.872 + the basis matrix and computing components of basic solution.
7.873 +
7.874 + These routines were used to implement a routine, which checks
7.875 + primal and dual feasibility of basic solution exactly, i.e. in
7.876 + rational numbers, without round-off errors. In glpsol this
7.877 + feature is available through the command-line option --xcheck.
7.878 +
7.879 + GLPK has its own low-level routines implementing operations on
7.880 + integer and rational numbers that makes it independent on other
7.881 + software packages. However, to attain a much better performance
7.882 + it is highly recommended to install (before configuring GLPK)
7.883 + the GNU Multiple Precision Arithmetic Library (GMP). Using GMP
7.884 + makes computations 100-200 times faster.
7.885 +
7.886 +GLPK 4.11 (release date: Jul 25, 2006)
7.887 +
7.888 + Three new built-in functions in the modeling language were
7.889 + implemented: card (cardinality of set), length (length of
7.890 + character string), and substr (substring of character string).
7.891 + Another improvement concerns the printf statement which now
7.892 + allows redirecting its output to a specified file. These new
7.893 + features are illustrated in example models crypto.mod and
7.894 + graph.mod included in the distribution. For more details see
7.895 + the document "Modeling Language GNU MathProg".
7.896 +
7.897 + Four batch files (along with corresponding makefiles) were
7.898 + included in the distribution to simplify building GLPK under
7.899 + MS Windows; see them in subdirectory 'w32'.
7.900 +
7.901 +GLPK 4.10 (release date: May 11, 2006)
7.902 +
7.903 + Cutting planes of two new classes were implemented: mixed cover
7.904 + cuts and clique cuts. On API level this feature can be enabled
7.905 + by setting control parameter LPX_K_USECUTS passed to the routine
7.906 + lpx_intopt. In glpsol this feature is available through the
7.907 + command-line options --cover and --clique. For more details see
7.908 + the reference manual.
7.909 +
7.910 + Now the routines lpx_read_mps and lpx_read_freemps support LI
7.911 + bound type. It is similar to LO, however, indicates the column
7.912 + as of integer kind.
7.913 +
7.914 +GLPK 4.9 (release date: Jan 17, 2006)
7.915 +
7.916 + An advanced MIP solver was implemented. It includes:
7.917 +
7.918 + - basic presolving technique (removing free, singleton and
7.919 + redundant rows, improving bounds of columns, removing fixed
7.920 + columns, reducing constraint coefficents);
7.921 +
7.922 + - generating cutting planes to improve LP relaxation (currently
7.923 + only Gomory's mixed integer cuts are implemented);
7.924 +
7.925 + - using the branch-and-bound method to solve resultant MIP;
7.926 +
7.927 + - recovering solution of the original MIP.
7.928 +
7.929 + The solver is available on API level via the routine lpx_intopt
7.930 + (see the reference manual). It is similar to the routine
7.931 + lpx_integer, however, does not require initial solution of LP
7.932 + relaxation.
7.933 +
7.934 + The solver is also available in the command-line utility glpsol
7.935 + via two options: --intopt (only presolving) and --cuts (assumes
7.936 + --intopt plus generating cuts).
7.937 +
7.938 + Note that efficiency of the MIP solver strongly depends on the
7.939 + internal structure of the problem to be solved. For some hard
7.940 + instances it is very efficient, but for other instances it may
7.941 + be significantly worse than the standard branch-and-bound.
7.942 +
7.943 + For some comparative benchmarks see doc/bench1.txt.
7.944 +
7.945 + Well, what else...
7.946 +
7.947 + Three built-in functions were added to MathProg: sin, cos, and
7.948 + atan (the latter allows one or two arguments).
7.949 +
7.950 + Some bugs were fixed.
7.951 +
7.952 + Several new examples in MathProg were included: color.mod
7.953 + (graph coloring problem), tsp.mod (traveling salesman problem),
7.954 + and pbn.mod (paint-by-numbers puzzle).
7.955 +
7.956 +GLPK 4.8 (release date: Jan 12, 2005)
7.957 +
7.958 + Core simplex method and interior-point method routines were
7.959 + re-implemented and now they use a new, "storage-by-rows" sparse
7.960 + matrix format (unlike previous versions where linked lists were
7.961 + used to represent sparse matrices). For details see ChangeLog.
7.962 +
7.963 + Also a minor bug was fixed in API routine lpx_read_cpxlp.
7.964 +
7.965 +GLPK 4.7 (release date: Aug 23, 2004)
7.966 +
7.967 + Now GLPK supports free MPS format. Two new API routines
7.968 + lpx_read_freemps (to read problem data in free MPS format) and
7.969 + lpx_write_freemps (to write problem data in free MPS format)
7.970 + were added. This feature is also available in the solver glpsol
7.971 + via new command-line options --freemps and --wfreemps. For more
7.972 + details see the GLPK reference manual.
7.973 +
7.974 + API routines lpx_read_cpxlp and lpx_write_cpxlp for reading and
7.975 + writing problem data in CPLEX LP format were re-implemented to
7.976 + allow long symbolic names (up to 255 characters).
7.977 +
7.978 + The following three modules were temporarily removed from the
7.979 + GLPK distribution due to licensing problems: DELI (an interface
7.980 + module to Delphi), GLPKMEX (an interface module to Matlab), and
7.981 + JNI (an interface module to Java).
7.982 +
7.983 +GLPK 4.6 (release date: Aug 04, 2004)
7.984 +
7.985 + Three new statements were implemented in the GNU MathProg
7.986 + language: solve, printf, and for. Their detailed description can
7.987 + be found in the GLPK documentation included in the distribution.
7.988 + (See also a sample model, examples/queens.mod, which illustrates
7.989 + using these new statements.)
7.990 +
7.991 + Two new API routines were added to the package: lpx_read_prob
7.992 + and lpx_write_prob. They allow reading/writing problem data in
7.993 + GNU LP low-level text format.
7.994 +
7.995 + Three new command-line options were implemented in the LP/MIP
7.996 + solver glpsol: --glp (to read problem data in GNU LP format),
7.997 + --wglp (to write problem data in GNU LP format), and --name (to
7.998 + change problem name). Now glpsol also supports processing models
7.999 + where the new statements (see above) are used.
7.1000 +
7.1001 + A new version of GLPKMEX, a Matlab MEX interface to GLPK, was
7.1002 + included. For more details see contrib/glpkmex/ChangeLog.
7.1003 +
7.1004 +GLPK 4.5 (release date: Jul 19, 2004)
7.1005 +
7.1006 + The branch-and-bound solver was completely re-implemented.
7.1007 +
7.1008 + Some modifications were made in memory allocation routines that
7.1009 + allows using the package on 64-bit platforms.
7.1010 +
7.1011 + For more details see ChangeLog.
7.1012 +
7.1013 +GLPK 4.4 (release date: Jan 17, 2004)
7.1014 +
7.1015 + All API routines were re-implemented using new data structures.
7.1016 + The new implementation provides the same specifications and
7.1017 + functionality of API routines as the old one, however, it has
7.1018 + some important advantages, in particular:
7.1019 + * linked lists are used everywhere that allows creating and
7.1020 + modifying the problem object as efficiently as possible
7.1021 + * all data stored in the problem object are non-scaled (even if
7.1022 + the internal scaling is used) that prevents distortion of the
7.1023 + original problem data
7.1024 + * solution components obtained by the solver remain available
7.1025 + even if the problem object has been modified
7.1026 + * no solver-specific data are used in the new data structures
7.1027 + that allows attaching any external lp/mip solver using GLPK
7.1028 + API as an uniform interface
7.1029 + Note that some API routines became obsolete being replaced by
7.1030 + new, more convenient routines. These obsolete routines are kept
7.1031 + for backward compatibility, however, they will be removed in
7.1032 + the future. For more details please see ChangeLog and the GLPK
7.1033 + Reference Manual.
7.1034 +
7.1035 + New edition of the GLPK Reference Manual was included in the
7.1036 + distribution.
7.1037 +
7.1038 + GLPKMEX, a Matlab MEX interface to GLPK package, contributed by
7.1039 + Nicolo Giorgetti <giorgetti@dii.unisi.it> was included in the
7.1040 + distribution.
7.1041 +
7.1042 + GLPK FAQ contributed by Harley Mackenzie <hjm@bigpond.com> was
7.1043 + included in the distribution.
7.1044 +
7.1045 +GLPK 4.3 (release date: Dec 12, 2003)
7.1046 +
7.1047 + The bug, due to which the standard math library is not linked
7.1048 + on building the package on some platforms, was fixed.
7.1049 +
7.1050 + The following new built-in functions were added to the MathProg
7.1051 + language: round, trunc, Irand224, Uniform01, Uniform, Normal01,
7.1052 + Normal. For details see the language description.
7.1053 +
7.1054 + The MathProg syntax was changed to allow writing 'subj to' that
7.1055 + means 'subject to'.
7.1056 +
7.1057 + The new api routine lpx_get_ray_info was added. It is intended
7.1058 + to determine which (non-basic) variable causes unboundness. For
7.1059 + details see the reference manual.
7.1060 +
7.1061 + The module glpmps.c was changed to avoid compilation errors on
7.1062 + building the package on Mac OS X.
7.1063 +
7.1064 + Several typos was fixed and some new material was added to the
7.1065 + GLPK documentation.
7.1066 +
7.1067 +GLPK 4.2 (release date: Nov 14, 2003)
7.1068 +
7.1069 + A preliminary implementation of the Integer Optimization Suite
7.1070 + (IOS) was included in the package. The Branch-and-Cut Framework
7.1071 + being completely superseded by IOS was removed from the package.
7.1072 +
7.1073 + New API routine lpx_print_sens_bnds intended for bounds
7.1074 + sensitivity analysis was contributed to GLPK by Brady Hunsaker
7.1075 + <hunsaker@engr.pitt.edu>. This function is also available in
7.1076 + the solver glpsol (via command-line option --bounds).
7.1077 +
7.1078 + An improved version of GLPK JNI (Java Native Interface) was
7.1079 + contributed by Chris Rosebrugh <cpr@pobox.com>.
7.1080 +
7.1081 + GLPK DELI (Delphi Interface) was contributed by Ivo van Baren
7.1082 + <i.van.baren@freeler.nl>.
7.1083 +
7.1084 + Several makefiles were added to allow compiling GLPK on some
7.1085 + non-GNU 32-bit platforms:
7.1086 + * Windows single-threaded static library, Visual C++ 6.0
7.1087 + * Windows multi-threaded dynamic library, Visual C++ 6.0
7.1088 + * Windows single-threaded static library, Borland C++ 5.2
7.1089 + * DOS single-threaded static library, Digital Mars C++ 7.50
7.1090 +
7.1091 + And, of course, some bugs were fixed.
7.1092 +
7.1093 + For more details see ChangeLog.
7.1094 +
7.1095 +GLPK 4.1 (release date: Aug 23, 2003)
7.1096 +
7.1097 + Some improvements were made in the lp/mip solver routines and
7.1098 + several bugs were fixed in the model translator.
7.1099 +
7.1100 + For more details see ChangeLog.
7.1101 +
7.1102 +GLPK 4.0 (release date: May 06, 2003)
7.1103 +
7.1104 + Now GLPK supports the GNU MathProg modeling language, which is
7.1105 + a subset of the AMPL modeling language.
7.1106 +
7.1107 + The document "GLPK: Modeling Language GNU MathProg" included in
7.1108 + the distribution is a complete description of GNU MathProg. (See
7.1109 + the files lang.latex, lang.dvi, and lang.ps in the subdirectory
7.1110 + 'doc'. See also some examples in the subdirectory 'sample'.)
7.1111 +
7.1112 + New version of the solver glpsol, which supports models written
7.1113 + in GNU MathProg, was implemented. (Brief instructions how to use
7.1114 + glpsol can be found in the GNU MathProg documentation.)
7.1115 +
7.1116 + The GLPK/L modeling language is no more supported. The reason is
7.1117 + that GNU MathProg being much more powerful completely supersedes
7.1118 + all features of GLPK/L.
7.1119 +
7.1120 +GLPK 3.3 (release date: Mar 25, 2003)
7.1121 +
7.1122 + LP PRESOLVER
7.1123 + ------------
7.1124 +
7.1125 + Now the routine lpx_simplex (which is a driver to the simplex
7.1126 + method for solving LP) is provided with the built-in LP
7.1127 + presolver, which is a program that transforms the original LP
7.1128 + problem to an equivalent LP problem, which may be easier for
7.1129 + solving with the simplex method than the original one. Once the
7.1130 + transformed LP has been solver, the presolver transforms its
7.1131 + basic solution back to a corresponding basic solution of the
7.1132 + original problem. For details about this feature please see the
7.1133 + GLPK reference manual.
7.1134 +
7.1135 + Currently the LP presolver implements the following features:
7.1136 + * removing empty rows;
7.1137 + * removing empty columns;
7.1138 + * removing free rows;
7.1139 + * removing fixed columns;
7.1140 + * removing row singletons, which have the form of equations;
7.1141 + * removing row singletons, which have the form of inequalities;
7.1142 + * removing column singletons, which are implied slack variables;
7.1143 + * fixing and removing column singletons, which are implied free
7.1144 + variables;
7.1145 + * removing forcing rows that involves fixing and removing the
7.1146 + corresponding columns;
7.1147 + * checking for primal and dual infeasibilities.
7.1148 +
7.1149 + The LP presolver is also used by default in the stand-alone
7.1150 + program glpsol. In order *not* to use it, the option --nopresol
7.1151 + should be specified in the command-line.
7.1152 +
7.1153 + CHANGES IN GLPK/L
7.1154 + -----------------
7.1155 +
7.1156 + The syntax and semantics of the GLPK/L modeling language was
7.1157 + changed to allow declaration of "interval" sets. This means that
7.1158 + now the user can declare a set, for example, as:
7.1159 +
7.1160 + set task = [8:11];
7.1161 +
7.1162 + that is exactly equivalent to the following declaration:
7.1163 +
7.1164 + set task = (task_8, task_9, task_10, task_11);
7.1165 +
7.1166 + For details see the language description.
7.1167 +
7.1168 + JAVA INTERFACE
7.1169 + --------------
7.1170 +
7.1171 + Now GLPK includes the package GLPK JNI (Java Native Interface)
7.1172 + that implements Java binding for GLPK. It allows Java programs
7.1173 + to utilize GLPK in solving LP and MIP problems. For details see
7.1174 + a brief user's guide in the subdirectory contrib/java-binding.
7.1175 + This package was developed and programmed by Yuri Victorovich
7.1176 + <yuri@gjt.org>, who contributed it to GLPK.
7.1177 +
7.1178 +GLPK 3.2.4 (release date: Feb 18, 2003)
7.1179 +
7.1180 + This is a bug-fix release. For details see ChangeLog.
7.1181 +
7.1182 +GLPK 3.2.3 (release date: Nov 11, 2002)
7.1183 +
7.1184 + A new implementation of the api routine lpx_integer which now
7.1185 + is based on the b&b driver (which is based on the implicit
7.1186 + enumeration suite) was included in the package. This new
7.1187 + implementation has exactly the same functionality as the old
7.1188 + version, so all changes are transparent to the api user.
7.1189 +
7.1190 + Four new api routines were included in the package:
7.1191 + lpx_check_kkt checks Karush-Kuhn-Tucker optmality conditions;
7.1192 + lpx_read_bas reads predifined basis in MPS format;
7.1193 + lpx_write_bas writes current basis in MPS format;
7.1194 + lpx_write_lpt writes problem data in CPLEX LP format.
7.1195 +
7.1196 + Also other minor improvements were made (for details see the
7.1197 + file 'ChangeLog').
7.1198 +
7.1199 +GLPK 3.2.2 (release date: Oct 14, 2002)
7.1200 +
7.1201 + The api routine lpx_read_lpt was included in the package. It
7.1202 + is similar to the routine lpx_read_mps and intended to read
7.1203 + LP/MIP data prepared in CPLEX LP format. Description of this
7.1204 + format is given in the GLPK reference manual, a new edition of
7.1205 + which was also included in the distribution (see the files
7.1206 + 'refman.latex', 'refman.dvi', 'refman.ps' in the subdirectory
7.1207 + 'doc'). In order to use data files in CPLEX LP format with the
7.1208 + solver glpsol the option '--lpt' should be specified in the
7.1209 + command line.
7.1210 +
7.1211 + Several bugs were fixed and some minor improvements were made
7.1212 + (for details see the file 'ChangeLog').
7.1213 +
7.1214 +GLPK 3.2.1 (release date: Aug 12, 2002)
7.1215 +
7.1216 + Now GLPK includes a preliminary implementation of the
7.1217 + branch-and-cut framework, which is a set of data structures and
7.1218 + routines intended for developing branch-and-cut methods for
7.1219 + solving mixed-integer and combinatorial optimization problems.
7.1220 +
7.1221 + Detailed decsription of the branch-and-cut framework is given in
7.1222 + the document "GLPK: A Preliminary Implementation of the
7.1223 + Branch-And-Cut Framework" included in the distribution (see the
7.1224 + file 'brcut.txt' in the subdirectory 'doc').
7.1225 +
7.1226 + In order to illustrate how the GLPK branch-and-cut framework
7.1227 + can be used for solving a particular optimization problem there
7.1228 + is an example included in the package. This is a stand-alone
7.1229 + program, TSPSOL, which is intended for solving to optimality the
7.1230 + symmetric Traveling Salesman Problem (TSP), a classical problem
7.1231 + of the combinatorial optimization (see the file 'tspsol.c' in
7.1232 + the subdirectory 'sample').
7.1233 +
7.1234 +GLPK 3.2 (release date: Jul 15, 2002)
7.1235 +
7.1236 + New edition of the document "GLPK: Reference Manual" was
7.1237 + included (see the files 'refman.latex', 'refman.dvi', and
7.1238 + 'refman.ps' in the subdirectory 'doc').
7.1239 +
7.1240 + New edition of the document "GLPK: Modeling Language GLPK/L" was
7.1241 + included (see the files 'lang.latex', 'lang.dvi', and 'lang.ps'
7.1242 + in the subdirectory 'doc').
7.1243 +
7.1244 + The following new API routines were added to the package:
7.1245 +
7.1246 + lpx_transform_row (transform explicitly specified row);
7.1247 + lpx_transform_col (transform explicitly specified column);
7.1248 + lpx_prim_ratio_test (perform primal ratio test);
7.1249 + lpx_dual_ratio_test (perform dual ratio test);
7.1250 + lpx_interior (solve LP problem using interior point method);
7.1251 + lpx_get_ips_stat (query status of interior point solution);
7.1252 + lpx_get_ips_row (obtain row interior point solution);
7.1253 + lpx_get_ips_col (obtain column interior point solution);
7.1254 + lpx_get_ips_obj (obtain interior point value of obj.func.);
7.1255 + lpx_read_lpm (read LP/MIP model written in GLPK/L);
7.1256 + lpx_write_mps (write problem data using MPS format);
7.1257 + lpx_print_ips (print interior point solution).
7.1258 +
7.1259 + Detailed description of all these new API routines are given in
7.1260 + the new edition of the reference manual.
7.1261 +
7.1262 + New version of the stand-alone solver glpsol (which is based on
7.1263 + the new API) was implemented.
7.1264 +
7.1265 + So long as the new API (introduced in glpk 3.0) now provides
7.1266 + all the functions, which were provided by the old API, the old
7.1267 + API routines were removed from the package at all.
7.1268 +
7.1269 +GLPK 3.1 (release date: May 27, 2002)
7.1270 +
7.1271 + A preliminary implementation of new API routines was completed
7.1272 + and included in the package.
7.1273 +
7.1274 + These new API routines provide much more flexible interaction
7.1275 + between the application program, LP/MIP problem instances, and
7.1276 + solver routines. Based on completely changed data structures
7.1277 + they are, however, similar to the API routines and provide the
7.1278 + same functionality. Please note that three routines, namely,
7.1279 + solving LPs using interior point method, reading model written
7.1280 + in the GLPK/L modeling language, and writing problem data in
7.1281 + the MPS format, are not implemented in the new API, however,
7.1282 + these routines are planned to be implemented in the next version
7.1283 + of the package.
7.1284 +
7.1285 + A description of the new API routines is given in the document
7.1286 + "GLPK Reference Manual", a draft edition of which is included
7.1287 + in the package (see the files 'refman.latex', 'refman.dvi', and
7.1288 + 'refman.ps' in the subdirectory 'doc').
7.1289 +
7.1290 + Although the old API routines are kept in the package, they are
7.1291 + no longer supported and will be removed in the future.
7.1292 +
7.1293 +GLPK 3.0.8 (release date: May 13, 2002)
7.1294 +
7.1295 + A preliminary implementation of new API routines was included
7.1296 + in the package. These new API routines are intended to provide
7.1297 + much more flexible interaction between the application program,
7.1298 + LP/MIP problem and solver routines. See the document "New GLPK
7.1299 + API Routines" (the file 'newapi.txt' in the subdirectory 'doc')
7.1300 + also included in the package.
7.1301 +
7.1302 + The api routines glp_simplex2, glp_call_ipm1, glp_call_bbm1 were
7.1303 + renamed, respectively, to glp_simplex, glp_interior, glp_integer
7.1304 + in order to reflect changes in implementation. The api routines
7.1305 + glp_call_rsm1, glp_simplex1, glp_pivot_in, glp_pivout_out were
7.1306 + removed from the package since they are completely supreseded by
7.1307 + the new API routines (however, these routines still can be found
7.1308 + in the subdirectory 'oldsrc'). Please consult a new edition of
7.1309 + the document "GLPK User's Guide" about all these changes in the
7.1310 + existing api routines.
7.1311 +
7.1312 + The document "GLPK Library Reference" was removed from the
7.1313 + package (into the subdirectory 'oldsrc') since it describes the
7.1314 + obsolete library routines, most of which are no longer used.
7.1315 +
7.1316 +GLPK 3.0.7 (release date: Apr 22, 2002)
7.1317 +
7.1318 + A new, more efficient implementation of the primal/dual simplex
7.1319 + method was included in the package. Due to some improvements the
7.1320 + simplex-based solver allows solving many LP problems faster and
7.1321 + provides more reliable results. Note that the new implementation
7.1322 + is currently incomplete and available only via the api routine
7.1323 + glp_simplex2.
7.1324 +
7.1325 + All the changes are transparent on API level.
7.1326 +
7.1327 +GLPK 3.0.6 (release date: Mar 28, 2002)
7.1328 +
7.1329 + New version of LU-factorization and basis maintenance routines
7.1330 + (based on Forrest-Tomlin updating technique) was implemented.
7.1331 + Since these new routines functionally supersede some routines
7.1332 + (which implement other forms of the basis matrix) and make them
7.1333 + obsolete, the latter were removed from the package (they still
7.1334 + can be found in the subdirectory 'oldsrc').
7.1335 +
7.1336 + All the changes are transparent on API level.
7.1337 +
7.1338 +GLPK 3.0.5 (release date: Jan 29, 2002)
7.1339 +
7.1340 + New edition of the document "GLPK User's Guide" was included in
7.1341 + the distribution. Now it describes all additional API routines,
7.1342 + which were recently added to the package.
7.1343 +
7.1344 + Structure of the package was re-organized in order to make its
7.1345 + maintenance easier (all small files in the subdurectory 'source'
7.1346 + were merged in bigger units). These changes are transparent for
7.1347 + the user.
7.1348 +
7.1349 +GLPK 3.0.4 (release date: Dec 10, 2001)
7.1350 +
7.1351 + A new, more efficient implementation of the two-phase primal
7.1352 + simplex method was included in the package. Due to some new
7.1353 + features (an advanced initial basis, projected steepest edge,
7.1354 + recursive updating values and reduced costs) the new LP solver
7.1355 + is faster and numerically more stable than the old one.
7.1356 +
7.1357 + The new LP solver is available as API routine glp_simplex2 and
7.1358 + has the same purpose as API routine glp_call_rsm1. For detailed
7.1359 + specification see the file 'newapi.txt' in the directory 'doc'.
7.1360 +
7.1361 + Now the new LP solver is also used by default to solve an
7.1362 + initial LP problem in the branch-and-bound routine glp_call_bbm1
7.1363 + instead the routine rsm1_driver. Note that the branch-and-bound
7.1364 + procedure itself is still based on rsm1_driver.
7.1365 +
7.1366 + The new LP solver is also used as default solver in GLPSOL for
7.1367 + solving LP and MIP problems. In order to choose the old solver
7.1368 + the option '--old-sim' can be specified in the command line.
7.1369 +
7.1370 +GLPK 3.0.3 (release date: Oct 03, 2001)
7.1371 +
7.1372 + Some minor changes were made in the simplex method routines in
7.1373 + order to improve numerical stability of the method.
7.1374 +
7.1375 +GLPK 3.0.2 (release date: Sep 24, 2001)
7.1376 +
7.1377 + A new implementation of the basis maintaining routines was
7.1378 + included in the package. These routines, which are based on so
7.1379 + called FHV-factorization (a variety of LU-factorization) of the
7.1380 + basis matrix and Gustavson's data structures, allows performing
7.1381 + the main operations faster at the expense of some worsening
7.1382 + numerical accuracy.
7.1383 +
7.1384 + AFI (Advanced Form of the Inverse), which is the form of the
7.1385 + basis matrix based on FHV-factorization, is available via the
7.1386 + parameter form = 3 (on API level) or via the option --afi (in
7.1387 + GLPSOL solver).
7.1388 +
7.1389 +GLPK 3.0.1 (release date: Aug 01, 2001)
7.1390 +
7.1391 + Old GLPK API routines have been removed from the package.
7.1392 +
7.1393 + New GLPK API routines were added:
7.1394 +
7.1395 + - scaling routines;
7.1396 +
7.1397 + - a routine for writing problem data in MPS format;
7.1398 +
7.1399 + - a comprehensive driver to the simplex method;
7.1400 +
7.1401 + - basis maintaining routines.
7.1402 +
7.1403 + A description of the new API routines is given in the document
7.1404 + "Additional GLPK API Routines". This document is included into
7.1405 + the distribution in plain text format (see the file 'newapi.txt'
7.1406 + in the subdirectory 'doc').
7.1407 +
7.1408 + Now the distribution includes a non-trivial example of using
7.1409 + GLPK as a base LP solver for Concorde, a well known program that
7.1410 + solves Traveling Salesman Problem (TSP). For further details see
7.1411 + comments in the file 'sample/lpglpk30.c'.
7.1412 +
7.1413 +GLPK 3.0 (release date: Jul 19, 2001)
7.1414 +
7.1415 + Now GLPK is provided with new API, which being more flexible
7.1416 + can be used in more complex algorithmic schemes.
7.1417 +
7.1418 + New edition of the document "GLPK User's Guide" is included in
7.1419 + the distribution. Now it completely corresponds to the new GLPK
7.1420 + API routines.
7.1421 +
7.1422 + Old API routines are not removed yet from the package, however
7.1423 + they became obsolete and therefore should not be used. Since now
7.1424 + the header glpk.h corresponds to new API, in order to compile
7.1425 + existing programs that use old GLPK API routines the statement
7.1426 +
7.1427 + #define GLP_OLD_API
7.1428 +
7.1429 + should be inserted before the statement
7.1430 +
7.1431 + #include "glpk.h"
7.1432 +
7.1433 +GLPK 2.4.1 (release date: Jun 14, 2001)
7.1434 +
7.1435 + The document "Modeling language GLPK/L" is included into the
7.1436 + distribution in texinfo format.
7.1437 +
7.1438 + New edition of the document "GLPK User's Guide" is included in
7.1439 + the distribution. Now it describes all additional API routines
7.1440 + which were recently added to the package.
7.1441 +
7.1442 +GLPK 2.4 (release date: May 10, 2001)
7.1443 +
7.1444 + Now GLPK includes an implementation of a preliminary version
7.1445 + of the GLPK/L modeling language. This language is intended for
7.1446 + writing mathematcal programming models. The name GLPK/L is
7.1447 + derived from GNU Linear Programming Kit Language.
7.1448 +
7.1449 + A brief description of the GLPK/L language is given in the
7.1450 + document "GLPK/L Modeling Language: A Brief Description". This
7.1451 + document is included into the distribution in plain text format
7.1452 + (see the file 'language.txt' in the subdirectory 'doc').
7.1453 +
7.1454 + The language processor (which is a program that analyzes model
7.1455 + description written in GLPK/L and translates it to internal data
7.1456 + structures) is available as the GLPK API routine.
7.1457 +
7.1458 + The stand-alone solver GLPSOL now is able: a) to process model
7.1459 + descriptions written in the GLPK/L language; b) to solve pure LP
7.1460 + problems using the interior point method (therefore the program
7.1461 + GLPIPM was removed from the package).
7.1462 +
7.1463 +GLPK 2.3 (release date: Apr 09, 2001)
7.1464 +
7.1465 + New edition of the document "GLPK User's Guide" is included in
7.1466 + the distribution. Now it describes all additional API routines
7.1467 + which were recently added to the package.
7.1468 +
7.1469 + The MIP solver was fully re-programmed in order to improve its
7.1470 + robustness and performance. In particular, a basis recovering
7.1471 + procedure was implemented (this procedure allows switching to
7.1472 + the primal simplex method in case when the dual simplex method
7.1473 + fails).
7.1474 +
7.1475 +GLPK 2.2 (release date: Mar 15, 2001)
7.1476 +
7.1477 + Now GLPK includes a tentative implementation of the
7.1478 + branch-and-bound procedure based on the dual simplex method for
7.1479 + mixed integer linear programming (MIP).
7.1480 +
7.1481 + Complete description of this new feature of the package is given
7.1482 + in the preliminary document "Mixed Integer Linear Programming
7.1483 + Using GLPK Version 2.2 (Supplement to GLPK User's Guide)". This
7.1484 + document is included into the distribution in plain text format
7.1485 + (see the file 'mip.txt' in the subdirectory 'doc').
7.1486 +
7.1487 + The MIP solver (glp_integer) can be used as GLPK API routine in
7.1488 + the same way as the pure LP solver (glp_simplex).
7.1489 +
7.1490 + The stand-alone program 'glpsol' is now able to solve LP as well
7.1491 + as MIP problems.
7.1492 +
7.1493 + Note that the current version of GLPK MIP solver is based on
7.1494 + easiest heuristics for branching and backtrackng. Therefore the
7.1495 + solver is fit mainly for MIP problems which are not very hard
7.1496 + and have few integer variables.
7.1497 +
7.1498 +GLPK 2.1 (release date: Feb 19, 2001)
7.1499 +
7.1500 + The document "GLPK Implementation of the Revised Simplex Method"
7.1501 + is included into the distribution. This document describes most
7.1502 + of routines related to the revised simplex method.
7.1503 +
7.1504 +GLPK 2.0 (release date: Jan 25, 2001)
7.1505 +
7.1506 + Now GLPK includes a tentative implementation of the primal-dual
7.1507 + interior point method for large-scale linear programming.
7.1508 +
7.1509 + The interior point solver can be used as GLPK API routine in the
7.1510 + same manner as the simplex method solver (glp_simplex):
7.1511 +
7.1512 + ret = glp_interior();
7.1513 +
7.1514 + Note that currently the interior point solver implemented in
7.1515 + GLPK doesn't include many important features, in particular:
7.1516 +
7.1517 + * it can't process dense columns; therefore if the problem has
7.1518 + dense columns, the solving will be extremely inefficient;
7.1519 +
7.1520 + * it has no special features against numerical unstability;
7.1521 + some problems may cause premature termination of the solving
7.1522 + when the matrix A*D*A' becomes ill-conditioned;
7.1523 +
7.1524 + * it computes only values of primal (auxiliary and structural)
7.1525 + variables and doesn't compute values of dual variables (i.e.
7.1526 + reduced costs) which are just set to zero;
7.1527 +
7.1528 + * it doesn't identify optimal basis corresponding to the found
7.1529 + interior point solution; all variables in the found solution
7.1530 + are just marked as basic variables.
7.1531 +
7.1532 + GLPK also includes a stand-alone program 'glpipm' which is a
7.1533 + demo based on the interior point method. It may be used in the
7.1534 + same way as the program 'glpsol' that is based on the simplex
7.1535 + method.
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/README Mon Dec 06 13:09:21 2010 +0100
8.3 @@ -0,0 +1,39 @@
8.4 + Olga K. gewidmet
8.5 +
8.6 +GLPK (GNU Linear Programming Kit) Version 4.45
8.7 +
8.8 +Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
8.9 +2009, 2010 Andrew Makhorin, Department for Applied Informatics,
8.10 +Moscow Aviation Institute, Moscow, Russia. All rights reserved.
8.11 +E-mail: <mao@gnu.org>.
8.12 +
8.13 +GLPK is part of the GNU Project released under the aegis of GNU.
8.14 +
8.15 +GLPK is free software: you can redistribute it and/or modify it
8.16 +under the terms of the GNU General Public License as published by the
8.17 +Free Software Foundation, either version 3 of the License, or (at your
8.18 +option) any later version.
8.19 +
8.20 +See the file COPYING for the GNU General Public License.
8.21 +
8.22 +See the file INSTALL for compilation and installation instructions.
8.23 +
8.24 +The GLPK package is a set of routines written in ANSI C and organized
8.25 +in the form of a callable library. This package is intended for solving
8.26 +large-scale linear programming (LP), mixed integer linear programming
8.27 +(MIP), and other related problems.
8.28 +
8.29 +The GLPK package includes the following main components:
8.30 +
8.31 +* implementation of the simplex method;
8.32 +* implementation of the exact simplex method based on bignum (rational)
8.33 + arithmetic;
8.34 +* implementation of the primal-dual interior-point method;
8.35 +* implementation of the branch-and-cut method;
8.36 +* application program interface (API);
8.37 +* GNU MathProg modeling language (a subset of AMPL);
8.38 +* GLPSOL, a stand-alone LP/MIP solver.
8.39 +
8.40 +See GLPK webpage <http://www.gnu.org/software/glpk/glpk.html>.
8.41 +
8.42 +Please report bugs to <bug-glpk@gnu.org>.
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/THANKS Mon Dec 06 13:09:21 2010 +0100
9.3 @@ -0,0 +1,183 @@
9.4 +Noli Sicad <nsicad@gmail.com> for testing glpk under Mac OS.
9.5 +
9.6 +Pietro Scionti <pietro.scionti@archinet.it> for report typos found in
9.7 +the reference manual.
9.8 +
9.9 +Noli Sicad <nsicad@gmail.com> for example model in MathProg.
9.10 +
9.11 +Nigel Galloway <nigel_galloway@operamail.com> for example model in
9.12 +MathProg.
9.13 +
9.14 +Xypron <xypron.glpk@gmx.de> for contribution and testing batch scripts
9.15 +to build Glpk with MS Visual Studio 2010.
9.16 +
9.17 +Xypron <xypron.glpk@gmx.de> for improving the SQL table driver.
9.18 +
9.19 +Stefan Vigerske <stefan@math.hu-berlin.de> for bug report.
9.20 +
9.21 +Uday Venkatadri <Uday.Venkatadri@dal.ca> for bug report.
9.22 +
9.23 +Xypron <xypron.glpk@gmx.de> for bug fixing and some improvments in the
9.24 +FPUMP module.
9.25 +
9.26 +Niels Klitgord <niels@bu.edu> for bug report.
9.27 +
9.28 +Thomas Kahle <tom111@gmx.de> for some suggestions.
9.29 +
9.30 +Jonathan Senning <Jonathan.Senning@gordon.edu> for bug report.
9.31 +
9.32 +Xypron <xypron.glpk@gmx.de> for testing GLPK on 64-bit platforms and
9.33 +for maintaining Windows versions of the package.
9.34 +
9.35 +Nelson H. F. Beebe <beebe@math.utah.edu> for bug report.
9.36 +
9.37 +Larry D'Agostino <Larry.D'Agostino@gmacrescap.com> for example model in
9.38 +MathProg.
9.39 +
9.40 +Marco Atzeri <marco_atzeri@yahoo.it> for bug report.
9.41 +
9.42 +Robert Wood <rgwood01@cox.net> for example model in MathProg.
9.43 +
9.44 +Sebastien Briais <sbriais@free.fr> for bug report.
9.45 +
9.46 +Kelly Westbrooks <kellywestbrooks@yahoo.com> for suggestions.
9.47 +
9.48 +Nigel Galloway <nigel_galloway@operamail.com> for example models in
9.49 +MathProg.
9.50 +
9.51 +Xypron <xypron.glpk@gmx.de> for bug patch.
9.52 +
9.53 +Sebastian Nowozin <nowozin@gmail.com> for example models in MathProg.
9.54 +
9.55 +Stefan Vigerske <stefan@vigerske.de> for bug report.
9.56 +
9.57 +Luiz Bettoni <bettoni@cpgei.ct.utfpr.edu.br> for some suggestions.
9.58 +
9.59 +Nigel Galloway <nigel_galloway@operamail.com> for bug report.
9.60 +
9.61 +Peter Ingerfeld <peter.ingerfeld@mops-optimizer.com> for bug report.
9.62 +
9.63 +Heinrich Schuchardt <heinrich.schuchardt@gmx.de> for contribution of
9.64 +makefiles and testing the package under 64-bit Windows.
9.65 +
9.66 +Oscar Gustafsson <oscarg@isy.liu.se> for contribution of a new version
9.67 +of the routine to write data in OPB (pseudo boolean) format.
9.68 +
9.69 +Heinrich Schuchardt <heinrich.schuchardt@gmx.de> for some patches for
9.70 +the MathProg translator.
9.71 +
9.72 +Markus Pilz <pilz@cs.uni-bonn.de> for bug report.
9.73 +
9.74 +Anne-Laurence Putz <anne-laurence.putz@eurodecision.com> for bug
9.75 +report.
9.76 +
9.77 +Robbie Morrison <robbie@actrix.co.nz> for correcting the glpk manual.
9.78 +
9.79 +Axel Simon <Axel.Simon@ens.fr> for bug report.
9.80 +
9.81 +Vijay Patil <vijay.patil@gmail.com> for testing the package under
9.82 +Windows XP.
9.83 +
9.84 +Heinrich Schuchardt <heinrich.schuchardt@gmx.de> for contribution of
9.85 +two MathProg table drivers for iODBC and MySQL.
9.86 +
9.87 +Rafael Laboissiere <rafael@debian.org> for useful advices concerning
9.88 +shared library support under GNU/Linux.
9.89 +
9.90 +Nigel Galloway <Nigel_Galloway@operamail.com> for an example program
9.91 +in C#.
9.92 +
9.93 +Enric Rodriguez <erodri@lsi.upc.edu> for bug report.
9.94 +
9.95 +Nigel Galloway <Nigel_Galloway@operamail.com> for an example MathProg
9.96 +model.
9.97 +
9.98 +Roberto Bagnara <bagnara@cs.unipr.it> (Department of Mathematics,
9.99 +University of Parma, Italy) for bug report.
9.100 +
9.101 +Peter T. Breuer <ptb@inv.it.uc3m.es> for bug report.
9.102 +
9.103 +Graham Rockwell <bionomicron@gmail.com> for bug report.
9.104 +
9.105 +Cedric[FR] <fox2113@wanadoo.fr> for bug report.
9.106 +
9.107 +Cameron Kellough <Cameron.Kellough@sri.com> for bug report.
9.108 +
9.109 +Oscar Gustafsson <oscarg@isy.liu.se> for contribution of a routine to
9.110 +write data in OPB (pseudo boolean) format.
9.111 +
9.112 +Boris Wirtz <Boris.Wirtz@uni-oldenburg.de> for bug report.
9.113 +
9.114 +Sebastian Nowozin <nowozin@gmail.com> for three example MathProg
9.115 +models.
9.116 +
9.117 +Rafael Laboissiere <rafael@debian.org> for useful advices concerning
9.118 +shared library support.
9.119 +
9.120 +Dr. Harley Mackenzie <hjm@hardsoftware.com> for two example MathProg
9.121 +models (curve fitting problem).
9.122 +
9.123 +Minh Ha Duong <haduong@centre-cired.fr> for fixing doc typos.
9.124 +
9.125 +Brady Hunsaker <hunsaker@engr.pitt.edu> for some suggestions concerning
9.126 +MIP routines.
9.127 +
9.128 +Karel Zimmermann <kzimm@diamant.jouy.inra.fr> for bug report.
9.129 +
9.130 +Christophe Caron <caron@diamant.jouy.inra.fr> for bug report.
9.131 +
9.132 +Nicolo Giorgetti <giorgetti@dii.unisi.it> for contribution of GLPKMEX,
9.133 +a Matlab MEX interface.
9.134 +
9.135 +Harley Mackenzie <hjm@bigpond.com> for contribution of GLPK FAQ.
9.136 +
9.137 +Andre Girard <andre@inrs-emt.uquebec.ca> for bug report.
9.138 +
9.139 +Morten Welinder <terra@gnu.org> for bug report.
9.140 +
9.141 +Brady Hunsaker <hunsaker@engr.pitt.edu> for contribution of a routine
9.142 +for bounds sensitivity analysis.
9.143 +
9.144 +Chris Rosebrugh <cpr@pobox.com> for contribution of a new version of
9.145 +GLPK JNI (Java Native Interface).
9.146 +
9.147 +Ivo van Baren <i.van.baren@freeler.nl> for contribution of GLPK DELI
9.148 +(Delphi Interface).
9.149 +
9.150 +Andrew Hamilton-Wright <andrewhw@ieee.org> for bug report.
9.151 +
9.152 +Jiri Spitz <jiri.spitz@telecom.cz> for bug report.
9.153 +
9.154 +Giles Thompson <gwpt1@cus.cam.ac.uk> for bug report.
9.155 +
9.156 +Sebastien de Menten <sdementen@hotmail.com> for bug report.
9.157 +
9.158 +Kendall Demaree <kendal.demaree@verizon.net> for bug report.
9.159 +
9.160 +Bernhard Schmidt <schmidt@math.uni-augsburg.de> for bug report.
9.161 +
9.162 +Yuri Victorovich <yuri@gjt.org> for contribution of GLPK Java binding.
9.163 +
9.164 +Olivier <odwl@skynet.be> for bug report.
9.165 +
9.166 +Kjell Eikland <kjell.eikland@broadpark.no> for bug report.
9.167 +
9.168 +Ivan Luzzi <iluzzi@libero.it> for comments concerning CPLEX LP format.
9.169 +
9.170 +Peter Lee <plee@kinggee.com.au> for example LP model and bug report.
9.171 +
9.172 +Morten Welinder <terra@diku.dk> for bug report.
9.173 +
9.174 +Vlahos Kiriakos <Kiriakos.Vlahos@gs.com> for bug report.
9.175 +
9.176 +Flavio Keidi Miyazawa <fkm@ic.unicamp.br> for bug report.
9.177 +
9.178 +Hans Schwengeler <Hans.Schwengeler@unibas.ch> for bug report.
9.179 +
9.180 +Sami Farin <sfarin@ratol.fi> for bug report.
9.181 +
9.182 +Peter A. Huegler <phuegler@bsco.com> for bug report.
9.183 +
9.184 +Alexandre Oliva <oliva@lsd.ic.unicamp.br> for bug report.
9.185 +
9.186 +Andrew Hood <ajhood@fl.net.au> for bug report.
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/configure.ac Mon Dec 06 13:09:21 2010 +0100
10.3 @@ -0,0 +1,159 @@
10.4 +dnl Process this file with autoconf to produce a configure script
10.5 +
10.6 +AC_INIT([GLPK], [4.45], [bug-glpk@gnu.org])
10.7 +
10.8 +AC_CONFIG_SRCDIR([include/glpk.h])
10.9 +
10.10 +AC_CONFIG_MACRO_DIR([m4])
10.11 +
10.12 +AM_INIT_AUTOMAKE
10.13 +
10.14 +AC_CONFIG_HEADERS([config.h])
10.15 +
10.16 +AC_ARG_WITH(gmp,
10.17 +AC_HELP_STRING([--with-gmp],
10.18 + [use GNU MP bignum library [[default=no]]]),
10.19 + [case $withval in
10.20 + yes | no) ;;
10.21 + *) AC_MSG_ERROR([invalid value `$withval' for --with-gmp]);;
10.22 + esac],
10.23 + [with_gmp=no])
10.24 +
10.25 +AC_ARG_WITH(zlib,
10.26 +AC_HELP_STRING([--with-zlib],
10.27 + [use zlib data compression library [[default=no]]]),
10.28 + [case $withval in
10.29 + yes | no) ;;
10.30 + *) AC_MSG_ERROR([invalid value `$withval' for --with-zlib]);;
10.31 + esac],
10.32 + [with_zlib=no])
10.33 +
10.34 +AC_ARG_ENABLE(dl,
10.35 +AC_HELP_STRING([--enable-dl],
10.36 + [enable shared library support [[default=no]]]),
10.37 + [case $enableval in
10.38 + yes | ltdl | dlfcn | no) ;;
10.39 + *) AC_MSG_ERROR([invalid value `$enableval' for --enable-dl]);;
10.40 + esac],
10.41 + [enable_dl=no])
10.42 +
10.43 +AC_ARG_ENABLE(odbc,
10.44 +AC_HELP_STRING([--enable-odbc],
10.45 + [enable MathProg ODBC support [[default=no]]]),
10.46 + [case $enableval in
10.47 + yes | unix | no) ;;
10.48 + *) AC_MSG_ERROR([invalid value `$enableval' for --enable-odbc]);;
10.49 + esac],
10.50 + [enable_odbc=no])
10.51 +
10.52 +AC_ARG_ENABLE(mysql,
10.53 +AC_HELP_STRING([--enable-mysql],
10.54 + [enable MathProg MySQL support [[default=no]]]),
10.55 + [case $enableval in
10.56 + yes | no) ;;
10.57 + *) AC_MSG_ERROR([invalid value `$enableval' for --enable-mysql]);;
10.58 + esac],
10.59 + [enable_mysql=no])
10.60 +
10.61 +dnl Disable unnecessary libtool tests
10.62 +define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])
10.63 +define([AC_LIBTOOL_LANG_F77_CONFIG], [:])
10.64 +define([AC_LIBTOOL_LANG_GCJ_CONFIG], [:])
10.65 +
10.66 +dnl Check for programs
10.67 +AC_PROG_CC
10.68 +AC_PROG_INSTALL
10.69 +AC_PROG_LIBTOOL
10.70 +
10.71 +dnl Check for math library
10.72 +AC_CHECK_LIB([m], [exp])
10.73 +
10.74 +dnl Check for <sys/time.h> header
10.75 +AC_CHECK_HEADER([sys/time.h],
10.76 + AC_DEFINE([HAVE_SYS_TIME_H], [1], [N/A]))
10.77 +
10.78 +dnl Check for gettimeofday function
10.79 +AC_CHECK_FUNC([gettimeofday],
10.80 + AC_DEFINE([HAVE_GETTIMEOFDAY], [1], [N/A]))
10.81 +
10.82 +AC_MSG_CHECKING([whether to use GNU MP bignum library])
10.83 +if test "$with_gmp" = "yes"; then
10.84 + AC_MSG_RESULT([yes])
10.85 + AC_DEFINE([HAVE_GMP], [1], [N/A])
10.86 + LIBS="-lgmp $LIBS"
10.87 +else
10.88 + AC_MSG_RESULT([no])
10.89 +fi
10.90 +
10.91 +AC_MSG_CHECKING([whether to use zlib data compression library])
10.92 +if test "$with_zlib" = "yes"; then
10.93 + AC_MSG_RESULT([yes])
10.94 + AC_DEFINE([HAVE_ZLIB], [1], [N/A])
10.95 + LIBS="-lz $LIBS"
10.96 +else
10.97 + AC_MSG_RESULT([no])
10.98 +fi
10.99 +
10.100 +AC_MSG_CHECKING([whether to enable shared library support])
10.101 +if test "$enable_dl" = "yes"; then
10.102 + AC_MSG_RESULT([ltdl])
10.103 + AC_DEFINE([HAVE_LTDL], [1], [N/A])
10.104 + LIBS="-lltdl $LIBS"
10.105 +elif test "$enable_dl" = "ltdl"; then
10.106 + AC_MSG_RESULT([ltdl])
10.107 + AC_DEFINE([HAVE_LTDL], [1], [N/A])
10.108 + LIBS="-lltdl $LIBS"
10.109 +elif test "$enable_dl" = "dlfcn"; then
10.110 + AC_MSG_RESULT([dlfcn])
10.111 + AC_DEFINE([HAVE_DLFCN], [1], [N/A])
10.112 +else
10.113 + AC_MSG_RESULT([no])
10.114 +fi
10.115 +
10.116 +case $host_os in
10.117 + darwin* | macosx*)
10.118 + LIBIODBC="libiodbc.dylib"
10.119 + LIBODBC="libodbc.dylib"
10.120 + LIBMYSQL="libmysqlclient.dylib"
10.121 + ;;
10.122 + *)
10.123 + LIBIODBC="libiodbc.so"
10.124 + LIBODBC="libodbc.so"
10.125 + LIBMYSQL="libmysqlclient.so"
10.126 + ;;
10.127 +esac
10.128 +
10.129 +AC_MSG_CHECKING([whether to enable MathProg ODBC support])
10.130 +if test "$enable_odbc" = "yes"; then
10.131 + if test "$enable_dl" = "no"; then
10.132 + AC_MSG_ERROR([--enable-odbc requires --enable-dl])
10.133 + fi
10.134 + AC_MSG_RESULT([yes])
10.135 + AC_DEFINE_UNQUOTED([ODBC_DLNAME], ["$LIBIODBC"], [N/A])
10.136 +elif test "$enable_odbc" = "unix"; then
10.137 + if test "$enable_dl" = "no"; then
10.138 + AC_MSG_ERROR([--enable-odbc requires --enable-dl])
10.139 + fi
10.140 + AC_MSG_RESULT([unix])
10.141 + AC_DEFINE_UNQUOTED([ODBC_DLNAME], ["$LIBODBC"], [N/A])
10.142 +else
10.143 + AC_MSG_RESULT([no])
10.144 +fi
10.145 +
10.146 +AC_MSG_CHECKING([whether to enable MathProg MySQL support])
10.147 +if test "$enable_mysql" = "yes"; then
10.148 + if test "$enable_dl" = "no"; then
10.149 + AC_MSG_ERROR([--enable-mysql requires --enable-dl])
10.150 + fi
10.151 + AC_MSG_RESULT([yes])
10.152 + CPPFLAGS="-I/usr/include/mysql $CPPFLAGS"
10.153 + AC_DEFINE_UNQUOTED([MYSQL_DLNAME], ["$LIBMYSQL"], [N/A])
10.154 +else
10.155 + AC_MSG_RESULT([no])
10.156 +fi
10.157 +
10.158 +AC_CONFIG_FILES(
10.159 + [include/Makefile src/Makefile examples/Makefile Makefile])
10.160 +AC_OUTPUT
10.161 +
10.162 +dnl eof
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/doc/glpk.tex Mon Dec 06 13:09:21 2010 +0100
11.3 @@ -0,0 +1,128 @@
11.4 +%* glpk.tex *%
11.5 +
11.6 +%***********************************************************************
11.7 +% This code is part of GLPK (GNU Linear Programming Kit).
11.8 +%
11.9 +% Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
11.10 +% 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
11.11 +% Moscow Aviation Institute, Moscow, Russia. All rights reserved.
11.12 +% E-mail: <mao@gnu.org>.
11.13 +%
11.14 +% GLPK is free software: you can redistribute it and/or modify it
11.15 +% under the terms of the GNU General Public License as published by
11.16 +% the Free Software Foundation, either version 3 of the License, or
11.17 +% (at your option) any later version.
11.18 +%
11.19 +% GLPK is distributed in the hope that it will be useful, but WITHOUT
11.20 +% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11.21 +% or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
11.22 +% License for more details.
11.23 +%
11.24 +% You should have received a copy of the GNU General Public License
11.25 +% along with GLPK. If not, see <http://www.gnu.org/licenses/>.
11.26 +%***********************************************************************
11.27 +
11.28 +\documentclass[11pt]{report}
11.29 +\usepackage{amssymb}
11.30 +\usepackage{lscape}
11.31 +\usepackage[dvipdfm,linktocpage,colorlinks,linkcolor=blue,
11.32 +urlcolor=blue]{hyperref}
11.33 +\usepackage[all]{xy}
11.34 +
11.35 +\renewcommand\contentsname{\sf\bfseries Contents}
11.36 +\renewcommand\chaptername{\sf\bfseries Chapter}
11.37 +\renewcommand\appendixname{\sf\bfseries Appendix}
11.38 +
11.39 +\begin{document}
11.40 +
11.41 +\thispagestyle{empty}
11.42 +
11.43 +\begin{center}
11.44 +
11.45 +\vspace*{1in}
11.46 +
11.47 +\begin{huge}
11.48 +\sf\bfseries GNU Linear Programming Kit
11.49 +\end{huge}
11.50 +
11.51 +\vspace{0.5in}
11.52 +
11.53 +\begin{LARGE}
11.54 +\sf Reference Manual
11.55 +\end{LARGE}
11.56 +
11.57 +\vspace{0.5in}
11.58 +
11.59 +\begin{LARGE}
11.60 +\sf for GLPK Version 4.45
11.61 +\end{LARGE}
11.62 +
11.63 +\vspace{0.5in}
11.64 +\begin{Large}
11.65 +\sf (DRAFT, December 2010)
11.66 +\end{Large}
11.67 +\end{center}
11.68 +
11.69 +\newpage
11.70 +
11.71 +\vspace*{1in}
11.72 +
11.73 +\vfill
11.74 +
11.75 +\noindent
11.76 +The GLPK package is part of the GNU Project released under the aegis of
11.77 +GNU.
11.78 +
11.79 +\medskip \noindent
11.80 +Copyright \copyright{} 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
11.81 +2008, 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
11.82 +Moscow Aviation Institute, Moscow, Russia. All rights reserved.
11.83 +
11.84 +\medskip \noindent
11.85 +Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
11.86 +02110-1301, USA.
11.87 +
11.88 +\medskip \noindent
11.89 +Permission is granted to make and distribute verbatim copies of this
11.90 +manual provided the copyright notice and this permission notice are
11.91 +preserved on all copies.
11.92 +
11.93 +\medskip \noindent
11.94 +Permission is granted to copy and distribute modified versions of this
11.95 +manual under the conditions for verbatim copying, provided also that the
11.96 +entire resulting derived work is distributed under the terms of
11.97 +a permission notice identical to this one.
11.98 +
11.99 +\medskip \noindent
11.100 +Permission is granted to copy and distribute translations of this manual
11.101 +into another language, under the above conditions for modified versions.
11.102 +
11.103 +\tableofcontents
11.104 +
11.105 +\include{glpk01}
11.106 +
11.107 +\include{glpk02}
11.108 +
11.109 +\include{glpk03}
11.110 +
11.111 +\include{glpk04}
11.112 +
11.113 +\include{glpk05}
11.114 +
11.115 +\include{glpk06}
11.116 +
11.117 +\appendix
11.118 +
11.119 +\include{glpk07}
11.120 +
11.121 +\include{glpk08}
11.122 +
11.123 +\include{glpk09}
11.124 +
11.125 +\include{glpk10}
11.126 +
11.127 +\include{glpk11}
11.128 +
11.129 +\include{glpk12}
11.130 +
11.131 +\end{document}
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/doc/glpk01.tex Mon Dec 06 13:09:21 2010 +0100
12.3 @@ -0,0 +1,348 @@
12.4 +%* glpk01.tex *%
12.5 +
12.6 +\chapter{Introduction}
12.7 +
12.8 +GLPK (\underline{G}NU \underline{L}inear \underline{P}rogramming
12.9 +\underline{K}it) is a set of routines written in the ANSI C programming
12.10 +language and organized in the form of a callable library. It is intended
12.11 +for solving linear programming (LP), mixed integer programming (MIP),
12.12 +and other related problems.
12.13 +
12.14 +\section{LP problem}
12.15 +\label{seclp}
12.16 +
12.17 +GLPK assumes the following formulation of {\it linear programming (LP)}
12.18 +problem:
12.19 +
12.20 +\medskip
12.21 +
12.22 +\noindent
12.23 +\hspace{.5in} minimize (or maximize)
12.24 +$$z = c_1x_{m+1} + c_2x_{m+2} + \dots + c_nx_{m+n} + c_0 \eqno (1.1)$$
12.25 +\hspace{.5in} subject to linear constraints
12.26 +$$
12.27 +\begin{array}{r@{\:}c@{\:}r@{\:}c@{\:}r@{\:}c@{\:}r}
12.28 +x_1&=&a_{11}x_{m+1}&+&a_{12}x_{m+2}&+ \dots +&a_{1n}x_{m+n} \\
12.29 +x_2&=&a_{21}x_{m+1}&+&a_{22}x_{m+2}&+ \dots +&a_{2n}x_{m+n} \\
12.30 +\multicolumn{7}{c}
12.31 +{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .} \\
12.32 +x_m&=&a_{m1}x_{m+1}&+&a_{m2}x_{m+2}&+ \dots +&a_{mn}x_{m+n} \\
12.33 +\end{array} \eqno (1.2)
12.34 +$$
12.35 +\hspace{.5in} and bounds of variables
12.36 +$$
12.37 +\begin{array}{r@{\:}c@{\:}c@{\:}c@{\:}l}
12.38 +l_1&\leq&x_1&\leq&u_1 \\
12.39 +l_2&\leq&x_2&\leq&u_2 \\
12.40 +\multicolumn{5}{c}{.\ \ .\ \ .\ \ .\ \ .}\\
12.41 +l_{m+n}&\leq&x_{m+n}&\leq&u_{m+n} \\
12.42 +\end{array} \eqno (1.3)
12.43 +$$
12.44 +where: $x_1, x_2, \dots, x_m$ are auxiliary variables;
12.45 +$x_{m+1}, x_{m+2}, \dots, x_{m+n}$ are\linebreak structural variables;
12.46 +$z$ is the objective function;
12.47 +$c_1, c_2, \dots, c_n$ are objective coefficients;
12.48 +$c_0$ is the constant term (``shift'') of the objective function;
12.49 +$a_{11}, a_{12}, \dots, a_{mn}$ are constraint coefficients;
12.50 +$l_1, l_2, \dots, l_{m+n}$ are lower bounds of variables;
12.51 +$u_1, u_2, \dots, u_{m+n}$ are upper bounds of variables.
12.52 +
12.53 +Auxiliary variables are also called {\it rows}, because they correspond
12.54 +to rows of the constraint matrix (i.e. a matrix built of the constraint
12.55 +coefficients). Similarly, structural variables are also called
12.56 +{\it columns}, because they correspond to columns of the constraint
12.57 +matrix.
12.58 +
12.59 +Bounds of variables can be finite as well as infinite. Besides, lower
12.60 +and upper bounds can be equal to each other. Thus, the following types
12.61 +of variables are possible:
12.62 +\begin{center}
12.63 +\begin{tabular}{r@{}c@{}ll}
12.64 +\multicolumn{3}{c}{Bounds of variable} & Type of variable \\
12.65 +\hline
12.66 +$-\infty <$ &$\ x_k\ $& $< +\infty$ & Free (unbounded) variable \\
12.67 +$l_k \leq$ &$\ x_k\ $& $< +\infty$ & Variable with lower bound \\
12.68 +$-\infty <$ &$\ x_k\ $& $\leq u_k$ & Variable with upper bound \\
12.69 +$l_k \leq$ &$\ x_k\ $& $\leq u_k$ & Double-bounded variable \\
12.70 +$l_k =$ &$\ x_k\ $& $= u_k$ & Fixed variable \\
12.71 +\end{tabular}
12.72 +\end{center}
12.73 +\noindent
12.74 +Note that the types of variables shown above are applicable to
12.75 +structural as well as to auxiliary variables.
12.76 +
12.77 +To solve the LP problem (1.1)---(1.3) is to find such values of all
12.78 +structural and auxiliary variables, which:
12.79 +
12.80 +$\bullet$ satisfy to all the linear constraints (1.2), and
12.81 +
12.82 +$\bullet$ are within their bounds (1.3), and
12.83 +
12.84 +$\bullet$ provide the smallest (in case of minimization) or the largest
12.85 +(in case of maximization) value of the objective function (1.1).
12.86 +
12.87 +\section{MIP problem}
12.88 +
12.89 +{\it Mixed integer linear programming (MIP)} problem is LP problem in
12.90 +which some variables are additionally required to be integer.
12.91 +
12.92 +GLPK assumes that MIP problem has the same formulation as ordinary
12.93 +(pure) LP problem (1.1)---(1.3), i.e. includes auxiliary and structural
12.94 +variables, which may have lower and/or upper bounds. However, in case of
12.95 +MIP problem some variables may be required to be integer. This
12.96 +additional constraint means that a value of each {\it integer variable}
12.97 +must be only integer number. (Should note that GLPK allows only
12.98 +structural variables to be of integer kind.)
12.99 +
12.100 +\section{Using the package}
12.101 +
12.102 +\subsection{Brief example}
12.103 +
12.104 +In order to understand what GLPK is from the user's standpoint,
12.105 +consider the following simple LP problem:
12.106 +
12.107 +\medskip
12.108 +
12.109 +\noindent
12.110 +\hspace{.5in} maximize
12.111 +$$z = 10 x_1 + 6 x_2 + 4 x_3$$
12.112 +\hspace{.5in} subject to
12.113 +$$
12.114 +\begin{array}{r@{\:}c@{\:}r@{\:}c@{\:}r@{\:}c@{\:}r}
12.115 +x_1 &+&x_2 &+&x_3 &\leq 100 \\
12.116 +10 x_1 &+& 4 x_2 & +&5 x_3 & \leq 600 \\
12.117 +2 x_1 &+& 2 x_2 & +& 6 x_3 & \leq 300 \\
12.118 +\end{array}
12.119 +$$
12.120 +\hspace{.5in} where all variables are non-negative
12.121 +$$x_1 \geq 0, \ x_2 \geq 0, \ x_3 \geq 0$$
12.122 +
12.123 +At first this LP problem should be transformed to the standard form
12.124 +(1.1)---(1.3). This can be easily done by introducing auxiliary
12.125 +variables, by one for each original inequality constraint. Thus, the
12.126 +problem can be reformulated as follows:
12.127 +
12.128 +\medskip
12.129 +
12.130 +\noindent
12.131 +\hspace{.5in} maximize
12.132 +$$z = 10 x_1 + 6 x_2 + 4 x_3$$
12.133 +\hspace{.5in} subject to
12.134 +$$
12.135 +\begin{array}{r@{\:}c@{\:}r@{\:}c@{\:}r@{\:}c@{\:}r}
12.136 +p& = &x_1 &+&x_2 &+&x_3 \\
12.137 +q& = &10 x_1 &+& 4 x_2 &+& 5 x_3 \\
12.138 +r& = &2 x_1 &+& 2 x_2 &+& 6 x_3 \\
12.139 +\end{array}
12.140 +$$
12.141 +\hspace{.5in} and bounds of variables
12.142 +$$
12.143 +\begin{array}{ccc}
12.144 +\nonumber -\infty < p \leq 100 && 0 \leq x_1 < +\infty \\
12.145 +\nonumber -\infty < q \leq 600 && 0 \leq x_2 < +\infty \\
12.146 +\nonumber -\infty < r \leq 300 && 0 \leq x_3 < +\infty \\
12.147 +\end{array}
12.148 +$$
12.149 +where $p, q, r$ are auxiliary variables (rows), and $x_1, x_2, x_3$ are
12.150 +structural variables (columns).
12.151 +
12.152 +The example C program shown below uses GLPK API routines in order to
12.153 +solve this LP problem.\footnote{If you just need to solve LP or MIP
12.154 +instance, you may write it in MPS or CPLEX LP format and then use the
12.155 +GLPK stand-alone solver to obtain a solution. This is much less
12.156 +time-consuming than programming in C with GLPK API routines.}
12.157 +
12.158 +\newpage
12.159 +
12.160 +\begin{verbatim}
12.161 +/* sample.c */
12.162 +
12.163 +#include <stdio.h>
12.164 +#include <stdlib.h>
12.165 +#include <glpk.h>
12.166 +
12.167 +int main(void)
12.168 +{ glp_prob *lp;
12.169 + int ia[1+1000], ja[1+1000];
12.170 + double ar[1+1000], z, x1, x2, x3;
12.171 +s1: lp = glp_create_prob();
12.172 +s2: glp_set_prob_name(lp, "sample");
12.173 +s3: glp_set_obj_dir(lp, GLP_MAX);
12.174 +s4: glp_add_rows(lp, 3);
12.175 +s5: glp_set_row_name(lp, 1, "p");
12.176 +s6: glp_set_row_bnds(lp, 1, GLP_UP, 0.0, 100.0);
12.177 +s7: glp_set_row_name(lp, 2, "q");
12.178 +s8: glp_set_row_bnds(lp, 2, GLP_UP, 0.0, 600.0);
12.179 +s9: glp_set_row_name(lp, 3, "r");
12.180 +s10: glp_set_row_bnds(lp, 3, GLP_UP, 0.0, 300.0);
12.181 +s11: glp_add_cols(lp, 3);
12.182 +s12: glp_set_col_name(lp, 1, "x1");
12.183 +s13: glp_set_col_bnds(lp, 1, GLP_LO, 0.0, 0.0);
12.184 +s14: glp_set_obj_coef(lp, 1, 10.0);
12.185 +s15: glp_set_col_name(lp, 2, "x2");
12.186 +s16: glp_set_col_bnds(lp, 2, GLP_LO, 0.0, 0.0);
12.187 +s17: glp_set_obj_coef(lp, 2, 6.0);
12.188 +s18: glp_set_col_name(lp, 3, "x3");
12.189 +s19: glp_set_col_bnds(lp, 3, GLP_LO, 0.0, 0.0);
12.190 +s20: glp_set_obj_coef(lp, 3, 4.0);
12.191 +s21: ia[1] = 1, ja[1] = 1, ar[1] = 1.0; /* a[1,1] = 1 */
12.192 +s22: ia[2] = 1, ja[2] = 2, ar[2] = 1.0; /* a[1,2] = 1 */
12.193 +s23: ia[3] = 1, ja[3] = 3, ar[3] = 1.0; /* a[1,3] = 1 */
12.194 +s24: ia[4] = 2, ja[4] = 1, ar[4] = 10.0; /* a[2,1] = 10 */
12.195 +s25: ia[5] = 3, ja[5] = 1, ar[5] = 2.0; /* a[3,1] = 2 */
12.196 +s26: ia[6] = 2, ja[6] = 2, ar[6] = 4.0; /* a[2,2] = 4 */
12.197 +s27: ia[7] = 3, ja[7] = 2, ar[7] = 2.0; /* a[3,2] = 2 */
12.198 +s28: ia[8] = 2, ja[8] = 3, ar[8] = 5.0; /* a[2,3] = 5 */
12.199 +s29: ia[9] = 3, ja[9] = 3, ar[9] = 6.0; /* a[3,3] = 6 */
12.200 +s30: glp_load_matrix(lp, 9, ia, ja, ar);
12.201 +s31: glp_simplex(lp, NULL);
12.202 +s32: z = glp_get_obj_val(lp);
12.203 +s33: x1 = glp_get_col_prim(lp, 1);
12.204 +s34: x2 = glp_get_col_prim(lp, 2);
12.205 +s35: x3 = glp_get_col_prim(lp, 3);
12.206 +s36: printf("\nz = %g; x1 = %g; x2 = %g; x3 = %g\n",
12.207 + z, x1, x2, x3);
12.208 +s37: glp_delete_prob(lp);
12.209 + return 0;
12.210 +}
12.211 +
12.212 +/* eof */
12.213 +\end{verbatim}
12.214 +
12.215 +The statement \verb|s1| creates a problem object. Being created the
12.216 +object is initially empty. The statement \verb|s2| assigns a symbolic
12.217 +name to the problem object.
12.218 +
12.219 +The statement \verb|s3| calls the routine \verb|glp_set_obj_dir| in
12.220 +order to set the optimization direction flag, where \verb|GLP_MAX| means
12.221 +maximization.
12.222 +
12.223 +The statement \verb|s4| adds three rows to the problem object.
12.224 +
12.225 +The statement \verb|s5| assigns the symbolic name `\verb|p|' to the
12.226 +first row, and the statement \verb|s6| sets the type and bounds of the
12.227 +first row, where \verb|GLP_UP| means that the row has an upper bound.
12.228 +The statements \verb|s7|, \verb|s8|, \verb|s9|, \verb|s10| are used in
12.229 +the same way in order to assign the symbolic names `\verb|q|' and
12.230 +`\verb|r|' to the second and third rows and set their types and bounds.
12.231 +
12.232 +The statement \verb|s11| adds three columns to the problem object.
12.233 +
12.234 +The statement \verb|s12| assigns the symbolic name `\verb|x1|' to the
12.235 +first column, the statement \verb|s13| sets the type and bounds of the
12.236 +first column, where \verb|GLP_LO| means that the column has an lower
12.237 +bound, and the statement \verb|s14| sets the objective coefficient for
12.238 +the first column. The statements \verb|s15|---\verb|s20| are used in the
12.239 +same way in order to assign the symbolic names `\verb|x2|' and
12.240 +`\verb|x3|' to the second and third columns and set their types, bounds,
12.241 +and objective coefficients.
12.242 +
12.243 +The statements \verb|s21|---\verb|s29| prepare non-zero elements of the
12.244 +constraint matrix (i.e. constraint coefficients). Row indices of each
12.245 +element are stored in the array \verb|ia|, column indices are stored in
12.246 +the array \verb|ja|, and numerical values of corresponding elements are
12.247 +stored in the array \verb|ar|. Then the statement \verb|s30| calls
12.248 +the routine \verb|glp_load_matrix|, which loads information from these
12.249 +three arrays into the problem object.
12.250 +
12.251 +Now all data have been entered into the problem object, and therefore
12.252 +the statement \verb|s31| calls the routine \verb|glp_simplex|, which is
12.253 +a driver to the simplex method, in order to solve the LP problem. This
12.254 +routine finds an optimal solution and stores all relevant information
12.255 +back into the problem object.
12.256 +
12.257 +The statement \verb|s32| obtains a computed value of the objective
12.258 +function, and the statements \verb|s33|---\verb|s35| obtain computed
12.259 +values of structural variables (columns), which correspond to the
12.260 +optimal basic solution found by the solver.
12.261 +
12.262 +The statement \verb|s36| writes the optimal solution to the standard
12.263 +output. The printout may look like follows:
12.264 +
12.265 +{\footnotesize
12.266 +\begin{verbatim}
12.267 +* 0: objval = 0.000000000e+00 infeas = 0.000000000e+00 (0)
12.268 +* 2: objval = 7.333333333e+02 infeas = 0.000000000e+00 (0)
12.269 +OPTIMAL SOLUTION FOUND
12.270 +
12.271 +z = 733.333; x1 = 33.3333; x2 = 66.6667; x3 = 0
12.272 +\end{verbatim}
12.273 +
12.274 +}
12.275 +
12.276 +Finally, the statement \verb|s37| calls the routine
12.277 +\verb|glp_delete_prob|, which frees all the memory allocated to the
12.278 +problem object.
12.279 +
12.280 +\subsection{Compiling}
12.281 +
12.282 +The GLPK package has the only header file \verb|glpk.h|, which should
12.283 +be available on compiling a C (or C++) program using GLPK API routines.
12.284 +
12.285 +If the header file is installed in the default location
12.286 +\verb|/usr/local/include|, the following typical command may be used to
12.287 +compile, say, the example C program described above with the GNU C
12.288 +compiler:
12.289 +
12.290 +\begin{verbatim}
12.291 + $ gcc -c sample.c
12.292 +\end{verbatim}
12.293 +
12.294 +If \verb|glpk.h| is not in the default location, the corresponding
12.295 +directory containing it should be made known to the C compiler through
12.296 +\verb|-I| option, for example:
12.297 +
12.298 +\begin{verbatim}
12.299 + $ gcc -I/foo/bar/glpk-4.15/include -c sample.c
12.300 +\end{verbatim}
12.301 +
12.302 +In any case the compilation results in an object file \verb|sample.o|.
12.303 +
12.304 +\subsection{Linking}
12.305 +
12.306 +The GLPK library is a single file \verb|libglpk.a|. (On systems which
12.307 +support shared libraries there may be also a shared version of the
12.308 +library \verb|libglpk.so|.)
12.309 +
12.310 +If the library is installed in the default
12.311 +location \verb|/usr/local/lib|, the following typical command may be
12.312 +used to link, say, the example C program described above against with
12.313 +the library:
12.314 +
12.315 +\begin{verbatim}
12.316 + $ gcc sample.o -lglpk -lm
12.317 +\end{verbatim}
12.318 +
12.319 +If the GLPK library is not in the default location, the corresponding
12.320 +directory containing it should be made known to the linker through
12.321 +\verb|-L| option, for example:
12.322 +
12.323 +\begin{verbatim}
12.324 + $ gcc -L/foo/bar/glpk-4.15 sample.o -lglpk -lm
12.325 +\end{verbatim}
12.326 +
12.327 +Depending on configuration of the package linking against with the GLPK
12.328 +library may require the following optional libraries:
12.329 +
12.330 +\bigskip
12.331 +
12.332 +\begin{tabular}{@{}ll}
12.333 +\verb|-lgmp| & the GNU MP bignum library; \\
12.334 +\verb|-lz| & the zlib data compression library; \\
12.335 +\verb|-lltdl| & the GNU ltdl shared support library. \\
12.336 +\end{tabular}
12.337 +
12.338 +\bigskip
12.339 +
12.340 +\noindent
12.341 +in which case corresponding libraries should be also made known to the
12.342 +linker, for example:
12.343 +
12.344 +\begin{verbatim}
12.345 + $ gcc sample.o -lglpk -lz -lltdl -lm
12.346 +\end{verbatim}
12.347 +
12.348 +For more details about configuration options of the GLPK package see
12.349 +Appendix \ref{install}, page \pageref{install}.
12.350 +
12.351 +%* eof *%
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
13.2 +++ b/doc/glpk02.tex Mon Dec 06 13:09:21 2010 +0100
13.3 @@ -0,0 +1,3406 @@
13.4 +%* glpk02.tex *%
13.5 +
13.6 +\chapter{Basic API Routines}
13.7 +
13.8 +This chapter describes GLPK API routines intended for using in
13.9 +application programs.
13.10 +
13.11 +\subsubsection*{Library header}
13.12 +
13.13 +All GLPK API data types and routines are defined in the header file
13.14 +\verb|glpk.h|. It should be included in all source files which use
13.15 +GLPK API, either directly or indirectly through some other header file
13.16 +as follows:
13.17 +
13.18 +\begin{verbatim}
13.19 + #include <glpk.h>
13.20 +\end{verbatim}
13.21 +
13.22 +\subsubsection*{Error handling}
13.23 +
13.24 +If some GLPK API routine detects erroneous or incorrect data passed by
13.25 +the application program, it writes appropriate diagnostic messages to
13.26 +the terminal and then abnormally terminates the application program.
13.27 +In most practical cases this allows to simplify programming by avoiding
13.28 +numerous checks of return codes. Thus, in order to prevent crashing the
13.29 +application program should check all data, which are suspected to be
13.30 +incorrect, before calling GLPK API routines.
13.31 +
13.32 +Should note that this kind of error handling is used only in cases of
13.33 +incorrect data passed by the application program. If, for example, the
13.34 +application program calls some GLPK API routine to read data from an
13.35 +input file and these data are incorrect, the GLPK API routine reports
13.36 +about error in the usual way by means of the return code.
13.37 +
13.38 +\subsubsection*{Thread safety}
13.39 +
13.40 +Currently GLPK API routines are non-reentrant and therefore cannot be
13.41 +used in multi-threaded programs.
13.42 +
13.43 +\subsubsection*{Array indexing}
13.44 +
13.45 +Normally all GLPK API routines start array indexing from 1, not from 0
13.46 +(except the specially stipulated cases). This means, for example, that
13.47 +if some vector $x$ of the length $n$ is passed as an array to some GLPK
13.48 +API routine, the latter expects vector components to be placed in
13.49 +locations \verb|x[1]|, \verb|x[2]|, \dots, \verb|x[n]|, and the location
13.50 +\verb|x[0]| normally is not used.
13.51 +
13.52 +In order to avoid indexing errors it is most convenient and most
13.53 +reliable to declare the array \verb|x| as follows:
13.54 +
13.55 +\begin{verbatim}
13.56 + double x[1+n];
13.57 +\end{verbatim}
13.58 +
13.59 +\noindent
13.60 +or to allocate it as follows:
13.61 +
13.62 +\begin{verbatim}
13.63 + double *x;
13.64 + . . .
13.65 + x = calloc(1+n, sizeof(double));
13.66 +\end{verbatim}
13.67 +
13.68 +\noindent
13.69 +In both cases one extra location \verb|x[0]| is reserved that allows
13.70 +passing the array to GLPK routines in a usual way.
13.71 +
13.72 +\section{Problem object}
13.73 +
13.74 +All GLPK API routines deal with so called {\it problem object}, which
13.75 +is a program object of type \verb|glp_prob| and intended to represent
13.76 +a particular LP or MIP instance.
13.77 +
13.78 +The type \verb|glp_prob| is a data structure declared in the header
13.79 +file \verb|glpk.h| as follows:
13.80 +
13.81 +\begin{verbatim}
13.82 + typedef struct { ... } glp_prob;
13.83 +\end{verbatim}
13.84 +
13.85 +Problem objects (i.e. program objects of the \verb|glp_prob| type) are
13.86 +allocated and managed internally by the GLPK API routines. The
13.87 +application program should never use any members of the \verb|glp_prob|
13.88 +structure directly and should deal only with pointers to these objects
13.89 +(that is, \verb|glp_prob *| values).
13.90 +
13.91 +\pagebreak
13.92 +
13.93 +The problem object consists of five segments, which are:
13.94 +
13.95 +$\bullet$ problem segment,
13.96 +
13.97 +$\bullet$ basis segment,
13.98 +
13.99 +$\bullet$ interior point segment,
13.100 +
13.101 +$\bullet$ MIP segment, and
13.102 +
13.103 +$\bullet$ control parameters and statistics segment.
13.104 +
13.105 +\subsubsection*{Problem segment}
13.106 +
13.107 +The {\it problem segment} contains original LP/MIP data, which
13.108 +corresponds to the problem formulation (1.1)---(1.3) (see Section
13.109 +\ref{seclp}, page \pageref{seclp}). It includes the following
13.110 +components:
13.111 +
13.112 +$\bullet$ rows (auxiliary variables),
13.113 +
13.114 +$\bullet$ columns (structural variables),
13.115 +
13.116 +$\bullet$ objective function, and
13.117 +
13.118 +$\bullet$ constraint matrix.
13.119 +
13.120 +Rows and columns have the same set of the following attributes:
13.121 +
13.122 +$\bullet$ ordinal number,
13.123 +
13.124 +$\bullet$ symbolic name (1 up to 255 arbitrary graphic characters),
13.125 +
13.126 +$\bullet$ type (free, lower bound, upper bound, double bound, fixed),
13.127 +
13.128 +$\bullet$ numerical values of lower and upper bounds,
13.129 +
13.130 +$\bullet$ scale factor.
13.131 +
13.132 +{\it Ordinal numbers} are intended for referencing rows and columns.
13.133 +Row ordinal numbers are integers $1, 2, \dots, m$, and column ordinal
13.134 +numbers are integers $1, 2, \dots, n$, where $m$ and $n$ are,
13.135 +respectively, the current number of rows and columns in the problem
13.136 +object.
13.137 +
13.138 +{\it Symbolic names} are intended for informational purposes. They also
13.139 +can be used for referencing rows and columns.
13.140 +
13.141 +{\it Types and bounds} of rows (auxiliary variables) and columns
13.142 +(structural variables) are explained above (see Section \ref{seclp},
13.143 +page \pageref{seclp}).
13.144 +
13.145 +{\it Scale factors} are used internally for scaling rows and columns of
13.146 +the constraint matrix.
13.147 +
13.148 +Information about the {\it objective function} includes numerical
13.149 +values of objective coefficients and a flag, which defines the
13.150 +optimization direction (i.e. minimization or maximization).
13.151 +
13.152 +The {\it constraint matrix} is a $m \times n$ rectangular matrix built
13.153 +of constraint coefficients $a_{ij}$, which defines the system of linear
13.154 +constraints (1.2) (see Section \ref{seclp}, page \pageref{seclp}). This
13.155 +matrix is stored in the problem object in both row-wise and column-wise
13.156 +sparse formats.
13.157 +
13.158 +Once the problem object has been created, the application program can
13.159 +access and modify any components of the problem segment in arbitrary
13.160 +order.
13.161 +
13.162 +\subsubsection*{Basis segment}
13.163 +
13.164 +The {\it basis segment} of the problem object keeps information related
13.165 +to the current basic solution. It includes:
13.166 +
13.167 +$\bullet$ row and column statuses,
13.168 +
13.169 +$\bullet$ basic solution statuses,
13.170 +
13.171 +$\bullet$ factorization of the current basis matrix, and
13.172 +
13.173 +$\bullet$ basic solution components.
13.174 +
13.175 +The {\it row and column statuses} define which rows and columns are
13.176 +basic and which are non-basic. These statuses may be assigned either by
13.177 +the application program of by some API routines. Note that these
13.178 +statuses are always defined independently on whether the corresponding
13.179 +basis is valid or not.
13.180 +
13.181 +The {\it basic solution statuses} include the {\it primal status} and
13.182 +the {\it dual status}, which are set by the simplex-based solver once
13.183 +the problem has been solved. The primal status shows whether a primal
13.184 +basic solution is feasible, infeasible, or undefined. The dual status
13.185 +shows the same for a dual basic solution.
13.186 +
13.187 +The {\it factorization of the basis matrix} is some factorized form
13.188 +(like LU-factorization) of the current basis matrix (defined by the
13.189 +current row and column statuses). The factorization is used by the
13.190 +simplex-based solver and kept when the solver terminates the search.
13.191 +This feature allows efficiently reoptimizing the problem after some
13.192 +modifications (for example, after changing some bounds or objective
13.193 +coefficients). It also allows performing the post-optimal analysis (for
13.194 +example, computing components of the simplex table, etc.).
13.195 +
13.196 +The {\it basic solution components} include primal and dual values of
13.197 +all auxiliary and structural variables for the most recently obtained
13.198 +basic solution.
13.199 +
13.200 +\subsubsection*{Interior point segment}
13.201 +
13.202 +The {\it interior point segment} is automatically allocated after the
13.203 +problem has been solved using the interior point solver. It contains
13.204 +interior point solution components, which include the solution status,
13.205 +and primal and dual values of all auxiliary and structural variables.
13.206 +
13.207 +\subsubsection*{MIP segment}
13.208 +
13.209 +The {\it MIP segment} is used only for MIP problems. This segment
13.210 +includes:
13.211 +
13.212 +$\bullet$ column kinds,
13.213 +
13.214 +$\bullet$ MIP solution status, and
13.215 +
13.216 +$\bullet$ MIP solution components.
13.217 +
13.218 +The {\it column kinds} define which columns (i.e. structural variables)
13.219 +are integer and which are continuous.
13.220 +
13.221 +The {\it MIP solution status} is set by the MIP solver and shows whether
13.222 +a MIP solution is integer optimal, integer feasible (non-optimal), or
13.223 +undefined.
13.224 +
13.225 +The {\it MIP solution components} are computed by the MIP solver and
13.226 +include primal values of all auxiliary and structural variables for the
13.227 +most recently obtained MIP solution.
13.228 +
13.229 +Note that in case of MIP problem the basis segment corresponds to
13.230 +the optimal solution of LP relaxation, which is also available to the
13.231 +application program.
13.232 +
13.233 +Currently the search tree is not kept in the MIP segment. Therefore if
13.234 +the search has been terminated, it cannot be continued.
13.235 +
13.236 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13.237 +
13.238 +\newpage
13.239 +
13.240 +\section{Problem creating and modifying routines}
13.241 +
13.242 +\subsection{glp\_create\_prob---create problem object}
13.243 +
13.244 +\subsubsection*{Synopsis}
13.245 +
13.246 +\begin{verbatim}
13.247 +glp_prob *glp_create_prob(void);
13.248 +\end{verbatim}
13.249 +
13.250 +\subsubsection*{Description}
13.251 +
13.252 +The routine \verb|glp_create_prob| creates a new problem object, which
13.253 +initially is ``empty'', i.e. has no rows and columns.
13.254 +
13.255 +\subsubsection*{Returns}
13.256 +
13.257 +The routine returns a pointer to the created object, which should be
13.258 +used in any subsequent operations on this object.
13.259 +
13.260 +\subsection{glp\_set\_prob\_name---assign (change) problem name}
13.261 +
13.262 +\subsubsection*{Synopsis}
13.263 +
13.264 +\begin{verbatim}
13.265 +void glp_set_prob_name(glp_prob *lp, const char *name);
13.266 +\end{verbatim}
13.267 +
13.268 +\subsubsection*{Description}
13.269 +
13.270 +The routine \verb|glp_set_prob_name| assigns a given symbolic
13.271 +\verb|name| (1 up to 255 characters) to the specified problem object.
13.272 +
13.273 +If the parameter \verb|name| is \verb|NULL| or empty string, the routine
13.274 +erases an existing symbolic name of the problem object.
13.275 +
13.276 +\subsection{glp\_set\_obj\_name---assign (change) objective function
13.277 +name}
13.278 +
13.279 +\subsubsection*{Synopsis}
13.280 +
13.281 +\begin{verbatim}
13.282 +void glp_set_obj_name(glp_prob *lp, const char *name);
13.283 +\end{verbatim}
13.284 +
13.285 +\subsubsection*{Description}
13.286 +
13.287 +The routine \verb|glp_set_obj_name| assigns a given symbolic
13.288 +\verb|name| (1 up to 255 characters) to the objective function of the
13.289 +specified problem object.
13.290 +
13.291 +If the parameter \verb|name| is \verb|NULL| or empty string, the routine
13.292 +erases an existing symbolic name of the objective function.
13.293 +
13.294 +\subsection{glp\_set\_obj\_dir---set (change) optimization direction\\
13.295 +flag}
13.296 +
13.297 +\subsubsection*{Synopsis}
13.298 +
13.299 +\begin{verbatim}
13.300 +void glp_set_obj_dir(glp_prob *lp, int dir);
13.301 +\end{verbatim}
13.302 +
13.303 +\subsubsection*{Description}
13.304 +
13.305 +The routine \verb|glp_set_obj_dir| sets (changes) the optimization
13.306 +direction flag (i.e. ``sense'' of the objective function) as specified
13.307 +by the parameter \verb|dir|:
13.308 +
13.309 +\begin{tabular}{@{}ll}
13.310 +\verb|GLP_MIN| & minimization; \\
13.311 +\verb|GLP_MAX| & maximization. \\
13.312 +\end{tabular}
13.313 +
13.314 +\noindent
13.315 +(Note that by default the problem is minimization.)
13.316 +
13.317 +\subsection{glp\_add\_rows---add new rows to problem object}
13.318 +
13.319 +\subsubsection*{Synopsis}
13.320 +
13.321 +\begin{verbatim}
13.322 +int glp_add_rows(glp_prob *lp, int nrs);
13.323 +\end{verbatim}
13.324 +
13.325 +\subsubsection*{Description}
13.326 +
13.327 +The routine \verb|glp_add_rows| adds \verb|nrs| rows (constraints) to
13.328 +the specified problem object. New rows are always added to the end of
13.329 +the row list, so the ordinal numbers of existing rows are not changed.
13.330 +
13.331 +Being added each new row is initially free (unbounded) and has empty
13.332 +list of the constraint coefficients.
13.333 +
13.334 +\subsubsection*{Returns}
13.335 +
13.336 +The routine \verb|glp_add_rows| returns the ordinal number of the first
13.337 +new row added to the problem object.
13.338 +
13.339 +\newpage
13.340 +
13.341 +\subsection{glp\_add\_cols---add new columns to problem object}
13.342 +
13.343 +\subsubsection*{Synopsis}
13.344 +
13.345 +\begin{verbatim}
13.346 +int glp_add_cols(glp_prob *lp, int ncs);
13.347 +\end{verbatim}
13.348 +
13.349 +\subsubsection*{Description}
13.350 +
13.351 +The routine \verb|glp_add_cols| adds \verb|ncs| columns (structural
13.352 +variables) to the specified problem object. New columns are always added
13.353 +to the end of the column list, so the ordinal numbers of existing
13.354 +columns are not changed.
13.355 +
13.356 +Being added each new column is initially fixed at zero and has empty
13.357 +list of the constraint coefficients.
13.358 +
13.359 +\subsubsection*{Returns}
13.360 +
13.361 +The routine \verb|glp_add_cols| returns the ordinal number of the first
13.362 +new column added to the problem object.
13.363 +
13.364 +\subsection{glp\_set\_row\_name---assign (change) row name}
13.365 +
13.366 +\subsubsection*{Synopsis}
13.367 +
13.368 +\begin{verbatim}
13.369 +void glp_set_row_name(glp_prob *lp, int i, const char *name);
13.370 +\end{verbatim}
13.371 +
13.372 +\subsubsection*{Description}
13.373 +
13.374 +The routine \verb|glp_set_row_name| assigns a given symbolic
13.375 +\verb|name| (1 up to 255 characters) to \verb|i|-th row (auxiliary
13.376 +variable) of the specified problem object.
13.377 +
13.378 +If the parameter \verb|name| is \verb|NULL| or empty string, the routine
13.379 +erases an existing name of $i$-th row.
13.380 +
13.381 +\subsection{glp\_set\_col\_name---assign (change) column name}
13.382 +
13.383 +\subsubsection*{Synopsis}
13.384 +
13.385 +\begin{verbatim}
13.386 +void glp_set_col_name(glp_prob *lp, int j, const char *name);
13.387 +\end{verbatim}
13.388 +
13.389 +\subsubsection*{Description}
13.390 +
13.391 +The routine \verb|glp_set_col_name| assigns a given symbolic
13.392 +\verb|name| (1 up to 255 characters) to \verb|j|-th column (structural
13.393 +variable) of the specified problem object.
13.394 +
13.395 +If the parameter \verb|name| is \verb|NULL| or empty string, the routine
13.396 +erases an existing name of $j$-th column.
13.397 +
13.398 +\subsection{glp\_set\_row\_bnds---set (change) row bounds}
13.399 +
13.400 +\subsubsection*{Synopsis}
13.401 +
13.402 +\begin{verbatim}
13.403 +void glp_set_row_bnds(glp_prob *lp, int i, int type,
13.404 + double lb, double ub);
13.405 +\end{verbatim}
13.406 +
13.407 +\subsubsection*{Description}
13.408 +
13.409 +The routine \verb|glp_set_row_bnds| sets (changes) the type and bounds
13.410 +of \verb|i|-th row (auxiliary variable) of the specified problem object.
13.411 +
13.412 +The parameters \verb|type|, \verb|lb|, and \verb|ub| specify the type,
13.413 +lower bound, and upper bound, respectively, as follows:
13.414 +
13.415 +\begin{center}
13.416 +\begin{tabular}{cr@{}c@{}ll}
13.417 +Type & \multicolumn{3}{c}{Bounds} & Comment \\
13.418 +\hline
13.419 +\verb|GLP_FR| & $-\infty <$ &$\ x\ $& $< +\infty$
13.420 + & Free (unbounded) variable \\
13.421 +\verb|GLP_LO| & $lb \leq$ &$\ x\ $& $< +\infty$
13.422 + & Variable with lower bound \\
13.423 +\verb|GLP_UP| & $-\infty <$ &$\ x\ $& $\leq ub$
13.424 + & Variable with upper bound \\
13.425 +\verb|GLP_DB| & $lb \leq$ &$\ x\ $& $\leq ub$
13.426 + & Double-bounded variable \\
13.427 +\verb|GLP_FX| & $lb =$ &$\ x\ $& $= ub$
13.428 + & Fixed variable \\
13.429 +\end{tabular}
13.430 +\end{center}
13.431 +
13.432 +\noindent
13.433 +where $x$ is the auxiliary variable associated with $i$-th row.
13.434 +
13.435 +If the row has no lower bound, the parameter \verb|lb| is ignored. If
13.436 +the row has no upper bound, the parameter \verb|ub| is ignored. If the
13.437 +row is an equality constraint (i.e. the corresponding auxiliary variable
13.438 +is of fixed type), only the parameter \verb|lb| is used while the
13.439 +parameter \verb|ub| is ignored.
13.440 +
13.441 +Being added to the problem object each row is initially free, i.e. its
13.442 +type is \verb|GLP_FR|.
13.443 +
13.444 +\newpage
13.445 +
13.446 +\subsection{glp\_set\_col\_bnds---set (change) column bounds}
13.447 +
13.448 +\subsubsection*{Synopsis}
13.449 +
13.450 +\begin{verbatim}
13.451 +void glp_set_col_bnds(glp_prob *lp, int j, int type,
13.452 + double lb, double ub);
13.453 +\end{verbatim}
13.454 +
13.455 +\subsubsection*{Description}
13.456 +
13.457 +The routine \verb|glp_set_col_bnds| sets (changes) the type and bounds
13.458 +of \verb|j|-th column (structural variable) of the specified problem
13.459 +object.
13.460 +
13.461 +The parameters \verb|type|, \verb|lb|, and \verb|ub| specify the type,
13.462 +lower bound, and upper bound, respectively, as follows:
13.463 +
13.464 +\begin{center}
13.465 +\begin{tabular}{cr@{}c@{}ll}
13.466 +Type & \multicolumn{3}{c}{Bounds} & Comment \\
13.467 +\hline
13.468 +\verb|GLP_FR| & $-\infty <$ &$\ x\ $& $< +\infty$
13.469 + & Free (unbounded) variable \\
13.470 +\verb|GLP_LO| & $lb \leq$ &$\ x\ $& $< +\infty$
13.471 + & Variable with lower bound \\
13.472 +\verb|GLP_UP| & $-\infty <$ &$\ x\ $& $\leq ub$
13.473 + & Variable with upper bound \\
13.474 +\verb|GLP_DB| & $lb \leq$ &$\ x\ $& $\leq ub$
13.475 + & Double-bounded variable \\
13.476 +\verb|GLP_FX| & $lb =$ &$\ x\ $& $= ub$
13.477 + & Fixed variable \\
13.478 +\end{tabular}
13.479 +\end{center}
13.480 +
13.481 +\noindent
13.482 +where $x$ is the structural variable associated with $j$-th column.
13.483 +
13.484 +If the column has no lower bound, the parameter \verb|lb| is ignored.
13.485 +If the column has no upper bound, the parameter \verb|ub| is ignored.
13.486 +If the column is of fixed type, only the parameter \verb|lb| is used
13.487 +while the parameter \verb|ub| is ignored.
13.488 +
13.489 +Being added to the problem object each column is initially fixed at
13.490 +zero, i.e. its type is \verb|GLP_FX| and both bounds are 0.
13.491 +
13.492 +\subsection{glp\_set\_obj\_coef---set (change) objective coefficient
13.493 +or constant term}
13.494 +
13.495 +\subsubsection*{Synopsis}
13.496 +
13.497 +\begin{verbatim}
13.498 +void glp_set_obj_coef(glp_prob *lp, int j, double coef);
13.499 +\end{verbatim}
13.500 +
13.501 +\subsubsection*{Description}
13.502 +
13.503 +The routine \verb|glp_set_obj_coef| sets (changes) the objective
13.504 +coefficient at \verb|j|-th column (structural variable). A new value of
13.505 +the objective coefficient is specified by the parameter \verb|coef|.
13.506 +
13.507 +If the parameter \verb|j| is 0, the routine sets (changes) the constant
13.508 +term (``shift'') of the objective function.
13.509 +
13.510 +\subsection{glp\_set\_mat\_row---set (replace) row of the constraint
13.511 +matrix}
13.512 +
13.513 +\subsubsection*{Synopsis}
13.514 +
13.515 +\begin{verbatim}
13.516 +void glp_set_mat_row(glp_prob *lp, int i, int len,
13.517 + const int ind[], const double val[]);
13.518 +\end{verbatim}
13.519 +
13.520 +\subsubsection*{Description}
13.521 +
13.522 +The routine \verb|glp_set_mat_row| stores (replaces) the contents of
13.523 +\verb|i|-th row of the constraint matrix of the specified problem
13.524 +object.
13.525 +
13.526 +Column indices and numerical values of new row elements must be placed
13.527 +in locations \verb|ind[1]|, \dots, \verb|ind[len]| and \verb|val[1]|,
13.528 +\dots, \verb|val[len]|, respectively, where $0 \leq$ \verb|len| $\leq n$
13.529 +is the new length of $i$-th row, $n$ is the current number of columns in
13.530 +the problem object. Elements with identical column indices are not
13.531 +allowed. Zero elements are allowed, but they are not stored in the
13.532 +constraint matrix.
13.533 +
13.534 +If the parameter \verb|len| is 0, the parameters \verb|ind| and/or
13.535 +\verb|val| can be specified as \verb|NULL|.
13.536 +
13.537 +\subsection{glp\_set\_mat\_col---set (replace) column of the
13.538 +constr\-aint matrix}
13.539 +
13.540 +\subsubsection*{Synopsis}
13.541 +
13.542 +\begin{verbatim}
13.543 +void glp_set_mat_col(glp_prob *lp, int j, int len,
13.544 + const int ind[], const double val[]);
13.545 +\end{verbatim}
13.546 +
13.547 +\subsubsection*{Description}
13.548 +
13.549 +The routine \verb|glp_set_mat_col| stores (replaces) the contents of
13.550 +\verb|j|-th column of the constraint matrix of the specified problem
13.551 +object.
13.552 +
13.553 +Row indices and numerical values of new column elements must be placed
13.554 +in locations \verb|ind[1]|, \dots, \verb|ind[len]| and \verb|val[1]|,
13.555 +\dots, \verb|val[len]|, respectively, where $0 \leq$ \verb|len| $\leq m$
13.556 +is the new length of $j$-th column, $m$ is the current number of rows in
13.557 +the problem object. Elements with identical row indices are not allowed.
13.558 +Zero elements are allowed, but they are not stored in the constraint
13.559 +matrix.
13.560 +
13.561 +If the parameter \verb|len| is 0, the parameters \verb|ind| and/or
13.562 +\verb|val| can be specified as \verb|NULL|.
13.563 +
13.564 +\subsection{glp\_load\_matrix---load (replace) the whole constraint
13.565 +matrix}
13.566 +
13.567 +\subsubsection*{Synopsis}
13.568 +
13.569 +\begin{verbatim}
13.570 +void glp_load_matrix(glp_prob *lp, int ne, const int ia[],
13.571 + const int ja[], const double ar[]);
13.572 +\end{verbatim}
13.573 +
13.574 +\subsubsection*{Description}
13.575 +
13.576 +The routine \verb|glp_load_matrix| loads the constraint matrix passed
13.577 +in the arrays \verb|ia|, \verb|ja|, and \verb|ar| into the specified
13.578 +problem object. Before loading the current contents of the constraint
13.579 +matrix is destroyed.
13.580 +
13.581 +Constraint coefficients (elements of the constraint matrix) must be
13.582 +specified as triplets (\verb|ia[k]|, \verb|ja[k]|, \verb|ar[k]|) for
13.583 +$k=1,\dots,ne$, where \verb|ia[k]| is the row index, \verb|ja[k]| is
13.584 +the column index, and \verb|ar[k]| is a numeric value of corresponding
13.585 +constraint coefficient. The parameter \verb|ne| specifies the total
13.586 +number of (non-zero) elements in the matrix to be loaded. Coefficients
13.587 +with identical indices are not allowed. Zero coefficients are allowed,
13.588 +however, they are not stored in the constraint matrix.
13.589 +
13.590 +If the parameter \verb|ne| is 0, the parameters \verb|ia|, \verb|ja|,
13.591 +and/or \verb|ar| can be specified as \verb|NULL|.
13.592 +
13.593 +\subsection{glp\_check\_dup---check for duplicate elements in sparse
13.594 +matrix}
13.595 +
13.596 +\subsubsection*{Synopsis}
13.597 +
13.598 +\begin{verbatim}
13.599 +int glp_check_dup(int m, int n, int ne, const int ia[],
13.600 + const int ja[]);
13.601 +\end{verbatim}
13.602 +
13.603 +\subsubsection*{Description}
13.604 +
13.605 +The routine \verb|glp_check_dup checks| for duplicate elements (that
13.606 +is, elements with identical indices) in a sparse matrix specified in
13.607 +the coordinate format.
13.608 +
13.609 +The parameters $m$ and $n$ specifies, respectively, the number of rows
13.610 +and columns in the matrix, $m\geq 0$, $n\geq 0$.
13.611 +
13.612 +The parameter {\it ne} specifies the number of (structurally) non-zero
13.613 +elements in the matrix, {\it ne} $\geq 0$.
13.614 +
13.615 +Elements of the matrix are specified as doublets $(ia[k],ja[k])$ for
13.616 +$k=1,\dots,ne$, where $ia[k]$ is a row index, $ja[k]$ is a column index.
13.617 +
13.618 +The routine \verb|glp_check_dup| can be used prior to a call to the
13.619 +routine \verb|glp_load_matrix| to check that the constraint matrix to
13.620 +be loaded has no duplicate elements.
13.621 +
13.622 +\subsubsection*{Returns}
13.623 +
13.624 +The routine \verb|glp_check_dup| returns one of the following values:
13.625 +
13.626 +\noindent
13.627 +\begin{tabular}{@{}r@{\ }c@{\ }l@{}}
13.628 +0&---&the matrix has no duplicate elements;\\
13.629 +$-k$&---&indices $ia[k]$ or/and $ja[k]$ are out of range;\\
13.630 +$+k$&---&element $(ia[k],ja[k])$ is duplicate.\\
13.631 +\end{tabular}
13.632 +
13.633 +\subsection{glp\_sort\_matrix---sort elements of the constraint matrix}
13.634 +
13.635 +\subsubsection*{Synopsis}
13.636 +
13.637 +\begin{verbatim}
13.638 +void glp_sort_matrix(glp_prob *P);
13.639 +\end{verbatim}
13.640 +
13.641 +\subsubsection*{Description}
13.642 +
13.643 +The routine \verb|glp_sort_matrix| sorts elements of the constraint
13.644 +matrix rebuilding its row and column linked lists. On exit from the
13.645 +routine the constraint matrix is not changed, however, elements in the
13.646 +row linked lists become ordered by ascending column indices, and the
13.647 +elements in the column linked lists become ordered by ascending row
13.648 +indices.
13.649 +
13.650 +\subsection{glp\_del\_rows---delete rows from problem object}
13.651 +
13.652 +\subsubsection*{Synopsis}
13.653 +
13.654 +\begin{verbatim}
13.655 +void glp_del_rows(glp_prob *lp, int nrs, const int num[]);
13.656 +\end{verbatim}
13.657 +
13.658 +\subsubsection*{Description}
13.659 +
13.660 +The routine \verb|glp_del_rows| deletes rows from the specified problem
13.661 +ob-\linebreak ject. Ordinal numbers of rows to be deleted should be
13.662 +placed in locations \verb|num[1]|, \dots, \verb|num[nrs]|, where
13.663 +${\tt nrs}>0$.
13.664 +
13.665 +Note that deleting rows involves changing ordinal numbers of other
13.666 +rows remaining in the problem object. New ordinal numbers of the
13.667 +remaining rows are assigned under the assumption that the original
13.668 +order of rows is not changed. Let, for example, before deletion there
13.669 +be five rows $a$, $b$, $c$, $d$, $e$ with ordinal numbers 1, 2, 3, 4, 5,
13.670 +and let rows $b$ and $d$ have been deleted. Then after deletion the
13.671 +remaining rows $a$, $c$, $e$ are assigned new oridinal numbers 1, 2, 3.
13.672 +
13.673 +\subsection{glp\_del\_cols---delete columns from problem object}
13.674 +
13.675 +\subsubsection*{Synopsis}
13.676 +
13.677 +\begin{verbatim}
13.678 +void glp_del_cols(glp_prob *lp, int ncs, const int num[]);
13.679 +\end{verbatim}
13.680 +
13.681 +\subsubsection*{Description}
13.682 +
13.683 +The routine \verb|glp_del_cols| deletes columns from the specified
13.684 +problem object. Ordinal numbers of columns to be deleted should be
13.685 +placed in locations \verb|num[1]|, \dots, \verb|num[ncs]|, where
13.686 +${\tt ncs}>0$.
13.687 +
13.688 +Note that deleting columns involves changing ordinal numbers of other
13.689 +columns remaining in the problem object. New ordinal numbers of the
13.690 +remaining columns are assigned under the assumption that the original
13.691 +order of columns is not changed. Let, for example, before deletion there
13.692 +be six columns $p$, $q$, $r$, $s$, $t$, $u$ with ordinal numbers 1, 2,
13.693 +3, 4, 5, 6, and let columns $p$, $q$, $s$ have been deleted. Then after
13.694 +deletion the remaining columns $r$, $t$, $u$ are assigned new ordinal
13.695 +numbers 1, 2, 3.
13.696 +
13.697 +\subsection{glp\_copy\_prob---copy problem object content}
13.698 +
13.699 +\subsubsection*{Synopsis}
13.700 +
13.701 +\begin{verbatim}
13.702 +void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names);
13.703 +\end{verbatim}
13.704 +
13.705 +\subsubsection*{Description}
13.706 +
13.707 +The routine \verb|glp_copy_prob| copies the content of the problem
13.708 +object \verb|prob| to the problem object \verb|dest|.
13.709 +
13.710 +The parameter \verb|names| is a flag. If it is \verb|GLP_ON|,
13.711 +the routine also copies all symbolic names; otherwise, if it is
13.712 +\verb|GLP_OFF|, no symbolic names are copied.
13.713 +
13.714 +\newpage
13.715 +
13.716 +\subsection{glp\_erase\_prob---erase problem object content}
13.717 +
13.718 +\subsubsection*{Synopsis}
13.719 +
13.720 +\begin{verbatim}
13.721 +void glp_erase_prob(glp_prob *lp);
13.722 +\end{verbatim}
13.723 +
13.724 +\subsubsection*{Description}
13.725 +
13.726 +The routine \verb|glp_erase_prob| erases the content of the specified
13.727 +problem object. The effect of this operation is the same as if the
13.728 +problem object would be deleted with the routine \verb|glp_delete_prob|
13.729 +and then created anew with the routine \verb|glp_create_prob|, with the
13.730 +only exception that the handle (pointer) to the problem object remains
13.731 +valid.
13.732 +
13.733 +\subsection{glp\_delete\_prob---delete problem object}
13.734 +
13.735 +\subsubsection*{Synopsis}
13.736 +
13.737 +\begin{verbatim}
13.738 +void glp_delete_prob(glp_prob *lp);
13.739 +\end{verbatim}
13.740 +
13.741 +\subsubsection*{Description}
13.742 +
13.743 +The routine \verb|glp_delete_prob| deletes a problem object, which the
13.744 +parameter \verb|lp| points to, freeing all the memory allocated to this
13.745 +object.
13.746 +
13.747 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13.748 +
13.749 +\newpage
13.750 +
13.751 +\section{Problem retrieving routines}
13.752 +
13.753 +\subsection{glp\_get\_prob\_name---retrieve problem name}
13.754 +
13.755 +\subsubsection*{Synopsis}
13.756 +
13.757 +\begin{verbatim}
13.758 +const char *glp_get_prob_name(glp_prob *lp);
13.759 +\end{verbatim}
13.760 +
13.761 +\subsubsection*{Returns}
13.762 +
13.763 +The routine \verb|glp_get_prob_name| returns a pointer to an internal
13.764 +buffer, which contains symbolic name of the problem. However, if the
13.765 +problem has no assigned name, the routine returns \verb|NULL|.
13.766 +
13.767 +\subsection{glp\_get\_obj\_name---retrieve objective function name}
13.768 +
13.769 +\subsubsection*{Synopsis}
13.770 +
13.771 +\begin{verbatim}
13.772 +const char *glp_get_obj_name(glp_prob *lp);
13.773 +\end{verbatim}
13.774 +
13.775 +\subsubsection*{Returns}
13.776 +
13.777 +The routine \verb|glp_get_obj_name| returns a pointer to an internal
13.778 +buffer, which contains symbolic name assigned to the objective
13.779 +function. However, if the objective function has no assigned name, the
13.780 +routine returns \verb|NULL|.
13.781 +
13.782 +\subsection{glp\_get\_obj\_dir---retrieve optimization direction flag}
13.783 +
13.784 +\subsubsection*{Synopsis}
13.785 +
13.786 +\begin{verbatim}
13.787 +int glp_get_obj_dir(glp_prob *lp);
13.788 +\end{verbatim}
13.789 +
13.790 +\subsubsection*{Returns}
13.791 +
13.792 +The routine \verb|glp_get_obj_dir| returns the optimization direction
13.793 +flag (i.e. ``sense'' of the objective function):
13.794 +
13.795 +\begin{tabular}{@{}ll}
13.796 +\verb|GLP_MIN| & minimization; \\
13.797 +\verb|GLP_MAX| & maximization. \\
13.798 +\end{tabular}
13.799 +
13.800 +\pagebreak
13.801 +
13.802 +\subsection{glp\_get\_num\_rows---retrieve number of rows}
13.803 +
13.804 +\subsubsection*{Synopsis}
13.805 +
13.806 +\begin{verbatim}
13.807 +int glp_get_num_rows(glp_prob *lp);
13.808 +\end{verbatim}
13.809 +
13.810 +\subsubsection*{Returns}
13.811 +
13.812 +The routine \verb|glp_get_num_rows| returns the current number of rows
13.813 +in the specified problem object.
13.814 +
13.815 +\subsection{glp\_get\_num\_cols---retrieve number of columns}
13.816 +
13.817 +\subsubsection*{Synopsis}
13.818 +
13.819 +\begin{verbatim}
13.820 +int glp_get_num_cols(glp_prob *lp);
13.821 +\end{verbatim}
13.822 +
13.823 +\subsubsection*{Returns}
13.824 +
13.825 +The routine \verb|glp_get_num_cols| returns the current number of
13.826 +columns the specified problem object.
13.827 +
13.828 +\subsection{glp\_get\_row\_name---retrieve row name}
13.829 +
13.830 +\subsubsection*{Synopsis}
13.831 +
13.832 +\begin{verbatim}
13.833 +const char *glp_get_row_name(glp_prob *lp, int i);
13.834 +\end{verbatim}
13.835 +
13.836 +\subsubsection*{Returns}
13.837 +
13.838 +The routine \verb|glp_get_row_name| returns a pointer to an internal
13.839 +buffer, which contains a symbolic name assigned to \verb|i|-th row.
13.840 +However, if the row has no assigned name, the routine returns
13.841 +\verb|NULL|.
13.842 +
13.843 +\subsection{glp\_get\_col\_name---retrieve column name}
13.844 +
13.845 +\subsubsection*{Synopsis}
13.846 +
13.847 +\begin{verbatim}
13.848 +const char *glp_get_col_name(glp_prob *lp, int j);
13.849 +\end{verbatim}
13.850 +
13.851 +\subsubsection*{Returns}
13.852 +
13.853 +The routine \verb|glp_get_col_name| returns a pointer to an internal
13.854 +buffer, which contains a symbolic name assigned to \verb|j|-th column.
13.855 +However, if the column has no assigned name, the routine returns
13.856 +\verb|NULL|.
13.857 +
13.858 +\subsection{glp\_get\_row\_type---retrieve row type}
13.859 +
13.860 +\subsubsection*{Synopsis}
13.861 +
13.862 +\begin{verbatim}
13.863 +int glp_get_row_type(glp_prob *lp, int i);
13.864 +\end{verbatim}
13.865 +
13.866 +\subsubsection*{Returns}
13.867 +
13.868 +The routine \verb|glp_get_row_type| returns the type of \verb|i|-th
13.869 +row, i.e. the type of corresponding auxiliary variable, as follows:
13.870 +
13.871 +\begin{tabular}{@{}ll}
13.872 +\verb|GLP_FR| & free (unbounded) variable; \\
13.873 +\verb|GLP_LO| & variable with lower bound; \\
13.874 +\verb|GLP_UP| & variable with upper bound; \\
13.875 +\verb|GLP_DB| & double-bounded variable; \\
13.876 +\verb|GLP_FX| & fixed variable. \\
13.877 +\end{tabular}
13.878 +
13.879 +\subsection{glp\_get\_row\_lb---retrieve row lower bound}
13.880 +
13.881 +\subsubsection*{Synopsis}
13.882 +
13.883 +\begin{verbatim}
13.884 +double glp_get_row_lb(glp_prob *lp, int i);
13.885 +\end{verbatim}
13.886 +
13.887 +\subsubsection*{Returns}
13.888 +
13.889 +The routine \verb|glp_get_row_lb| returns the lower bound of
13.890 +\verb|i|-th row, i.e. the lower bound of corresponding auxiliary
13.891 +variable. However, if the row has no lower bound, the routine returns
13.892 +\verb|-DBL_MAX|.
13.893 +
13.894 +\subsection{glp\_get\_row\_ub---retrieve row upper bound}
13.895 +
13.896 +\subsubsection*{Synopsis}
13.897 +
13.898 +\begin{verbatim}
13.899 +double glp_get_row_ub(glp_prob *lp, int i);
13.900 +\end{verbatim}
13.901 +
13.902 +\subsubsection*{Returns}
13.903 +
13.904 +The routine \verb|glp_get_row_ub| returns the upper bound of
13.905 +\verb|i|-th row, i.e. the upper bound of corresponding auxiliary
13.906 +variable. However, if the row has no upper bound, the routine returns
13.907 +\verb|+DBL_MAX|.
13.908 +
13.909 +\subsection{glp\_get\_col\_type---retrieve column type}
13.910 +
13.911 +\subsubsection*{Synopsis}
13.912 +
13.913 +\begin{verbatim}
13.914 +int glp_get_col_type(glp_prob *lp, int j);
13.915 +\end{verbatim}
13.916 +
13.917 +\subsubsection*{Returns}
13.918 +
13.919 +The routine \verb|glp_get_col_type| returns the type of \verb|j|-th
13.920 +column, i.e. the type of corresponding structural variable, as follows:
13.921 +
13.922 +\begin{tabular}{@{}ll}
13.923 +\verb|GLP_FR| & free (unbounded) variable; \\
13.924 +\verb|GLP_LO| & variable with lower bound; \\
13.925 +\verb|GLP_UP| & variable with upper bound; \\
13.926 +\verb|GLP_DB| & double-bounded variable; \\
13.927 +\verb|GLP_FX| & fixed variable. \\
13.928 +\end{tabular}
13.929 +
13.930 +\subsection{glp\_get\_col\_lb---retrieve column lower bound}
13.931 +
13.932 +\subsubsection*{Synopsis}
13.933 +
13.934 +\begin{verbatim}
13.935 +double glp_get_col_lb(glp_prob *lp, int j);
13.936 +\end{verbatim}
13.937 +
13.938 +\subsubsection*{Returns}
13.939 +
13.940 +The routine \verb|glp_get_col_lb| returns the lower bound of
13.941 +\verb|j|-th column, i.e. the lower bound of corresponding structural
13.942 +variable. However, if the column has no lower bound, the routine returns
13.943 +\verb|-DBL_MAX|.
13.944 +
13.945 +\subsection{glp\_get\_col\_ub---retrieve column upper bound}
13.946 +
13.947 +\subsubsection*{Synopsis}
13.948 +
13.949 +\begin{verbatim}
13.950 +double glp_get_col_ub(glp_prob *lp, int j);
13.951 +\end{verbatim}
13.952 +
13.953 +\subsubsection*{Returns}
13.954 +
13.955 +The routine \verb|glp_get_col_ub| returns the upper bound of
13.956 +\verb|j|-th column, i.e. the upper bound of corresponding structural
13.957 +variable. However, if the column has no upper bound, the routine returns
13.958 +\verb|+DBL_MAX|.
13.959 +
13.960 +\subsection{glp\_get\_obj\_coef---retrieve objective coefficient or\\
13.961 +constant term}
13.962 +
13.963 +\subsubsection*{Synopsis}
13.964 +
13.965 +\begin{verbatim}
13.966 +double glp_get_obj_coef(glp_prob *lp, int j);
13.967 +\end{verbatim}
13.968 +
13.969 +\subsubsection*{Returns}
13.970 +
13.971 +The routine \verb|glp_get_obj_coef| returns the objective coefficient
13.972 +at \verb|j|-th structural variable (column).
13.973 +
13.974 +If the parameter \verb|j| is 0, the routine returns the constant term
13.975 +(``shift'') of the objective function.
13.976 +
13.977 +\subsection{glp\_get\_num\_nz---retrieve number of constraint
13.978 +coefficients}
13.979 +
13.980 +\subsubsection*{Synopsis}
13.981 +
13.982 +\begin{verbatim}
13.983 +int glp_get_num_nz(glp_prob *lp);
13.984 +\end{verbatim}
13.985 +
13.986 +\subsubsection*{Returns}
13.987 +
13.988 +The routine \verb|glp_get_num_nz| returns the number of non-zero
13.989 +elements in the constraint matrix of the specified problem object.
13.990 +
13.991 +\subsection{glp\_get\_mat\_row---retrieve row of the constraint
13.992 +matrix}
13.993 +
13.994 +\subsubsection*{Synopsis}
13.995 +
13.996 +\begin{verbatim}
13.997 +int glp_get_mat_row(glp_prob *lp, int i, int ind[],
13.998 + double val[]);
13.999 +\end{verbatim}
13.1000 +
13.1001 +\subsubsection*{Description}
13.1002 +
13.1003 +The routine \verb|glp_get_mat_row| scans (non-zero) elements of
13.1004 +\verb|i|-th row of the constraint matrix of the specified problem object
13.1005 +and stores their column indices and numeric values to locations
13.1006 +\verb|ind[1]|, \dots, \verb|ind[len]| and \verb|val[1]|, \dots,
13.1007 +\verb|val[len]|, respectively, where $0\leq{\tt len}\leq n$ is the
13.1008 +number of elements in $i$-th row, $n$ is the number of columns.
13.1009 +
13.1010 +The parameter \verb|ind| and/or \verb|val| can be specified as
13.1011 +\verb|NULL|, in which case corresponding information is not stored.
13.1012 +
13.1013 +\subsubsection*{Returns}
13.1014 +
13.1015 +The routine \verb|glp_get_mat_row| returns the length \verb|len|, i.e.
13.1016 +the number of (non-zero) elements in \verb|i|-th row.
13.1017 +
13.1018 +\subsection{glp\_get\_mat\_col---retrieve column of the constraint\\
13.1019 +matrix}
13.1020 +
13.1021 +\subsubsection*{Synopsis}
13.1022 +
13.1023 +\begin{verbatim}
13.1024 +int glp_get_mat_col(glp_prob *lp, int j, int ind[],
13.1025 + double val[]);
13.1026 +\end{verbatim}
13.1027 +
13.1028 +\subsubsection*{Description}
13.1029 +
13.1030 +The routine \verb|glp_get_mat_col| scans (non-zero) elements of
13.1031 +\verb|j|-th column of the constraint matrix of the specified problem
13.1032 +object and stores their row indices and numeric values to locations
13.1033 +\verb|ind[1]|, \dots, \verb|ind[len]| and \verb|val[1]|, \dots,
13.1034 +\verb|val[len]|, respectively, where $0\leq{\tt len}\leq m$ is the
13.1035 +number of elements in $j$-th column, $m$ is the number of rows.
13.1036 +
13.1037 +The parameter \verb|ind| and/or \verb|val| can be specified as
13.1038 +\verb|NULL|, in which case corresponding information is not stored.
13.1039 +
13.1040 +\subsubsection*{Returns}
13.1041 +
13.1042 +The routine \verb|glp_get_mat_col| returns the length \verb|len|, i.e.
13.1043 +the number of (non-zero) elements in \verb|j|-th column.
13.1044 +
13.1045 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13.1046 +
13.1047 +\newpage
13.1048 +
13.1049 +\section{Row and column searching routines}
13.1050 +
13.1051 +\subsection{glp\_create\_index---create the name index}
13.1052 +
13.1053 +\subsubsection*{Synopsis}
13.1054 +
13.1055 +\begin{verbatim}
13.1056 +void glp_create_index(glp_prob *lp);
13.1057 +\end{verbatim}
13.1058 +
13.1059 +\subsubsection*{Description}
13.1060 +
13.1061 +The routine \verb|glp_create_index| creates the name index for the
13.1062 +specified problem object. The name index is an auxiliary data structure,
13.1063 +which is intended to quickly (i.e. for logarithmic time) find rows and
13.1064 +columns by their names.
13.1065 +
13.1066 +This routine can be called at any time. If the name index already
13.1067 +exists, the routine does nothing.
13.1068 +
13.1069 +\subsection{glp\_find\_row---find row by its name}
13.1070 +
13.1071 +\subsubsection*{Synopsis}
13.1072 +
13.1073 +\begin{verbatim}
13.1074 +int glp_find_row(glp_prob *lp, const char *name);
13.1075 +\end{verbatim}
13.1076 +
13.1077 +\subsubsection*{Returns}
13.1078 +
13.1079 +The routine \verb|glp_find_row| returns the ordinal number of a row,
13.1080 +which is assigned (by the routine \verb|glp_set_row_name|) the specified
13.1081 +symbolic \verb|name|. If no such row exists, the routine returns 0.
13.1082 +
13.1083 +\subsection{glp\_find\_col---find column by its name}
13.1084 +
13.1085 +\subsubsection*{Synopsis}
13.1086 +
13.1087 +\begin{verbatim}
13.1088 +int glp_find_col(glp_prob *lp, const char *name);
13.1089 +\end{verbatim}
13.1090 +
13.1091 +\subsubsection*{Returns}
13.1092 +
13.1093 +The routine \verb|glp_find_col| returns the ordinal number of a column,
13.1094 +which is assigned (by the routine \verb|glp_set_col_name|) the specified
13.1095 +symbolic \verb|name|. If no such column exists, the routine returns 0.
13.1096 +
13.1097 +\subsection{glp\_delete\_index---delete the name index}
13.1098 +
13.1099 +\subsubsection*{Synopsis}
13.1100 +
13.1101 +\begin{verbatim}
13.1102 +void glp_delete_index(glp_prob *lp);
13.1103 +\end{verbatim}
13.1104 +
13.1105 +\subsubsection*{Description}
13.1106 +
13.1107 +The routine \verb|glp_delete_index| deletes the name index previously
13.1108 +created by the routine \verb|glp_create_index| and frees the memory
13.1109 +allocated to this auxiliary data structure.
13.1110 +
13.1111 +This routine can be called at any time. If the name index does not
13.1112 +exist, the routine does nothing.
13.1113 +
13.1114 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13.1115 +
13.1116 +\newpage
13.1117 +
13.1118 +\section{Problem scaling routines}
13.1119 +
13.1120 +\subsection{Background}
13.1121 +
13.1122 +In GLPK the {\it scaling} means a linear transformation applied to the
13.1123 +constraint matrix to improve its numerical properties.\footnote{In many
13.1124 +cases a proper scaling allows making the constraint matrix to be better
13.1125 +conditioned, i.e. decreasing its condition number, that makes
13.1126 +computations numerically more stable.}
13.1127 +
13.1128 +The main equality is the following:
13.1129 +$$\widetilde{A}=RAS,\eqno(2.1)$$
13.1130 +where $A=(a_{ij})$ is the original constraint matrix, $R=(r_{ii})>0$ is
13.1131 +a diagonal matrix used to scale rows (constraints), $S=(s_{jj})>0$ is a
13.1132 +diagonal matrix used to scale columns (variables), $\widetilde{A}$ is
13.1133 +the scaled constraint matrix.
13.1134 +
13.1135 +From (2.1) it follows that in the {\it scaled} problem instance each
13.1136 +original constraint coefficient $a_{ij}$ is replaced by corresponding
13.1137 +scaled constraint coefficient:
13.1138 +$$\widetilde{a}_{ij}=r_{ii}a_{ij}s_{jj}.\eqno(2.2)$$
13.1139 +
13.1140 +Note that the scaling is performed internally and therefore
13.1141 +transparently to the user. This means that on API level the user always
13.1142 +deal with unscaled data.
13.1143 +
13.1144 +Scale factors $r_{ii}$ and $s_{jj}$ can be set or changed at any time
13.1145 +either directly by the application program in a problem specific way
13.1146 +(with the routines \verb|glp_set_rii| and \verb|glp_set_sjj|), or by
13.1147 +some API routines intended for automatic scaling.
13.1148 +
13.1149 +\subsection{glp\_set\_rii---set (change) row scale factor}
13.1150 +
13.1151 +\subsubsection*{Synopsis}
13.1152 +
13.1153 +\begin{verbatim}
13.1154 +void glp_set_rii(glp_prob *lp, int i, double rii);
13.1155 +\end{verbatim}
13.1156 +
13.1157 +\subsubsection*{Description}
13.1158 +
13.1159 +The routine \verb|glp_set_rii| sets (changes) the scale factor $r_{ii}$
13.1160 +for $i$-th row of the specified problem object.
13.1161 +
13.1162 +\subsection{glp\_set\_sjj---set (change) column scale factor}
13.1163 +
13.1164 +\subsubsection*{Synopsis}
13.1165 +
13.1166 +\begin{verbatim}
13.1167 +void glp_set_sjj(glp_prob *lp, int j, double sjj);
13.1168 +\end{verbatim}
13.1169 +
13.1170 +\subsubsection*{Description}
13.1171 +
13.1172 +The routine \verb|glp_set_sjj| sets (changes) the scale factor $s_{jj}$
13.1173 +for $j$-th column of the specified problem object.
13.1174 +
13.1175 +\subsection{glp\_get\_rii---retrieve row scale factor}
13.1176 +
13.1177 +\subsubsection*{Synopsis}
13.1178 +
13.1179 +\begin{verbatim}
13.1180 +double glp_get_rii(glp_prob *lp, int i);
13.1181 +\end{verbatim}
13.1182 +
13.1183 +\subsubsection*{Returns}
13.1184 +
13.1185 +The routine \verb|glp_get_rii| returns current scale factor $r_{ii}$ for
13.1186 +$i$-th row of the specified problem object.
13.1187 +
13.1188 +\subsection{glp\_get\_sjj---retrieve column scale factor}
13.1189 +
13.1190 +\subsubsection*{Synopsis}
13.1191 +
13.1192 +\begin{verbatim}
13.1193 +double glp_get_sjj(glp_prob *lp, int j);
13.1194 +\end{verbatim}
13.1195 +
13.1196 +\subsubsection*{Returns}
13.1197 +
13.1198 +The routine \verb|glp_get_sjj| returns current scale factor $s_{jj}$ for
13.1199 +$j$-th column of the specified problem object.
13.1200 +
13.1201 +\subsection{glp\_scale\_prob---scale problem data}
13.1202 +
13.1203 +\subsubsection*{Synopsis}
13.1204 +
13.1205 +\begin{verbatim}
13.1206 +void glp_scale_prob(glp_prob *lp, int flags);
13.1207 +\end{verbatim}
13.1208 +
13.1209 +\subsubsection*{Description}
13.1210 +
13.1211 +The routine \verb|glp_scale_prob| performs automatic scaling of problem
13.1212 +data for the specified problem object.
13.1213 +
13.1214 +The parameter \verb|flags| specifies scaling options used by the
13.1215 +routine. The options can be combined with the bitwise OR operator and
13.1216 +may be the following:
13.1217 +
13.1218 +\begin{tabular}{@{}ll}
13.1219 +\verb|GLP_SF_GM| & perform geometric mean scaling;\\
13.1220 +\verb|GLP_SF_EQ| & perform equilibration scaling;\\
13.1221 +\verb|GLP_SF_2N| & round scale factors to nearest power of two;\\
13.1222 +\verb|GLP_SF_SKIP| & skip scaling, if the problem is well scaled.\\
13.1223 +\end{tabular}
13.1224 +
13.1225 +The parameter \verb|flags| may be specified as \verb|GLP_SF_AUTO|, in
13.1226 +which case the routine chooses the scaling options automatically.
13.1227 +
13.1228 +\subsection{glp\_unscale\_prob---unscale problem data}
13.1229 +
13.1230 +\subsubsection*{Synopsis}
13.1231 +
13.1232 +\begin{verbatim}
13.1233 +void glp_unscale_prob(glp_prob *lp);
13.1234 +\end{verbatim}
13.1235 +
13.1236 +The routine \verb|glp_unscale_prob| performs unscaling of problem data
13.1237 +for the specified problem object.
13.1238 +
13.1239 +``Unscaling'' means replacing the current scaling matrices $R$ and $S$
13.1240 +by unity matrices that cancels the scaling effect.
13.1241 +
13.1242 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13.1243 +
13.1244 +\newpage
13.1245 +
13.1246 +\section{LP basis constructing routines}
13.1247 +
13.1248 +\subsection{Background}
13.1249 +
13.1250 +To start the search the simplex method needs a valid initial basis. In
13.1251 +GLPK the basis is completely defined by a set of {\it statuses} assigned
13.1252 +to {\it all} (auxiliary and structural) variables, where the status may
13.1253 +be one of the following:
13.1254 +
13.1255 +\begin{tabular}{@{}ll}
13.1256 +\verb|GLP_BS| & basic variable;\\
13.1257 +\verb|GLP_NL| & non-basic variable having active lower bound;\\
13.1258 +\verb|GLP_NU| & non-basic variable having active upper bound;\\
13.1259 +\verb|GLP_NF| & non-basic free variable;\\
13.1260 +\verb|GLP_NS| & non-basic fixed variable.\\
13.1261 +\end{tabular}
13.1262 +
13.1263 +The basis is {\it valid}, if the basis matrix, which is a matrix built
13.1264 +of columns of the augmented constraint matrix $(I\:|-A)$ corresponding
13.1265 +to basic variables, is non-singular. This, in particular, means that
13.1266 +the number of basic variables must be the same as the number of rows in
13.1267 +the problem object. (For more details see Section \ref{lpbasis}, page
13.1268 +\pageref{lpbasis}.)
13.1269 +
13.1270 +Any initial basis may be constructed (or restored) with the API
13.1271 +routines \verb|glp_set_row_stat| and \verb|glp_set_col_stat| by
13.1272 +assigning appropriate statuses to auxiliary and structural variables.
13.1273 +Another way to construct an initial basis is to use API routines like
13.1274 +\verb|glp_adv_basis|, which implement so called
13.1275 +{\it crashing}.\footnote{This term is from early linear programming
13.1276 +systems and means a heuristic to construct a valid initial basis.} Note
13.1277 +that on normal exit the simplex solver remains the basis valid, so in
13.1278 +case of reoptimization there is no need to construct an initial basis
13.1279 +from scratch.
13.1280 +
13.1281 +\subsection{glp\_set\_row\_stat---set (change) row status}
13.1282 +
13.1283 +\subsubsection*{Synopsis}
13.1284 +
13.1285 +\begin{verbatim}
13.1286 +void glp_set_row_stat(glp_prob *lp, int i, int stat);
13.1287 +\end{verbatim}
13.1288 +
13.1289 +\subsubsection*{Description}
13.1290 +
13.1291 +The routine \verb|glp_set_row_stat| sets (changes) the current status
13.1292 +of \verb|i|-th row (auxiliary variable) as specified by the parameter
13.1293 +\verb|stat|:
13.1294 +
13.1295 +\begin{tabular}{@{}lp{104.2mm}@{}}
13.1296 +\verb|GLP_BS| & make the row basic (make the constraint inactive); \\
13.1297 +\verb|GLP_NL| & make the row non-basic (make the constraint active); \\
13.1298 +\end{tabular}
13.1299 +
13.1300 +\newpage
13.1301 +
13.1302 +\begin{tabular}{@{}lp{104.2mm}@{}}
13.1303 +\verb|GLP_NU| & make the row non-basic and set it to the upper bound;
13.1304 + if the row is not double-bounded, this status is equivalent to
13.1305 + \verb|GLP_NL| (only in the case of this routine); \\
13.1306 +\verb|GLP_NF| & the same as \verb|GLP_NL| (only in the case of this
13.1307 + routine); \\
13.1308 +\verb|GLP_NS| & the same as \verb|GLP_NL| (only in the case of this
13.1309 + routine). \\
13.1310 +\end{tabular}
13.1311 +
13.1312 +\subsection{glp\_set\_col\_stat---set (change) column status}
13.1313 +
13.1314 +\subsubsection*{Synopsis}
13.1315 +
13.1316 +\begin{verbatim}
13.1317 +void glp_set_col_stat(glp_prob *lp, int j, int stat);
13.1318 +\end{verbatim}
13.1319 +
13.1320 +\subsubsection*{Description}
13.1321 +
13.1322 +The routine \verb|glp_set_col_stat sets| (changes) the current status
13.1323 +of \verb|j|-th column (structural variable) as specified by the
13.1324 +parameter \verb|stat|:
13.1325 +
13.1326 +\begin{tabular}{@{}lp{104.2mm}@{}}
13.1327 +\verb|GLP_BS| & make the column basic; \\
13.1328 +\verb|GLP_NL| & make the column non-basic; \\
13.1329 +\verb|GLP_NU| & make the column non-basic and set it to the upper
13.1330 + bound; if the column is not double-bounded, this status is equivalent
13.1331 + to \verb|GLP_NL| (only in the case of this routine); \\
13.1332 +\verb|GLP_NF| & the same as \verb|GLP_NL| (only in the case of this
13.1333 + routine); \\
13.1334 +\verb|GLP_NS| & the same as \verb|GLP_NL| (only in the case of this
13.1335 + routine).
13.1336 +\end{tabular}
13.1337 +
13.1338 +\subsection{glp\_std\_basis---construct standard initial LP basis}
13.1339 +
13.1340 +\subsubsection*{Synopsis}
13.1341 +
13.1342 +\begin{verbatim}
13.1343 +void glp_std_basis(glp_prob *lp);
13.1344 +\end{verbatim}
13.1345 +
13.1346 +\subsubsection*{Description}
13.1347 +
13.1348 +The routine \verb|glp_std_basis| constructs the ``standard'' (trivial)
13.1349 +initial LP basis for the specified problem object.
13.1350 +
13.1351 +In the ``standard'' LP basis all auxiliary variables (rows) are basic,
13.1352 +and all structural variables (columns) are non-basic (so the
13.1353 +corresponding basis matrix is unity).
13.1354 +
13.1355 +\newpage
13.1356 +
13.1357 +\subsection{glp\_adv\_basis---construct advanced initial LP basis}
13.1358 +
13.1359 +\subsubsection*{Synopsis}
13.1360 +
13.1361 +\begin{verbatim}
13.1362 +void glp_adv_basis(glp_prob *lp, int flags);
13.1363 +\end{verbatim}
13.1364 +
13.1365 +\subsubsection*{Description}
13.1366 +
13.1367 +The routine \verb|glp_adv_basis| constructs an advanced initial LP
13.1368 +basis for the specified problem object.
13.1369 +
13.1370 +The parameter \verb|flags| is reserved for use in the future and must
13.1371 +be specified as zero.
13.1372 +
13.1373 +In order to construct the advanced initial LP basis the routine does
13.1374 +the following:
13.1375 +
13.1376 +1) includes in the basis all non-fixed auxiliary variables;
13.1377 +
13.1378 +2) includes in the basis as many non-fixed structural variables as
13.1379 +possible keeping the triangular form of the basis matrix;
13.1380 +
13.1381 +3) includes in the basis appropriate (fixed) auxiliary variables to
13.1382 +complete the basis.
13.1383 +
13.1384 +As a result the initial LP basis has as few fixed variables as possible
13.1385 +and the corresponding basis matrix is triangular.
13.1386 +
13.1387 +\subsection{glp\_cpx\_basis---construct Bixby's initial LP basis}
13.1388 +
13.1389 +\subsubsection*{Synopsis}
13.1390 +
13.1391 +\begin{verbatim}
13.1392 +void glp_cpx_basis(glp_prob *lp);
13.1393 +\end{verbatim}
13.1394 +
13.1395 +\subsubsection*{Description}
13.1396 +
13.1397 +The routine \verb|glp_cpx_basis| constructs an initial basis for the
13.1398 +specified problem object with the algorithm proposed by
13.1399 +R.~Bixby.\footnote{Robert E. Bixby, ``Implementing the Simplex Method:
13.1400 +The Initial Basis.'' ORSA Journal on Computing, Vol. 4, No. 3, 1992,
13.1401 +pp. 267-84.}
13.1402 +
13.1403 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13.1404 +
13.1405 +\newpage
13.1406 +
13.1407 +\section{Simplex method routines}
13.1408 +
13.1409 +The {\it simplex method} is a well known efficient numerical procedure
13.1410 +to solve LP problems.
13.1411 +
13.1412 +On each iteration the simplex method transforms the original system of
13.1413 +equaility constraints (1.2) resolving them through different sets of
13.1414 +variables to an equivalent system called {\it the simplex table} (or
13.1415 +sometimes {\it the simplex tableau}), which has the following form:
13.1416 +$$
13.1417 +\begin{array}{r@{\:}c@{\:}r@{\:}c@{\:}r@{\:}c@{\:}r}
13.1418 +z&=&d_1(x_N)_1&+&d_2(x_N)_2&+ \dots +&d_n(x_N)_n \\
13.1419 +(x_B)_1&=&\xi_{11}(x_N)_1& +& \xi_{12}(x_N)_2& + \dots +&
13.1420 + \xi_{1n}(x_N)_n \\
13.1421 +(x_B)_2&=& \xi_{21}(x_N)_1& +& \xi_{22}(x_N)_2& + \dots +&
13.1422 + \xi_{2n}(x_N)_n \\
13.1423 +\multicolumn{7}{c}
13.1424 +{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .} \\
13.1425 +(x_B)_m&=&\xi_{m1}(x_N)_1& +& \xi_{m2}(x_N)_2& + \dots +&
13.1426 + \xi_{mn}(x_N)_n \\
13.1427 +\end{array} \eqno (2.3)
13.1428 +$$
13.1429 +where: $(x_B)_1, (x_B)_2, \dots, (x_B)_m$ are basic variables;
13.1430 +$(x_N)_1, (x_N)_2, \dots, (x_N)_n$ are non-basic variables;
13.1431 +$d_1, d_2, \dots, d_n$ are reduced costs;
13.1432 +$\xi_{11}, \xi_{12}, \dots, \xi_{mn}$ are coefficients of the
13.1433 +simplex table. (May note that the original LP problem (1.1)---(1.3) also
13.1434 +has the form of a simplex table, where all equalities are resolved
13.1435 +through auxiliary variables.)
13.1436 +
13.1437 +From the linear programming theory it is known that if an optimal
13.1438 +solution of the LP problem (1.1)---(1.3) exists, it can always be
13.1439 +written in the form (2.3), where non-basic variables are set on their
13.1440 +bounds while values of the objective function and basic variables are
13.1441 +determined by the corresponding equalities of the simplex table.
13.1442 +
13.1443 +A set of values of all basic and non-basic variables determined by the
13.1444 +simplex table is called {\it basic solution}. If all basic variables are
13.1445 +within their bounds, the basic solution is called {\it (primal)
13.1446 +feasible}, otherwise it is called {\it (primal) infeasible}. A feasible
13.1447 +basic solution, which provides a smallest (in case of minimization) or
13.1448 +a largest (in case of maximization) value of the objective function is
13.1449 +called {\it optimal}. Therefore, for solving LP problem the simplex
13.1450 +method tries to find its optimal basic solution.
13.1451 +
13.1452 +Primal feasibility of some basic solution may be stated by simple
13.1453 +checking if all basic variables are within their bounds. Basic solution
13.1454 +is optimal if additionally the following optimality conditions are
13.1455 +satisfied for all non-basic variables:
13.1456 +\begin{center}
13.1457 +\begin{tabular}{lcc}
13.1458 +Status of $(x_N)_j$ & Minimization & Maximization \\
13.1459 +\hline
13.1460 +$(x_N)_j$ is free & $d_j = 0$ & $d_j = 0$ \\
13.1461 +$(x_N)_j$ is on its lower bound & $d_j \geq 0$ & $d_j \leq 0$ \\
13.1462 +$(x_N)_j$ is on its upper bound & $d_j \leq 0$ & $d_j \geq 0$ \\
13.1463 +\end{tabular}
13.1464 +\end{center}
13.1465 +In other words, basic solution is optimal if there is no non-basic
13.1466 +variable, which changing in the feasible direction (i.e. increasing if
13.1467 +it is free or on its lower bound, or decreasing if it is free or on its
13.1468 +upper bound) can improve (i.e. decrease in case of minimization or
13.1469 +increase in case of maximization) the objective function.
13.1470 +
13.1471 +If all non-basic variables satisfy to the optimality conditions shown
13.1472 +above (independently on whether basic variables are within their bounds
13.1473 +or not), the basic solution is called {\it dual feasible}, otherwise it
13.1474 +is called {\it dual infeasible}.
13.1475 +
13.1476 +It may happen that some LP problem has no primal feasible solution due
13.1477 +to incorrect formulation---this means that its constraints conflict
13.1478 +with each other. It also may happen that some LP problem has unbounded
13.1479 +solution again due to incorrect formulation---this means that some
13.1480 +non-basic variable can improve the objective function, i.e. the
13.1481 +optimality conditions are violated, and at the same time this variable
13.1482 +can infinitely change in the feasible direction meeting no resistance
13.1483 +from basic variables. (May note that in the latter case the LP problem
13.1484 +has no dual feasible solution.)
13.1485 +
13.1486 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13.1487 +
13.1488 +\subsection{glp\_simplex---solve LP problem with the primal or dual
13.1489 +simplex method}
13.1490 +
13.1491 +\subsubsection*{Synopsis}
13.1492 +
13.1493 +\begin{verbatim}
13.1494 +int glp_simplex(glp_prob *lp, const glp_smcp *parm);
13.1495 +\end{verbatim}
13.1496 +
13.1497 +\subsubsection*{Description}
13.1498 +
13.1499 +The routine \verb|glp_simplex| is a driver to the LP solver based on
13.1500 +the simplex method. This routine retrieves problem data from the
13.1501 +specified problem object, calls the solver to solve the problem
13.1502 +instance, and stores results of computations back into the problem
13.1503 +object.
13.1504 +
13.1505 +The simplex solver has a set of control parameters. Values of the
13.1506 +control parameters can be passed in the structure \verb|glp_smcp|,
13.1507 +which the parameter \verb|parm| points to. For detailed description of
13.1508 +this structure see paragraph ``Control parameters'' below.
13.1509 +Before specifying some control parameters the application program
13.1510 +should initialize the structure \verb|glp_smcp| by default values of
13.1511 +all control parameters using the routine \verb|glp_init_smcp| (see the
13.1512 +next subsection). This is needed for backward compatibility, because in
13.1513 +the future there may appear new members in the structure
13.1514 +\verb|glp_smcp|.
13.1515 +
13.1516 +The parameter \verb|parm| can be specified as \verb|NULL|, in which
13.1517 +case the solver uses default settings.
13.1518 +
13.1519 +\subsubsection*{Returns}
13.1520 +
13.1521 +\def\arraystretch{1}
13.1522 +
13.1523 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
13.1524 +0 & The LP problem instance has been successfully solved. (This code
13.1525 +does {\it not} necessarily mean that the solver has found optimal
13.1526 +solution. It only means that the solution process was successful.) \\
13.1527 +\verb|GLP_EBADB| & Unable to start the search, because the initial basis
13.1528 +specified in the problem object is invalid---the number of basic
13.1529 +(auxiliary and structural) variables is not the same as the number of
13.1530 +rows in the problem object.\\
13.1531 +\verb|GLP_ESING| & Unable to start the search, because the basis matrix
13.1532 +corresponding to the initial basis is singular within the working
13.1533 +precision.\\
13.1534 +\verb|GLP_ECOND| & Unable to start the search, because the basis matrix
13.1535 +corresponding to the initial basis is ill-conditioned, i.e. its
13.1536 +condition number is too large.\\
13.1537 +\verb|GLP_EBOUND| & Unable to start the search, because some
13.1538 +double-bounded (auxiliary or structural) variables have incorrect
13.1539 +bounds.\\
13.1540 +\verb|GLP_EFAIL| & The search was prematurely terminated due to the
13.1541 +solver failure.\\
13.1542 +\verb|GLP_EOBJLL| & The search was prematurely terminated, because the
13.1543 +objective function being maximized has reached its lower limit and
13.1544 +continues decreasing (the dual simplex only).\\
13.1545 +\verb|GLP_EOBJUL| & The search was prematurely terminated, because the
13.1546 +objective function being minimized has reached its upper limit and
13.1547 +continues increasing (the dual simplex only).\\
13.1548 +\verb|GLP_EITLIM| & The search was prematurely terminated, because the
13.1549 +simplex iteration limit has been exceeded.\\
13.1550 +\verb|GLP_ETMLIM| & The search was prematurely terminated, because the
13.1551 +time limit has been exceeded.\\
13.1552 +\verb|GLP_ENOPFS| & The LP problem instance has no primal feasible
13.1553 +solution (only if the LP presolver is used).\\
13.1554 +\verb|GLP_ENODFS| & The LP problem instance has no dual feasible
13.1555 +solution (only if the LP presolver is used).\\
13.1556 +\end{tabular}
13.1557 +
13.1558 +\subsubsection*{Built-in LP presolver}
13.1559 +
13.1560 +The simplex solver has {\it built-in LP presolver}. It is a subprogram
13.1561 +that transforms the original LP problem specified in the problem object
13.1562 +to an equivalent LP problem, which may be easier for solving with the
13.1563 +simplex method than the original one. This is attained mainly due to
13.1564 +reducing the problem size and improving its numeric properties (for
13.1565 +example, by removing some inactive constraints or by fixing some
13.1566 +non-basic variables). Once the transformed LP problem has been solved,
13.1567 +the presolver transforms its basic solution back to the corresponding
13.1568 +basic solution of the original problem.
13.1569 +
13.1570 +Presolving is an optional feature of the routine \verb|glp_simplex|,
13.1571 +and by default it is disabled. In order to enable the LP presolver the
13.1572 +control parameter \verb|presolve| should be set to \verb|GLP_ON| (see
13.1573 +paragraph ``Control parameters'' below). Presolving may be used when
13.1574 +the problem instance is solved for the first time. However, on
13.1575 +performing re-optimization the presolver should be disabled.
13.1576 +
13.1577 +The presolving procedure is transparent to the API user in the sense
13.1578 +that all necessary processing is performed internally, and a basic
13.1579 +solution of the original problem recovered by the presolver is the same
13.1580 +as if it were computed directly, i.e. without presolving.
13.1581 +
13.1582 +Note that the presolver is able to recover only optimal solutions. If
13.1583 +a computed solution is infeasible or non-optimal, the corresponding
13.1584 +solution of the original problem cannot be recovered and therefore
13.1585 +remains undefined. If you need to know a basic solution even if it is
13.1586 +infeasible or non-optimal, the presolver should be disabled.
13.1587 +
13.1588 +\subsubsection*{Terminal output}
13.1589 +
13.1590 +Solving large problem instances may take a long time, so the solver
13.1591 +reports some information about the current basic solution, which is sent
13.1592 +to the terminal. This information has the following format:
13.1593 +
13.1594 +\begin{verbatim}
13.1595 +nnn: obj = xxx infeas = yyy (ddd)
13.1596 +\end{verbatim}
13.1597 +
13.1598 +\noindent
13.1599 +where: `\verb|nnn|' is the iteration number, `\verb|xxx|' is the
13.1600 +current value of the objective function (it is is unscaled and has
13.1601 +correct sign); `\verb|yyy|' is the current sum of primal or dual
13.1602 +infeasibilities (it is scaled and therefore may be used only for visual
13.1603 +estimating), `\verb|ddd|' is the current number of fixed basic
13.1604 +variables.
13.1605 +
13.1606 +The symbol preceding the iteration number indicates which phase of the
13.1607 +simplex method is in effect:
13.1608 +
13.1609 +{\it Blank} means that the solver is searching for primal feasible
13.1610 +solution using the primal simplex or for dual feasible solution using
13.1611 +the dual simplex;
13.1612 +
13.1613 +{\it Asterisk} (\verb|*|) means that the solver is searching for
13.1614 +optimal solution using the primal simplex;
13.1615 +
13.1616 +{\it Vertical dash} (\verb/|/) means that the solver is searching for
13.1617 +optimal solution using the dual simplex.
13.1618 +
13.1619 +\subsubsection*{Control parameters}
13.1620 +
13.1621 +This paragraph describes all control parameters currently used in the
13.1622 +simplex solver. Symbolic names of control parameters are names of
13.1623 +corresponding members in the structure \verb|glp_smcp|.
13.1624 +
13.1625 +\medskip
13.1626 +
13.1627 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.1628 +\multicolumn{2}{@{}l}{{\tt int msg\_lev} (default: {\tt GLP\_MSG\_ALL})}
13.1629 +\\
13.1630 +&Message level for terminal output:\\
13.1631 +&\verb|GLP_MSG_OFF|---no output;\\
13.1632 +&\verb|GLP_MSG_ERR|---error and warning messages only;\\
13.1633 +&\verb|GLP_MSG_ON |---normal output;\\
13.1634 +&\verb|GLP_MSG_ALL|---full output (including informational messages).
13.1635 +\\
13.1636 +\end{tabular}
13.1637 +
13.1638 +\medskip
13.1639 +
13.1640 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.1641 +\multicolumn{2}{@{}l}{{\tt int meth} (default: {\tt GLP\_PRIMAL})}
13.1642 +\\
13.1643 +&Simplex method option:\\
13.1644 +&\verb|GLP_PRIMAL|---use two-phase primal simplex;\\
13.1645 +&\verb|GLP_DUAL |---use two-phase dual simplex;\\
13.1646 +&\verb|GLP_DUALP |---use two-phase dual simplex, and if it fails,
13.1647 +switch to the\\
13.1648 +&\verb| |$\:$ primal simplex.\\
13.1649 +\end{tabular}
13.1650 +
13.1651 +\medskip
13.1652 +
13.1653 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.1654 +\multicolumn{2}{@{}l}{{\tt int pricing} (default: {\tt GLP\_PT\_PSE})}
13.1655 +\\
13.1656 +&Pricing technique:\\
13.1657 +&\verb|GLP_PT_STD|---standard (textbook);\\
13.1658 +&\verb|GLP_PT_PSE|---projected steepest edge.\\
13.1659 +\end{tabular}
13.1660 +
13.1661 +\medskip
13.1662 +
13.1663 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.1664 +\multicolumn{2}{@{}l}{{\tt int r\_test} (default: {\tt GLP\_RT\_HAR})}
13.1665 +\\
13.1666 +&Ratio test technique:\\
13.1667 +&\verb|GLP_RT_STD|---standard (textbook);\\
13.1668 +&\verb|GLP_RT_HAR|---Harris' two-pass ratio test.\\
13.1669 +\end{tabular}
13.1670 +
13.1671 +\medskip
13.1672 +
13.1673 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.1674 +\multicolumn{2}{@{}l}{{\tt double tol\_bnd} (default: {\tt 1e-7})}
13.1675 +\\
13.1676 +&Tolerance used to check if the basic solution is primal feasible.
13.1677 +(Do not change this parameter without detailed understanding its
13.1678 +purpose.)\\
13.1679 +\end{tabular}
13.1680 +
13.1681 +\medskip
13.1682 +
13.1683 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.1684 +\multicolumn{2}{@{}l}{{\tt double tol\_dj} (default: {\tt 1e-7})}
13.1685 +\\
13.1686 +&Tolerance used to check if the basic solution is dual feasible.
13.1687 +(Do not change this parameter without detailed understanding its
13.1688 +purpose.)\\
13.1689 +\end{tabular}
13.1690 +
13.1691 +\medskip
13.1692 +
13.1693 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.1694 +\multicolumn{2}{@{}l}{{\tt double tol\_piv} (default: {\tt 1e-10})}
13.1695 +\\
13.1696 +&Tolerance used to choose eligble pivotal elements of the simplex table.
13.1697 +(Do not change this parameter without detailed understanding its
13.1698 +purpose.)\\
13.1699 +\end{tabular}
13.1700 +
13.1701 +\medskip
13.1702 +
13.1703 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.1704 +\multicolumn{2}{@{}l}{{\tt double obj\_ll} (default: {\tt -DBL\_MAX})}
13.1705 +\\
13.1706 +&Lower limit of the objective function. If the objective function
13.1707 +reaches this limit and continues decreasing, the solver terminates the
13.1708 +search. (Used in the dual simplex only.)\\
13.1709 +\end{tabular}
13.1710 +
13.1711 +\medskip
13.1712 +
13.1713 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.1714 +\multicolumn{2}{@{}l}{{\tt double obj\_ul} (default: {\tt +DBL\_MAX})}
13.1715 +\\
13.1716 +&Upper limit of the objective function. If the objective function
13.1717 +reaches this limit and continues increasing, the solver terminates the
13.1718 +search. (Used in the dual simplex only.)\\
13.1719 +\end{tabular}
13.1720 +
13.1721 +\medskip
13.1722 +
13.1723 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.1724 +\multicolumn{2}{@{}l}{{\tt int it\_lim} (default: {\tt INT\_MAX})}
13.1725 +\\
13.1726 +&Simplex iteration limit.\\
13.1727 +\end{tabular}
13.1728 +
13.1729 +\medskip
13.1730 +
13.1731 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.1732 +\multicolumn{2}{@{}l}{{\tt int tm\_lim} (default: {\tt INT\_MAX})}
13.1733 +\\
13.1734 +&Searching time limit, in milliseconds.\\
13.1735 +\end{tabular}
13.1736 +
13.1737 +\medskip
13.1738 +
13.1739 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.1740 +\multicolumn{2}{@{}l}{{\tt int out\_frq} (default: {\tt 500})}
13.1741 +\\
13.1742 +&Output frequency, in iterations. This parameter specifies how
13.1743 +frequently the solver sends information about the solution process to
13.1744 +the terminal.\\
13.1745 +\end{tabular}
13.1746 +
13.1747 +\medskip
13.1748 +
13.1749 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.1750 +\multicolumn{2}{@{}l}{{\tt int out\_dly} (default: {\tt 0})}
13.1751 +\\
13.1752 +&Output delay, in milliseconds. This parameter specifies how long the
13.1753 +solver should delay sending information about the solution process to
13.1754 +the terminal.\\
13.1755 +\end{tabular}
13.1756 +
13.1757 +\medskip
13.1758 +
13.1759 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.1760 +\multicolumn{2}{@{}l}{{\tt int presolve} (default: {\tt GLP\_OFF})}
13.1761 +\\
13.1762 +&LP presolver option:\\
13.1763 +&\verb|GLP_ON |---enable using the LP presolver;\\
13.1764 +&\verb|GLP_OFF|---disable using the LP presolver.\\
13.1765 +\end{tabular}
13.1766 +
13.1767 +\subsubsection*{Example 1}
13.1768 +
13.1769 +The following main program reads LP problem instance in fixed MPS
13.1770 +format from file \verb|25fv47.mps|,\footnote{This instance in fixed MPS
13.1771 +format can be found in the Netlib LP collection; see
13.1772 +{\tt ftp://ftp.netlib.org/lp/data/}.} constructs an advanced initial
13.1773 +basis, solves the instance with the primal simplex method (by default),
13.1774 +and writes the solution to file \verb|25fv47.txt|.
13.1775 +
13.1776 +\newpage
13.1777 +
13.1778 +\begin{footnotesize}
13.1779 +\begin{verbatim}
13.1780 +/* spxsamp1.c */
13.1781 +
13.1782 +#include <stdio.h>
13.1783 +#include <stdlib.h>
13.1784 +#include <glpk.h>
13.1785 +
13.1786 +int main(void)
13.1787 +{ glp_prob *P;
13.1788 + P = glp_create_prob();
13.1789 + glp_read_mps(P, GLP_MPS_DECK, NULL, "25fv47.mps");
13.1790 + glp_adv_basis(P, 0);
13.1791 + glp_simplex(P, NULL);
13.1792 + glp_print_sol(P, "25fv47.txt");
13.1793 + glp_delete_prob(P);
13.1794 + return 0;
13.1795 +}
13.1796 +
13.1797 +/* eof */
13.1798 +\end{verbatim}
13.1799 +\end{footnotesize}
13.1800 +
13.1801 +\noindent
13.1802 +Below here is shown the terminal output from this example program.
13.1803 +
13.1804 +\begin{footnotesize}
13.1805 +\begin{verbatim}
13.1806 +Reading problem data from `25fv47.mps'...
13.1807 +Problem: 25FV47
13.1808 +Objective: R0000
13.1809 +822 rows, 1571 columns, 11127 non-zeros
13.1810 +6919 records were read
13.1811 +Crashing...
13.1812 +Size of triangular part = 799
13.1813 + 0: obj = 1.627307307e+04 infeas = 5.194e+04 (23)
13.1814 + 200: obj = 1.474901610e+04 infeas = 1.233e+04 (19)
13.1815 + 400: obj = 1.343909995e+04 infeas = 3.648e+03 (13)
13.1816 + 600: obj = 1.756052217e+04 infeas = 4.179e+02 (7)
13.1817 +* 775: obj = 1.789251591e+04 infeas = 4.982e-14 (1)
13.1818 +* 800: obj = 1.663354510e+04 infeas = 2.857e-14 (1)
13.1819 +* 1000: obj = 1.024935068e+04 infeas = 1.958e-12 (1)
13.1820 +* 1200: obj = 7.860174791e+03 infeas = 2.810e-29 (1)
13.1821 +* 1400: obj = 6.642378184e+03 infeas = 2.036e-16 (1)
13.1822 +* 1600: obj = 6.037014568e+03 infeas = 0.000e+00 (1)
13.1823 +* 1800: obj = 5.662171307e+03 infeas = 6.447e-15 (1)
13.1824 +* 2000: obj = 5.528146165e+03 infeas = 9.764e-13 (1)
13.1825 +* 2125: obj = 5.501845888e+03 infeas = 0.000e+00 (1)
13.1826 +OPTIMAL SOLUTION FOUND
13.1827 +Writing basic solution to `25fv47.txt'...
13.1828 +\end{verbatim}
13.1829 +\end{footnotesize}
13.1830 +
13.1831 +\newpage
13.1832 +
13.1833 +\subsubsection*{Example 2}
13.1834 +
13.1835 +The following main program solves the same LP problem instance as in
13.1836 +Example 1 above, however, it uses the dual simplex method, which starts
13.1837 +from the standard initial basis.
13.1838 +
13.1839 +\begin{footnotesize}
13.1840 +\begin{verbatim}
13.1841 +/* spxsamp2.c */
13.1842 +
13.1843 +#include <stdio.h>
13.1844 +#include <stdlib.h>
13.1845 +#include <glpk.h>
13.1846 +
13.1847 +int main(void)
13.1848 +{ glp_prob *P;
13.1849 + glp_smcp parm;
13.1850 + P = glp_create_prob();
13.1851 + glp_read_mps(P, GLP_MPS_DECK, NULL, "25fv47.mps");
13.1852 + glp_init_smcp(&parm);
13.1853 + parm.meth = GLP_DUAL;
13.1854 + glp_simplex(P, &parm);
13.1855 + glp_print_sol(P, "25fv47.txt");
13.1856 + glp_delete_prob(P);
13.1857 + return 0;
13.1858 +}
13.1859 +
13.1860 +/* eof */
13.1861 +\end{verbatim}
13.1862 +\end{footnotesize}
13.1863 +
13.1864 +\noindent
13.1865 +Below here is shown the terminal output from this example program.
13.1866 +
13.1867 +\begin{footnotesize}
13.1868 +\begin{verbatim}
13.1869 +Reading problem data from `25fv47.mps'...
13.1870 +Problem: 25FV47
13.1871 +Objective: R0000
13.1872 +822 rows, 1571 columns, 11127 non-zeros
13.1873 +6919 records were read
13.1874 + 0: infeas = 1.223e+03 (516)
13.1875 + 200: infeas = 7.000e+00 (471)
13.1876 + 240: infeas = 1.106e-14 (461)
13.1877 +| 400: obj = -5.394267152e+03 infeas = 5.571e-16 (391)
13.1878 +| 600: obj = -4.586395752e+03 infeas = 1.389e-15 (340)
13.1879 +| 800: obj = -4.158268146e+03 infeas = 1.640e-15 (264)
13.1880 +| 1000: obj = -3.725320045e+03 infeas = 5.181e-15 (245)
13.1881 +| 1200: obj = -3.104802163e+03 infeas = 1.019e-14 (210)
13.1882 +| 1400: obj = -2.584190499e+03 infeas = 8.865e-15 (178)
13.1883 +| 1600: obj = -2.073852927e+03 infeas = 7.867e-15 (142)
13.1884 +| 1800: obj = -1.164037407e+03 infeas = 8.792e-15 (109)
13.1885 +| 2000: obj = -4.370590250e+02 infeas = 2.591e-14 (85)
13.1886 +| 2200: obj = 1.068240144e+03 infeas = 1.025e-13 (70)
13.1887 +| 2400: obj = 1.607481126e+03 infeas = 3.272e-14 (67)
13.1888 +| 2600: obj = 3.038230551e+03 infeas = 4.850e-14 (52)
13.1889 +| 2800: obj = 4.316238187e+03 infeas = 2.622e-14 (36)
13.1890 +| 3000: obj = 5.443842629e+03 infeas = 3.976e-15 (11)
13.1891 +| 3060: obj = 5.501845888e+03 infeas = 8.806e-15 (2)
13.1892 +OPTIMAL SOLUTION FOUND
13.1893 +Writing basic solution to `25fv47.txt'...
13.1894 +\end{verbatim}
13.1895 +\end{footnotesize}
13.1896 +
13.1897 +\subsection{glp\_exact---solve LP problem in exact arithmetic}
13.1898 +
13.1899 +\subsubsection*{Synopsis}
13.1900 +
13.1901 +\begin{verbatim}
13.1902 +int glp_exact(glp_prob *lp, const glp_smcp *parm);
13.1903 +\end{verbatim}
13.1904 +
13.1905 +\subsubsection*{Description}
13.1906 +
13.1907 +The routine \verb|glp_exact| is a tentative implementation of the
13.1908 +primal two-phase simplex method based on exact (rational) arithmetic.
13.1909 +It is similar to the routine \verb|glp_simplex|, however, for all
13.1910 +internal computations it uses arithmetic of rational numbers, which is
13.1911 +exact in mathematical sense, i.e. free of round-off errors unlike
13.1912 +floating-point arithmetic.
13.1913 +
13.1914 +Note that the routine \verb|glp_exact| uses only two control parameters
13.1915 +passed in the structure \verb|glp_smcp|, namely, \verb|it_lim| and
13.1916 +\verb|tm_lim|.
13.1917 +
13.1918 +\subsubsection*{Returns}
13.1919 +
13.1920 +\def\arraystretch{1}
13.1921 +
13.1922 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
13.1923 +0 & The LP problem instance has been successfully solved. (This code
13.1924 +does {\it not} necessarily mean that the solver has found optimal
13.1925 +solution. It only means that the solution process was successful.) \\
13.1926 +\verb|GLP_EBADB| & Unable to start the search, because the initial basis
13.1927 +specified in the problem object is invalid---the number of basic
13.1928 +(auxiliary and structural) variables is not the same as the number of
13.1929 +rows in the problem object.\\
13.1930 +\verb|GLP_ESING| & Unable to start the search, because the basis matrix
13.1931 +corresponding to the initial basis is exactly singular.\\
13.1932 +\verb|GLP_EBOUND| & Unable to start the search, because some
13.1933 +double-bounded (auxiliary or structural) variables have incorrect
13.1934 +bounds.\\
13.1935 +\verb|GLP_EFAIL| & The problem instance has no rows/columns.\\
13.1936 +\verb|GLP_EITLIM| & The search was prematurely terminated, because the
13.1937 +simplex iteration limit has been exceeded.\\
13.1938 +\verb|GLP_ETMLIM| & The search was prematurely terminated, because the
13.1939 +time limit has been exceeded.\\
13.1940 +\end{tabular}
13.1941 +
13.1942 +\subsubsection*{Comments}
13.1943 +
13.1944 +Computations in exact arithmetic are very time consuming, so solving
13.1945 +LP problem with the routine \verb|glp_exact| from the very beginning is
13.1946 +not a good idea. It is much better at first to find an optimal basis
13.1947 +with the routine \verb|glp_simplex| and only then to call
13.1948 +\verb|glp_exact|, in which case only a few simplex iterations need to
13.1949 +be performed in exact arithmetic.
13.1950 +
13.1951 +\subsection{glp\_init\_smcp---initialize simplex solver control
13.1952 +parameters}
13.1953 +
13.1954 +\subsubsection*{Synopsis}
13.1955 +
13.1956 +\begin{verbatim}
13.1957 +int glp_init_smcp(glp_smcp *parm);
13.1958 +\end{verbatim}
13.1959 +
13.1960 +\subsubsection*{Description}
13.1961 +
13.1962 +The routine \verb|glp_init_smcp| initializes control parameters, which
13.1963 +are used by the simplex solver, with default values.
13.1964 +
13.1965 +Default values of the control parameters are stored in a \verb|glp_smcp|
13.1966 +structure, which the parameter \verb|parm| points to.
13.1967 +
13.1968 +\subsection{glp\_get\_status---determine generic status of basic
13.1969 +solution}
13.1970 +
13.1971 +\subsubsection*{Synopsis}
13.1972 +
13.1973 +\begin{verbatim}
13.1974 +int glp_get_status(glp_prob *lp);
13.1975 +\end{verbatim}
13.1976 +
13.1977 +\subsubsection*{Returns}
13.1978 +
13.1979 +The routine \verb|glp_get_status| reports the generic status of the
13.1980 +current basic solution for the specified problem object as follows:
13.1981 +
13.1982 +\begin{tabular}{@{}ll}
13.1983 +\verb|GLP_OPT| & solution is optimal; \\
13.1984 +\verb|GLP_FEAS| & solution is feasible; \\
13.1985 +\verb|GLP_INFEAS| & solution is infeasible; \\
13.1986 +\verb|GLP_NOFEAS| & problem has no feasible solution; \\
13.1987 +\verb|GLP_UNBND| & problem has unbounded solution; \\
13.1988 +\verb|GLP_UNDEF| & solution is undefined. \\
13.1989 +\end{tabular}
13.1990 +
13.1991 +More detailed information about the status of basic solution can be
13.1992 +retrieved with the routines \verb|glp_get_prim_stat| and
13.1993 +\verb|glp_get_dual_stat|.
13.1994 +
13.1995 +\newpage
13.1996 +
13.1997 +\subsection{glp\_get\_prim\_stat---retrieve status of primal basic
13.1998 +solution}
13.1999 +
13.2000 +\subsubsection*{Synopsis}
13.2001 +
13.2002 +\begin{verbatim}
13.2003 +int glp_get_prim_stat(glp_prob *lp);
13.2004 +\end{verbatim}
13.2005 +
13.2006 +\subsubsection*{Returns}
13.2007 +
13.2008 +The routine \verb|glp_get_prim_stat| reports the status of the primal
13.2009 +basic solution for the specified problem object as follows:
13.2010 +
13.2011 +\begin{tabular}{@{}ll}
13.2012 +\verb|GLP_UNDEF| & primal solution is undefined; \\
13.2013 +\verb|GLP_FEAS| & primal solution is feasible; \\
13.2014 +\verb|GLP_INFEAS| & primal solution is infeasible; \\
13.2015 +\verb|GLP_NOFEAS| & no primal feasible solution exists. \\
13.2016 +\end{tabular}
13.2017 +
13.2018 +\subsection{glp\_get\_dual\_stat---retrieve status of dual basic
13.2019 +solution}
13.2020 +
13.2021 +\subsubsection*{Synopsis}
13.2022 +
13.2023 +\begin{verbatim}
13.2024 +int glp_get_dual_stat(glp_prob *lp);
13.2025 +\end{verbatim}
13.2026 +
13.2027 +\subsubsection*{Returns}
13.2028 +
13.2029 +The routine \verb|glp_get_dual_stat| reports the status of the dual
13.2030 +basic solution for the specified problem object as follows:
13.2031 +
13.2032 +\begin{tabular}{@{}ll}
13.2033 +\verb|GLP_UNDEF| & dual solution is undefined; \\
13.2034 +\verb|GLP_FEAS| & dual solution is feasible; \\
13.2035 +\verb|GLP_INFEAS| & dual solution is infeasible; \\
13.2036 +\verb|GLP_NOFEAS| & no dual feasible solution exists. \\
13.2037 +\end{tabular}
13.2038 +
13.2039 +\subsection{glp\_get\_obj\_val---retrieve objective value}
13.2040 +
13.2041 +\subsubsection*{Synopsis}
13.2042 +
13.2043 +\begin{verbatim}
13.2044 +double glp_get_obj_val(glp_prob *lp);
13.2045 +\end{verbatim}
13.2046 +
13.2047 +\subsubsection*{Returns}
13.2048 +
13.2049 +The routine \verb|glp_get_obj_val| returns current value of the
13.2050 +objective function.
13.2051 +
13.2052 +\subsection{glp\_get\_row\_stat---retrieve row status}
13.2053 +
13.2054 +\subsubsection*{Synopsis}
13.2055 +
13.2056 +\begin{verbatim}
13.2057 +int glp_get_row_stat(glp_prob *lp, int i);
13.2058 +\end{verbatim}
13.2059 +
13.2060 +\subsubsection*{Returns}
13.2061 +
13.2062 +The routine \verb|glp_get_row_stat| returns current status assigned to
13.2063 +the auxiliary variable associated with \verb|i|-th row as follows:
13.2064 +
13.2065 +\begin{tabular}{@{}ll}
13.2066 +\verb|GLP_BS| & basic variable; \\
13.2067 +\verb|GLP_NL| & non-basic variable on its lower bound; \\
13.2068 +\verb|GLP_NU| & non-basic variable on its upper bound; \\
13.2069 +\verb|GLP_NF| & non-basic free (unbounded) variable; \\
13.2070 +\verb|GLP_NS| & non-basic fixed variable. \\
13.2071 +\end{tabular}
13.2072 +
13.2073 +\subsection{glp\_get\_row\_prim---retrieve row primal value}
13.2074 +
13.2075 +\subsubsection*{Synopsis}
13.2076 +
13.2077 +\begin{verbatim}
13.2078 +double glp_get_row_prim(glp_prob *lp, int i);
13.2079 +\end{verbatim}
13.2080 +
13.2081 +\subsubsection*{Returns}
13.2082 +
13.2083 +The routine \verb|glp_get_row_prim| returns primal value of the
13.2084 +auxiliary variable associated with \verb|i|-th row.
13.2085 +
13.2086 +\subsection{glp\_get\_row\_dual---retrieve row dual value}
13.2087 +
13.2088 +\subsubsection*{Synopsis}
13.2089 +
13.2090 +\begin{verbatim}
13.2091 +double glp_get_row_dual(glp_prob *lp, int i);
13.2092 +\end{verbatim}
13.2093 +
13.2094 +\subsubsection*{Returns}
13.2095 +
13.2096 +The routine \verb|glp_get_row_dual| returns dual value (i.e. reduced
13.2097 +cost) of the auxiliary variable associated with \verb|i|-th row.
13.2098 +
13.2099 +\newpage
13.2100 +
13.2101 +\subsection{glp\_get\_col\_stat---retrieve column status}
13.2102 +
13.2103 +\subsubsection*{Synopsis}
13.2104 +
13.2105 +\begin{verbatim}
13.2106 +int glp_get_col_stat(glp_prob *lp, int j);
13.2107 +\end{verbatim}
13.2108 +
13.2109 +\subsubsection*{Returns}
13.2110 +
13.2111 +The routine \verb|glp_get_col_stat| returns current status assigned to
13.2112 +the structural variable associated with \verb|j|-th column as follows:
13.2113 +
13.2114 +\begin{tabular}{@{}ll}
13.2115 +\verb|GLP_BS| & basic variable; \\
13.2116 +\verb|GLP_NL| & non-basic variable on its lower bound; \\
13.2117 +\verb|GLP_NU| & non-basic variable on its upper bound; \\
13.2118 +\verb|GLP_NF| & non-basic free (unbounded) variable; \\
13.2119 +\verb|GLP_NS| & non-basic fixed variable. \\
13.2120 +\end{tabular}
13.2121 +
13.2122 +\subsection{glp\_get\_col\_prim---retrieve column primal value}
13.2123 +
13.2124 +\subsubsection*{Synopsis}
13.2125 +
13.2126 +\begin{verbatim}
13.2127 +double glp_get_col_prim(glp_prob *lp, int j);
13.2128 +\end{verbatim}
13.2129 +
13.2130 +\subsubsection*{Returns}
13.2131 +
13.2132 +The routine \verb|glp_get_col_prim| returns primal value of the
13.2133 +structural variable associated with \verb|j|-th column.
13.2134 +
13.2135 +\subsection{glp\_get\_col\_dual---retrieve column dual value}
13.2136 +
13.2137 +\subsubsection*{Synopsis}
13.2138 +
13.2139 +\begin{verbatim}
13.2140 +double glp_get_col_dual(glp_prob *lp, int j);
13.2141 +\end{verbatim}
13.2142 +
13.2143 +\subsubsection*{Returns}
13.2144 +
13.2145 +The routine \verb|glp_get_col_dual| returns dual value (i.e. reduced
13.2146 +cost) of the structural variable associated with \verb|j|-th column.
13.2147 +
13.2148 +\newpage
13.2149 +
13.2150 +\subsection{glp\_get\_unbnd\_ray---determine variable causing\\
13.2151 +unboundedness}
13.2152 +
13.2153 +\subsubsection*{Synopsis}
13.2154 +
13.2155 +\begin{verbatim}
13.2156 +int glp_get_unbnd_ray(glp_prob *lp);
13.2157 +\end{verbatim}
13.2158 +
13.2159 +\subsubsection*{Returns}
13.2160 +
13.2161 +The routine \verb|glp_get_unbnd_ray| returns the number $k$ of
13.2162 +a variable, which causes primal or dual unboundedness.
13.2163 +If $1\leq k\leq m$, it is $k$-th auxiliary variable, and if
13.2164 +$m+1\leq k\leq m+n$, it is $(k-m)$-th structural variable, where $m$ is
13.2165 +the number of rows, $n$ is the number of columns in the problem object.
13.2166 +If such variable is not defined, the routine returns 0.
13.2167 +
13.2168 +\subsubsection*{Comments}
13.2169 +
13.2170 +If it is not exactly known which version of the simplex solver
13.2171 +detected unboundedness, i.e. whether the unboundedness is primal or
13.2172 +dual, it is sufficient to check the status of the variable
13.2173 +with the routine \verb|glp_get_row_stat| or \verb|glp_get_col_stat|.
13.2174 +If the variable is non-basic, the unboundedness is primal, otherwise,
13.2175 +if the variable is basic, the unboundedness is dual (the latter case
13.2176 +means that the problem has no primal feasible dolution).
13.2177 +
13.2178 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13.2179 +
13.2180 +\newpage
13.2181 +
13.2182 +\section{Interior-point method routines}
13.2183 +
13.2184 +{\it Interior-point methods} (also known as {\it barrier methods}) are
13.2185 +more modern and powerful numerical methods for large-scale linear
13.2186 +programming. Such methods are especially efficient for very sparse LP
13.2187 +problems and allow solving such problems much faster than the simplex
13.2188 +method.
13.2189 +
13.2190 +In brief, the GLPK interior-point solver works as follows.
13.2191 +
13.2192 +At first, the solver transforms the original LP to a {\it working} LP
13.2193 +in the standard format:
13.2194 +
13.2195 +\medskip
13.2196 +
13.2197 +\noindent
13.2198 +\hspace{.5in} minimize
13.2199 +$$z = c_1x_{m+1} + c_2x_{m+2} + \dots + c_nx_{m+n} + c_0 \eqno (2.4)$$
13.2200 +\hspace{.5in} subject to linear constraints
13.2201 +$$
13.2202 +\begin{array}{r@{\:}c@{\:}r@{\:}c@{\:}r@{\:}c@{\:}l}
13.2203 +a_{11}x_{m+1}&+&a_{12}x_{m+2}&+ \dots +&a_{1n}x_{m+n}&=&b_1 \\
13.2204 +a_{21}x_{m+1}&+&a_{22}x_{m+2}&+ \dots +&a_{2n}x_{m+n}&=&b_2 \\
13.2205 +\multicolumn{7}{c}
13.2206 +{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .} \\
13.2207 +a_{m1}x_{m+1}&+&a_{m2}x_{m+2}&+ \dots +&a_{mn}x_{m+n}&=&b_m \\
13.2208 +\end{array} \eqno (2.5)
13.2209 +$$
13.2210 +\hspace{.5in} and non-negative variables
13.2211 +$$x_1\geq 0,\ \ x_2\geq 0,\ \ \dots,\ \ x_n\geq 0 \eqno(2.6)$$
13.2212 +where: $z$ is the objective function; $x_1$, \dots, $x_n$ are variables;
13.2213 +$c_1$, \dots, $c_n$ are objective coefficients; $c_0$ is a constant term
13.2214 +of the objective function;\linebreak $a_{11}$, \dots, $a_{mn}$ are
13.2215 +constraint coefficients; $b_1$, \dots, $b_m$ are right-hand sides.
13.2216 +
13.2217 +Using vector and matrix notations the working LP (2.4)---(2.6) can be
13.2218 +written as follows:
13.2219 +$$z=c^Tx+c_0\ \rightarrow\ \min,\eqno(2.7)$$
13.2220 +$$Ax=b,\eqno(2.8)$$
13.2221 +$$x\geq 0,\eqno(2.9)$$
13.2222 +where: $x=(x_j)$ is $n$-vector of variables, $c=(c_j)$ is $n$-vector of
13.2223 +objective coefficients, $A=(a_{ij})$ is $m\times n$-matrix of
13.2224 +constraint coefficients, and $b=(b_i)$ is $m$-vector of right-hand
13.2225 +sides.
13.2226 +
13.2227 +Karush--Kuhn--Tucker optimality conditions for LP (2.7)---(2.9) are the
13.2228 +following:
13.2229 +
13.2230 +\newpage
13.2231 +
13.2232 +$$Ax=b,\eqno(2.10)$$
13.2233 +$$A^T\pi+\lambda=c,\eqno(2.11)$$
13.2234 +$$\lambda^Tx=0,\eqno(2.12)$$
13.2235 +$$x\geq 0,\ \ \lambda\geq 0,\eqno(2.13)$$
13.2236 +where: $\pi$ is $m$-vector of Lagrange multipliers (dual variables) for
13.2237 +equality constraints (2.8), $\lambda$ is $n$-vector of Lagrange
13.2238 +multipliers (dual variables) for non-negativity constraints (2.9),
13.2239 +(2.10) is the primal feasibility condition, (2.11) is the dual
13.2240 +feasibility condition, (2.12) is the primal-dual complementarity
13.2241 +condition, and (2.13) is the non-negativity conditions.
13.2242 +
13.2243 +The main idea of the primal-dual interior-point method is based on
13.2244 +finding a point in the primal-dual space (i.e. in the space of all
13.2245 +primal and dual variables $x$, $\pi$, and $\lambda$), which satisfies
13.2246 +to all optimality conditions (2.10)---(2.13). Obviously, $x$-component
13.2247 +of such point then provides an optimal solution to the working LP
13.2248 +(2.7)---(2.9).
13.2249 +
13.2250 +To find the optimal point $(x^*,\pi^*,\lambda^*)$ the interior-point
13.2251 +method attempts to solve the system of equations (2.10)---(2.12), which
13.2252 +is closed in the sense that the number of variables $x_j$, $\pi_i$, and
13.2253 +$\lambda_j$ and the number equations are the same and equal to $m+2n$.
13.2254 +Due to condition (2.12) this system of equations is non-linear, so it
13.2255 +can be solved with a version of {\it Newton's method} provided with
13.2256 +additional rules to keep the current point within the positive orthant
13.2257 +as required by the non-negativity conditions (2.13).
13.2258 +
13.2259 +Finally, once the optimal point $(x^*,\pi^*,\lambda^*)$ has been found,
13.2260 +the solver performs inverse transformations to recover corresponding
13.2261 +solution to the original LP passed to the solver from the application
13.2262 +program.
13.2263 +
13.2264 +\subsection{glp\_interior---solve LP problem with the interior-point
13.2265 +method}
13.2266 +
13.2267 +\subsubsection*{Synopsis}
13.2268 +
13.2269 +\begin{verbatim}
13.2270 +int glp_interior(glp_prob *P, const glp_iptcp *parm);
13.2271 +\end{verbatim}
13.2272 +
13.2273 +\subsubsection*{Description}
13.2274 +
13.2275 +The routine \verb|glp_interior| is a driver to the LP solver based on
13.2276 +the primal-dual interior-point method. This routine retrieves problem
13.2277 +data from the specified problem object, calls the solver to solve the
13.2278 +problem instance, and stores results of computations back into the
13.2279 +problem object.
13.2280 +
13.2281 +The interior-point solver has a set of control parameters. Values of
13.2282 +the control parameters can be passed in the structure \verb|glp_iptcp|,
13.2283 +which the parameter \verb|parm| points to. For detailed description of
13.2284 +this structure see paragraph ``Control parameters'' below. Before
13.2285 +specifying some control parameters the application program should
13.2286 +initialize the structure \verb|glp_iptcp| by default values of all
13.2287 +control parameters using the routine \verb|glp_init_iptcp| (see the
13.2288 +next subsection). This is needed for backward compatibility, because in
13.2289 +the future there may appear new members in the structure
13.2290 +\verb|glp_iptcp|.
13.2291 +
13.2292 +The parameter \verb|parm| can be specified as \verb|NULL|, in which
13.2293 +case the solver uses default settings.
13.2294 +
13.2295 +\subsubsection*{Returns}
13.2296 +
13.2297 +\def\arraystretch{1}
13.2298 +
13.2299 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
13.2300 +0 & The LP problem instance has been successfully solved. (This code
13.2301 +does {\it not} necessarily mean that the solver has found optimal
13.2302 +solution. It only means that the solution process was successful.) \\
13.2303 +\verb|GLP_EFAIL| & The problem has no rows/columns.\\
13.2304 +\verb|GLP_ENOCVG| & Very slow convergence or divergence.\\
13.2305 +\verb|GLP_EITLIM| & Iteration limit exceeded.\\
13.2306 +\verb|GLP_EINSTAB| & Numerical instability on solving Newtonian
13.2307 +system.\\
13.2308 +\end{tabular}
13.2309 +
13.2310 +\subsubsection*{Comments}
13.2311 +
13.2312 +The routine \verb|glp_interior| implements an easy version of
13.2313 +the primal-dual interior-point method based on Mehrotra's
13.2314 +technique.\footnote{S. Mehrotra. On the implementation of a primal-dual
13.2315 +interior point method. SIAM J. on Optim., 2(4), pp. 575-601, 1992.}
13.2316 +
13.2317 +Note that currently the GLPK interior-point solver does not include
13.2318 +many important features, in particular:
13.2319 +
13.2320 +$\bullet$ it is not able to process dense columns. Thus, if the
13.2321 +constraint matrix of the LP problem has dense columns, the solving
13.2322 +process may be inefficient;
13.2323 +
13.2324 +$\bullet$ it has no features against numerical instability. For some
13.2325 +LP problems premature termination may happen if the matrix $ADA^T$
13.2326 +becomes singular or ill-conditioned;
13.2327 +
13.2328 +$\bullet$ it is not able to identify the optimal basis, which
13.2329 +corresponds to the interior-point solution found.
13.2330 +
13.2331 +\newpage
13.2332 +
13.2333 +\subsubsection*{Terminal output}
13.2334 +
13.2335 +Solving large LP problems may take a long time, so the solver reports
13.2336 +some information about every interior-point iteration,\footnote{Unlike
13.2337 +the simplex method the interior point method usually needs 30---50
13.2338 +iterations (independently on the problem size) in order to find an
13.2339 +optimal solution.} which is sent to the terminal. This information has
13.2340 +the following format:
13.2341 +
13.2342 +\begin{verbatim}
13.2343 +nnn: obj = fff; rpi = ppp; rdi = ddd; gap = ggg
13.2344 +\end{verbatim}
13.2345 +
13.2346 +\noindent where: \verb|nnn| is iteration number, \verb|fff| is the
13.2347 +current value of the objective function (in the case of maximization it
13.2348 +has wrong sign), \verb|ppp| is the current relative primal
13.2349 +infeasibility (cf. (2.10)):
13.2350 +$$\frac{\|Ax^{(k)}-b\|}{1+\|b\|},\eqno(2.14)$$
13.2351 +\verb|ddd| is the current relative dual infeasibility (cf. (2.11)):
13.2352 +$$\frac{\|A^T\pi^{(k)}+\lambda^{(k)}-c\|}{1+\|c\|},\eqno(2.15)$$
13.2353 +\verb|ggg| is the current primal-dual gap (cf. (2.12)):
13.2354 +$$\frac{|c^Tx^{(k)}-b^T\pi^{(k)}|}{1+|c^Tx^{(k)}|},\eqno(2.16)$$
13.2355 +and $[x^{(k)},\pi^{(k)},\lambda^{(k)}]$ is the current point on $k$-th
13.2356 +iteration, $k=0,1,2,\dots$\ . Note that all solution components are
13.2357 +internally scaled, so information sent to the terminal is suitable only
13.2358 +for visual inspection.
13.2359 +
13.2360 +\subsubsection*{Control parameters}
13.2361 +
13.2362 +This paragraph describes all control parameters currently used in the
13.2363 +interior-point solver. Symbolic names of control parameters are names of
13.2364 +corresponding members in the structure \verb|glp_iptcp|.
13.2365 +
13.2366 +\medskip
13.2367 +
13.2368 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2369 +\multicolumn{2}{@{}l}{{\tt int msg\_lev} (default: {\tt GLP\_MSG\_ALL})}
13.2370 +\\
13.2371 +&Message level for terminal output:\\
13.2372 +&\verb|GLP_MSG_OFF|---no output;\\
13.2373 +&\verb|GLP_MSG_ERR|---error and warning messages only;\\
13.2374 +&\verb|GLP_MSG_ON |---normal output;\\
13.2375 +&\verb|GLP_MSG_ALL|---full output (including informational messages).
13.2376 +\\
13.2377 +\end{tabular}
13.2378 +
13.2379 +\medskip
13.2380 +
13.2381 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2382 +\multicolumn{2}{@{}l}{{\tt int ord\_alg} (default: {\tt GLP\_ORD\_AMD})}
13.2383 +\\
13.2384 +&Ordering algorithm used prior to Cholesky factorization:\\
13.2385 +&\verb|GLP_ORD_NONE |---use natural (original) ordering;\\
13.2386 +&\verb|GLP_ORD_QMD |---quotient minimum degree (QMD);\\
13.2387 +&\verb|GLP_ORD_AMD |---approximate minimum degree (AMD);\\
13.2388 +&\verb|GLP_ORD_SYMAMD|---approximate minimum degree (SYMAMD).\\
13.2389 +\end{tabular}
13.2390 +
13.2391 +\subsubsection*{Example}
13.2392 +
13.2393 +The following main program reads LP problem instance in fixed MPS
13.2394 +format from file \verb|25fv47.mps|,\footnote{This instance in fixed MPS
13.2395 +format can be found in the Netlib LP collection; see
13.2396 +{\tt ftp://ftp.netlib.org/lp/data/}.} solves it with the interior-point
13.2397 +solver, and writes the solution to file \verb|25fv47.txt|.
13.2398 +
13.2399 +\begin{footnotesize}
13.2400 +\begin{verbatim}
13.2401 +/* iptsamp.c */
13.2402 +
13.2403 +#include <stdio.h>
13.2404 +#include <stdlib.h>
13.2405 +#include <glpk.h>
13.2406 +
13.2407 +int main(void)
13.2408 +{ glp_prob *P;
13.2409 + P = glp_create_prob();
13.2410 + glp_read_mps(P, GLP_MPS_DECK, NULL, "25fv47.mps");
13.2411 + glp_interior(P, NULL);
13.2412 + glp_print_ipt(P, "25fv47.txt");
13.2413 + glp_delete_prob(P);
13.2414 + return 0;
13.2415 +}
13.2416 +
13.2417 +/* eof */
13.2418 +\end{verbatim}
13.2419 +\end{footnotesize}
13.2420 +
13.2421 +\noindent
13.2422 +Below here is shown the terminal output from this example program.
13.2423 +
13.2424 +\begin{footnotesize}
13.2425 +\begin{verbatim}
13.2426 +Reading problem data from `25fv47.mps'...
13.2427 +Problem: 25FV47
13.2428 +Objective: R0000
13.2429 +822 rows, 1571 columns, 11127 non-zeros
13.2430 +6919 records were read
13.2431 +Original LP has 822 row(s), 1571 column(s), and 11127 non-zero(s)
13.2432 +Working LP has 821 row(s), 1876 column(s), and 10705 non-zero(s)
13.2433 +Matrix A has 10705 non-zeros
13.2434 +Matrix S = A*A' has 11895 non-zeros (upper triangle)
13.2435 +Minimal degree ordering...
13.2436 +Computing Cholesky factorization S = L'*L...
13.2437 +Matrix L has 35411 non-zeros
13.2438 +Guessing initial point...
13.2439 +Optimization begins...
13.2440 + 0: obj = 1.823377629e+05; rpi = 1.3e+01; rdi = 1.4e+01; gap = 9.3e-01
13.2441 + 1: obj = 9.260045192e+04; rpi = 5.3e+00; rdi = 5.6e+00; gap = 6.8e+00
13.2442 + 2: obj = 3.596999742e+04; rpi = 1.5e+00; rdi = 1.2e+00; gap = 1.8e+01
13.2443 + 3: obj = 1.989627568e+04; rpi = 4.7e-01; rdi = 3.0e-01; gap = 1.9e+01
13.2444 + 4: obj = 1.430215557e+04; rpi = 1.1e-01; rdi = 8.6e-02; gap = 1.4e+01
13.2445 + 5: obj = 1.155716505e+04; rpi = 2.3e-02; rdi = 2.4e-02; gap = 6.8e+00
13.2446 + 6: obj = 9.660273208e+03; rpi = 6.7e-03; rdi = 4.6e-03; gap = 3.9e+00
13.2447 + 7: obj = 8.694348283e+03; rpi = 3.7e-03; rdi = 1.7e-03; gap = 2.0e+00
13.2448 + 8: obj = 8.019543639e+03; rpi = 2.4e-03; rdi = 3.9e-04; gap = 1.0e+00
13.2449 + 9: obj = 7.122676293e+03; rpi = 1.2e-03; rdi = 1.5e-04; gap = 6.6e-01
13.2450 + 10: obj = 6.514534518e+03; rpi = 6.1e-04; rdi = 4.3e-05; gap = 4.1e-01
13.2451 + 11: obj = 6.361572203e+03; rpi = 4.8e-04; rdi = 2.2e-05; gap = 3.0e-01
13.2452 + 12: obj = 6.203355508e+03; rpi = 3.2e-04; rdi = 1.7e-05; gap = 2.6e-01
13.2453 + 13: obj = 6.032943411e+03; rpi = 2.0e-04; rdi = 9.3e-06; gap = 2.1e-01
13.2454 + 14: obj = 5.796553021e+03; rpi = 9.8e-05; rdi = 3.2e-06; gap = 1.0e-01
13.2455 + 15: obj = 5.667032431e+03; rpi = 4.4e-05; rdi = 1.1e-06; gap = 5.6e-02
13.2456 + 16: obj = 5.613911867e+03; rpi = 2.5e-05; rdi = 4.1e-07; gap = 3.5e-02
13.2457 + 17: obj = 5.560572626e+03; rpi = 9.9e-06; rdi = 2.3e-07; gap = 2.1e-02
13.2458 + 18: obj = 5.537276001e+03; rpi = 5.5e-06; rdi = 8.4e-08; gap = 1.1e-02
13.2459 + 19: obj = 5.522746942e+03; rpi = 2.2e-06; rdi = 4.0e-08; gap = 6.7e-03
13.2460 + 20: obj = 5.509956679e+03; rpi = 7.5e-07; rdi = 1.8e-08; gap = 2.9e-03
13.2461 + 21: obj = 5.504571733e+03; rpi = 1.6e-07; rdi = 5.8e-09; gap = 1.1e-03
13.2462 + 22: obj = 5.502576367e+03; rpi = 3.4e-08; rdi = 1.0e-09; gap = 2.5e-04
13.2463 + 23: obj = 5.502057119e+03; rpi = 8.1e-09; rdi = 3.0e-10; gap = 7.7e-05
13.2464 + 24: obj = 5.501885996e+03; rpi = 9.4e-10; rdi = 1.2e-10; gap = 2.4e-05
13.2465 + 25: obj = 5.501852464e+03; rpi = 1.4e-10; rdi = 1.2e-11; gap = 3.0e-06
13.2466 + 26: obj = 5.501846549e+03; rpi = 1.4e-11; rdi = 1.2e-12; gap = 3.0e-07
13.2467 + 27: obj = 5.501845954e+03; rpi = 1.4e-12; rdi = 1.2e-13; gap = 3.0e-08
13.2468 + 28: obj = 5.501845895e+03; rpi = 1.5e-13; rdi = 1.2e-14; gap = 3.0e-09
13.2469 +OPTIMAL SOLUTION FOUND
13.2470 +Writing interior-point solution to `25fv47.txt'...
13.2471 +\end{verbatim}
13.2472 +\end{footnotesize}
13.2473 +
13.2474 +\subsection{glp\_init\_iptcp---initialize interior-point solver control
13.2475 +parameters}
13.2476 +
13.2477 +\subsubsection*{Synopsis}
13.2478 +
13.2479 +\begin{verbatim}
13.2480 +int glp_init_iptcp(glp_iptcp *parm);
13.2481 +\end{verbatim}
13.2482 +
13.2483 +\subsubsection*{Description}
13.2484 +
13.2485 +The routine \verb|glp_init_iptcp| initializes control parameters, which
13.2486 +are used by the interior-point solver, with default values.
13.2487 +
13.2488 +Default values of the control parameters are stored in the structure
13.2489 +\verb|glp_iptcp|, which the parameter \verb|parm| points to.
13.2490 +
13.2491 +\subsection{glp\_ipt\_status---determine solution status}
13.2492 +
13.2493 +\subsubsection*{Synopsis}
13.2494 +
13.2495 +\begin{verbatim}
13.2496 +int glp_ipt_status(glp_prob *lp);
13.2497 +\end{verbatim}
13.2498 +
13.2499 +\subsubsection*{Returns}
13.2500 +
13.2501 +The routine \verb|glp_ipt_status| reports the status of a solution
13.2502 +found by the interior-point solver as follows:
13.2503 +
13.2504 +\begin{tabular}{@{}p{25mm}p{91.3mm}@{}}
13.2505 +\verb|GLP_UNDEF| & interior-point solution is undefined. \\
13.2506 +\verb|GLP_OPT| & interior-point solution is optimal. \\
13.2507 +\verb|GLP_INFEAS|& interior-point solution is infeasible. \\
13.2508 +\verb|GLP_NOFEAS|& no feasible primal-dual solution exists.\\
13.2509 +\end{tabular}
13.2510 +
13.2511 +\subsection{glp\_ipt\_obj\_val---retrieve objective value}
13.2512 +
13.2513 +\subsubsection*{Synopsis}
13.2514 +
13.2515 +\begin{verbatim}
13.2516 +double glp_ipt_obj_val(glp_prob *lp);
13.2517 +\end{verbatim}
13.2518 +
13.2519 +\subsubsection*{Returns}
13.2520 +
13.2521 +The routine \verb|glp_ipt_obj_val| returns value of the objective
13.2522 +function for interior-point solution.
13.2523 +
13.2524 +\subsection{glp\_ipt\_row\_prim---retrieve row primal value}
13.2525 +
13.2526 +\subsubsection*{Synopsis}
13.2527 +
13.2528 +\begin{verbatim}
13.2529 +double glp_ipt_row_prim(glp_prob *lp, int i);
13.2530 +\end{verbatim}
13.2531 +
13.2532 +\subsubsection*{Returns}
13.2533 +
13.2534 +The routine \verb|glp_ipt_row_prim| returns primal value of the
13.2535 +auxiliary variable associated with \verb|i|-th row.
13.2536 +
13.2537 +\newpage
13.2538 +
13.2539 +\subsection{glp\_ipt\_row\_dual---retrieve row dual value}
13.2540 +
13.2541 +\subsubsection*{Synopsis}
13.2542 +
13.2543 +\begin{verbatim}
13.2544 +double glp_ipt_row_dual(glp_prob *lp, int i);
13.2545 +\end{verbatim}
13.2546 +
13.2547 +\subsubsection*{Returns}
13.2548 +
13.2549 +The routine \verb|glp_ipt_row_dual| returns dual value (i.e. reduced
13.2550 +cost) of the auxiliary variable associated with \verb|i|-th row.
13.2551 +
13.2552 +\subsection{glp\_ipt\_col\_prim---retrieve column primal value}
13.2553 +
13.2554 +\subsubsection*{Synopsis}
13.2555 +
13.2556 +\begin{verbatim}
13.2557 +double glp_ipt_col_prim(glp_prob *lp, int j);
13.2558 +\end{verbatim}
13.2559 +
13.2560 +\subsubsection*{Returns}
13.2561 +
13.2562 +The routine \verb|glp_ipt_col_prim| returns primal value of the
13.2563 +structural variable associated with \verb|j|-th column.
13.2564 +
13.2565 +\subsection{glp\_ipt\_col\_dual---retrieve column dual value}
13.2566 +
13.2567 +\subsubsection*{Synopsis}
13.2568 +
13.2569 +\begin{verbatim}
13.2570 +double glp_ipt_col_dual(glp_prob *lp, int j);
13.2571 +\end{verbatim}
13.2572 +
13.2573 +\subsubsection*{Returns}
13.2574 +
13.2575 +The routine \verb|glp_ipt_col_dual| returns dual value (i.e. reduced
13.2576 +cost) of the structural variable associated with \verb|j|-th column.
13.2577 +
13.2578 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13.2579 +
13.2580 +\newpage
13.2581 +
13.2582 +\section{Mixed integer programming routines}
13.2583 +
13.2584 +\subsection{glp\_set\_col\_kind---set (change) column kind}
13.2585 +
13.2586 +\subsubsection*{Synopsis}
13.2587 +
13.2588 +\begin{verbatim}
13.2589 +void glp_set_col_kind(glp_prob *mip, int j, int kind);
13.2590 +\end{verbatim}
13.2591 +
13.2592 +\subsubsection*{Description}
13.2593 +
13.2594 +The routine \verb|glp_set_col_kind| sets (changes) the kind of
13.2595 +\verb|j|-th column (structural variable) as specified by the parameter
13.2596 +\verb|kind|:
13.2597 +
13.2598 +\begin{tabular}{@{}ll}
13.2599 +\verb|GLP_CV| & continuous variable; \\
13.2600 +\verb|GLP_IV| & integer variable; \\
13.2601 +\verb|GLP_BV| & binary variable. \\
13.2602 +\end{tabular}
13.2603 +
13.2604 +%If a column is set to \verb|GLP_IV|, its bounds must be exact integer
13.2605 +%numbers with no tolerance, such that the condition
13.2606 +%\verb|bnd == floor(bnd)| would hold.
13.2607 +
13.2608 +Setting a column to \verb|GLP_BV| has the same effect as if it were
13.2609 +set to \verb|GLP_IV|, its lower bound were set 0, and its upper bound
13.2610 +were set to 1.
13.2611 +
13.2612 +\subsection{glp\_get\_col\_kind---retrieve column kind}
13.2613 +
13.2614 +\subsubsection*{Synopsis}
13.2615 +
13.2616 +\begin{verbatim}
13.2617 +int glp_get_col_kind(glp_prob *mip, int j);
13.2618 +\end{verbatim}
13.2619 +
13.2620 +\subsubsection*{Returns}
13.2621 +
13.2622 +The routine \verb|glp_get_col_kind| returns the kind of \verb|j|-th
13.2623 +column (structural variable) as follows:
13.2624 +
13.2625 +\begin{tabular}{@{}ll}
13.2626 +\verb|GLP_CV| & continuous variable; \\
13.2627 +\verb|GLP_IV| & integer variable; \\
13.2628 +\verb|GLP_BV| & binary variable. \\
13.2629 +\end{tabular}
13.2630 +
13.2631 +\subsection{glp\_get\_num\_int---retrieve number of integer columns}
13.2632 +
13.2633 +\subsubsection*{Synopsis}
13.2634 +
13.2635 +\begin{verbatim}
13.2636 +int glp_get_num_int(glp_prob *mip);
13.2637 +\end{verbatim}
13.2638 +
13.2639 +\subsubsection*{Returns}
13.2640 +
13.2641 +The routine \verb|glp_get_num_int| returns the number of columns
13.2642 +(structural variables), which are marked as integer. Note that this
13.2643 +number {\it does} include binary columns.
13.2644 +
13.2645 +\subsection{glp\_get\_num\_bin---retrieve number of binary columns}
13.2646 +
13.2647 +\subsubsection*{Synopsis}
13.2648 +
13.2649 +\begin{verbatim}
13.2650 +int glp_get_num_bin(glp_prob *mip);
13.2651 +\end{verbatim}
13.2652 +
13.2653 +\subsubsection*{Returns}
13.2654 +
13.2655 +The routine \verb|glp_get_num_bin| returns the number of columns
13.2656 +(structural variables), which are marked as integer and whose lower
13.2657 +bound is zero and upper bound is one.
13.2658 +
13.2659 +\subsection{glp\_intopt---solve MIP problem with the branch-and-cut
13.2660 +method}
13.2661 +
13.2662 +\subsubsection*{Synopsis}
13.2663 +
13.2664 +\begin{verbatim}
13.2665 +int glp_intopt(glp_prob *mip, const glp_iocp *parm);
13.2666 +\end{verbatim}
13.2667 +
13.2668 +\subsubsection*{Description}
13.2669 +
13.2670 +The routine \verb|glp_intopt| is a driver to the MIP solver based on
13.2671 +the branch-and-cut method, which is a hybrid of branch-and-bound and
13.2672 +cutting plane methods.
13.2673 +
13.2674 +If the presolver is disabled (see paragraph ``Control parameters''
13.2675 +below), on entry to the routine \verb|glp_intopt| the problem object,
13.2676 +which the parameter \verb|mip| points to, should contain optimal
13.2677 +solution to LP relaxation (it can be obtained, for example, with the
13.2678 +routine \verb|glp_simplex|). Otherwise, if the presolver is enabled, it
13.2679 +is not necessary.
13.2680 +
13.2681 +The MIP solver has a set of control parameters. Values of the control
13.2682 +parameters can be passed in the structure \verb|glp_iocp|, which the
13.2683 +parameter \verb|parm| points to. For detailed description of this
13.2684 +structure see paragraph ``Control parameters'' below. Before specifying
13.2685 +some control parameters the application program should initialize the
13.2686 +structure \verb|glp_iocp| by default values of all control parameters
13.2687 +using the routine \verb|glp_init_iocp| (see the next subsection). This
13.2688 +is needed for backward compatibility, because in the future there may
13.2689 +appear new members in the structure \verb|glp_iocp|.
13.2690 +
13.2691 +The parameter \verb|parm| can be specified as \verb|NULL|, in which case
13.2692 +the solver uses default settings.
13.2693 +
13.2694 +Note that the GLPK branch-and-cut solver is not perfect, so it is unable
13.2695 +to solve hard or very large scale MIP instances for a reasonable time.
13.2696 +
13.2697 +\subsubsection*{Returns}
13.2698 +
13.2699 +\def\arraystretch{1}
13.2700 +
13.2701 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
13.2702 +0 & The MIP problem instance has been successfully solved. (This code
13.2703 +does {\it not} necessarily mean that the solver has found optimal
13.2704 +solution. It only means that the solution process was successful.) \\
13.2705 +\verb|GLP_EBOUND| & Unable to start the search, because some
13.2706 +double-bounded variables have incorrect bounds or some integer variables
13.2707 +have non-integer (fractional) bounds.\\
13.2708 +\verb|GLP_EROOT| & Unable to start the search, because optimal basis for
13.2709 +initial LP relaxation is not provided. (This code may appear only if the
13.2710 +presolver is disabled.)\\
13.2711 +\verb|GLP_ENOPFS| & Unable to start the search, because LP relaxation
13.2712 +of the MIP problem instance has no primal feasible solution. (This code
13.2713 +may appear only if the presolver is enabled.)\\
13.2714 +\verb|GLP_ENODFS| & Unable to start the search, because LP relaxation
13.2715 +of the MIP problem instance has no dual feasible solution. In other
13.2716 +word, this code means that if the LP relaxation has at least one primal
13.2717 +feasible solution, its optimal solution is unbounded, so if the MIP
13.2718 +problem has at least one integer feasible solution, its (integer)
13.2719 +optimal solution is also unbounded. (This code may appear only if the
13.2720 +presolver is enabled.)\\
13.2721 +\verb|GLP_EFAIL| & The search was prematurely terminated due to the
13.2722 +solver failure.\\
13.2723 +\verb|GLP_EMIPGAP| & The search was prematurely terminated, because the
13.2724 +relative mip gap tolerance has been reached.\\
13.2725 +\verb|GLP_ETMLIM| & The search was prematurely terminated, because the
13.2726 +time limit has been exceeded.\\
13.2727 +\verb|GLP_ESTOP| & The search was prematurely terminated by application.
13.2728 +(This code may appear only if the advanced solver interface is used.)\\
13.2729 +\end{tabular}
13.2730 +
13.2731 +\subsubsection*{Built-in MIP presolver}
13.2732 +
13.2733 +The branch-and-cut solver has {\it built-in MIP presolver}. It is
13.2734 +a subprogram that transforms the original MIP problem specified in the
13.2735 +problem object to an equivalent MIP problem, which may be easier for
13.2736 +solving with the branch-and-cut method than the original one. For
13.2737 +example, the presolver can remove redundant constraints and variables,
13.2738 +whose optimal values are known, perform bound and coefficient reduction,
13.2739 +etc. Once the transformed MIP problem has been solved, the presolver
13.2740 +transforms its solution back to corresponding solution of the original
13.2741 +problem.
13.2742 +
13.2743 +Presolving is an optional feature of the routine \verb|glp_intopt|, and
13.2744 +by default it is disabled. In order to enable the MIP presolver, the
13.2745 +control parameter \verb|presolve| should be set to \verb|GLP_ON| (see
13.2746 +paragraph ``Control parameters'' below).
13.2747 +
13.2748 +\subsubsection*{Advanced solver interface}
13.2749 +
13.2750 +The routine \verb|glp_intopt| allows the user to control the
13.2751 +branch-and-cut search by passing to the solver a user-defined callback
13.2752 +routine. For more details see Chapter ``Branch-and-Cut API Routines''.
13.2753 +
13.2754 +\subsubsection*{Terminal output}
13.2755 +
13.2756 +Solving a MIP problem may take a long time, so the solver reports some
13.2757 +information about best known solutions, which is sent to the terminal.
13.2758 +This information has the following format:
13.2759 +
13.2760 +\begin{verbatim}
13.2761 ++nnn: mip = xxx <rho> yyy gap (ppp; qqq)
13.2762 +\end{verbatim}
13.2763 +
13.2764 +\noindent
13.2765 +where: `\verb|nnn|' is the simplex iteration number; `\verb|xxx|' is a
13.2766 +value of the objective function for the best known integer feasible
13.2767 +solution (if no integer feasible solution has been found yet,
13.2768 +`\verb|xxx|' is the text `\verb|not found yet|'); `\verb|rho|' is the
13.2769 +string `\verb|>=|' (in case of minimization) or `\verb|<=|' (in case of
13.2770 +maximization); `\verb|yyy|' is a global bound for exact integer optimum
13.2771 +(i.e. the exact integer optimum is always in the range from `\verb|xxx|'
13.2772 +to `\verb|yyy|'); `\verb|gap|' is the relative mip gap, in percents,
13.2773 +computed as $gap=|xxx-yyy|/(|xxx|+{\tt DBL\_EPSILON})\cdot 100\%$ (if
13.2774 +$gap$ is greater than $999.9\%$, it is not printed); `\verb|ppp|' is the
13.2775 +number of subproblems in the active list, `\verb|qqq|' is the number of
13.2776 +subproblems which have been already fathomed and therefore removed from
13.2777 +the branch-and-bound search tree.
13.2778 +
13.2779 +\subsubsection{Control parameters}
13.2780 +
13.2781 +This paragraph describes all control parameters currently used in the
13.2782 +MIP solver. Symbolic names of control parameters are names of
13.2783 +corresponding members in the structure \verb|glp_iocp|.
13.2784 +
13.2785 +\medskip
13.2786 +
13.2787 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2788 +\multicolumn{2}{@{}l}{{\tt int msg\_lev} (default: {\tt GLP\_MSG\_ALL})}
13.2789 +\\
13.2790 +&Message level for terminal output:\\
13.2791 +&\verb|GLP_MSG_OFF|---no output;\\
13.2792 +&\verb|GLP_MSG_ERR|---error and warning messages only;\\
13.2793 +&\verb|GLP_MSG_ON |---normal output;\\
13.2794 +&\verb|GLP_MSG_ALL|---full output (including informational messages).
13.2795 +\\
13.2796 +\end{tabular}
13.2797 +
13.2798 +\medskip
13.2799 +
13.2800 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2801 +\multicolumn{2}{@{}l}{{\tt int br\_tech} (default: {\tt GLP\_BR\_DTH})}
13.2802 +\\
13.2803 +&Branching technique option:\\
13.2804 +&\verb|GLP_BR_FFV|---first fractional variable;\\
13.2805 +&\verb|GLP_BR_LFV|---last fractional variable;\\
13.2806 +&\verb|GLP_BR_MFV|---most fractional variable;\\
13.2807 +&\verb|GLP_BR_DTH|---heuristic by Driebeck and Tomlin;\\
13.2808 +&\verb|GLP_BR_PCH|---hybrid pseudocost heuristic.\\
13.2809 +\end{tabular}
13.2810 +
13.2811 +\medskip
13.2812 +
13.2813 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2814 +\multicolumn{2}{@{}l}{{\tt int bt\_tech} (default: {\tt GLP\_BT\_BLB})}
13.2815 +\\
13.2816 +&Backtracking technique option:\\
13.2817 +&\verb|GLP_BT_DFS|---depth first search;\\
13.2818 +&\verb|GLP_BT_BFS|---breadth first search;\\
13.2819 +&\verb|GLP_BT_BLB|---best local bound;\\
13.2820 +&\verb|GLP_BT_BPH|---best projection heuristic.\\
13.2821 +\end{tabular}
13.2822 +
13.2823 +\medskip
13.2824 +
13.2825 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2826 +\multicolumn{2}{@{}l}{{\tt int pp\_tech} (default: {\tt GLP\_PP\_ALL})}
13.2827 +\\
13.2828 +&Preprocessing technique option:\\
13.2829 +&\verb|GLP_PP_NONE|---disable preprocessing;\\
13.2830 +&\verb|GLP_PP_ROOT|---perform preprocessing only on the root level;\\
13.2831 +&\verb|GLP_PP_ALL |---perform preprocessing on all levels.\\
13.2832 +\end{tabular}
13.2833 +
13.2834 +\medskip
13.2835 +
13.2836 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2837 +\multicolumn{2}{@{}l}{{\tt int fp\_heur} (default: {\tt GLP\_OFF})}
13.2838 +\\
13.2839 +&Feasibility pump heuristic option:\\
13.2840 +&\verb|GLP_ON |---enable applying the feasibility pump heuristic;\\
13.2841 +&\verb|GLP_OFF|---disable applying the feasibility pump heuristic.\\
13.2842 +\end{tabular}
13.2843 +
13.2844 +\medskip
13.2845 +
13.2846 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2847 +\multicolumn{2}{@{}l}{{\tt int gmi\_cuts} (default: {\tt GLP\_OFF})}\\
13.2848 +&Gomory's mixed integer cut option:\\
13.2849 +&\verb|GLP_ON |---enable generating Gomory's cuts;\\
13.2850 +&\verb|GLP_OFF|---disable generating Gomory's cuts.\\
13.2851 +\end{tabular}
13.2852 +
13.2853 +\medskip
13.2854 +
13.2855 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2856 +\multicolumn{2}{@{}l}{{\tt int mir\_cuts} (default: {\tt GLP\_OFF})}\\
13.2857 +&Mixed integer rounding (MIR) cut option:\\
13.2858 +&\verb|GLP_ON |---enable generating MIR cuts;\\
13.2859 +&\verb|GLP_OFF|---disable generating MIR cuts.\\
13.2860 +\end{tabular}
13.2861 +
13.2862 +\medskip
13.2863 +
13.2864 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2865 +\multicolumn{2}{@{}l}{{\tt int cov\_cuts} (default: {\tt GLP\_OFF})}\\
13.2866 +&Mixed cover cut option:\\
13.2867 +&\verb|GLP_ON |---enable generating mixed cover cuts;\\
13.2868 +&\verb|GLP_OFF|---disable generating mixed cover cuts.\\
13.2869 +\end{tabular}
13.2870 +
13.2871 +\medskip
13.2872 +
13.2873 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2874 +\multicolumn{2}{@{}l}{{\tt int clq\_cuts} (default: {\tt GLP\_OFF})}\\
13.2875 +&Clique cut option:\\
13.2876 +&\verb|GLP_ON |---enable generating clique cuts;\\
13.2877 +&\verb|GLP_OFF|---disable generating clique cuts.\\
13.2878 +\end{tabular}
13.2879 +
13.2880 +\medskip
13.2881 +
13.2882 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2883 +\multicolumn{2}{@{}l}{{\tt double tol\_int} (default: {\tt 1e-5})}\\
13.2884 +&Absolute tolerance used to check if optimal solution to the current LP
13.2885 +relaxation is integer feasible. (Do not change this parameter without
13.2886 +detailed understanding its purpose.)\\
13.2887 +\end{tabular}
13.2888 +
13.2889 +\medskip
13.2890 +
13.2891 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2892 +\multicolumn{2}{@{}l}{{\tt double tol\_obj} (default: {\tt 1e-7})}\\
13.2893 +&Relative tolerance used to check if the objective value in optimal
13.2894 +solution to the current LP relaxation is not better than in the best
13.2895 +known integer feasible solution. (Do not change this parameter without
13.2896 +detailed understanding its purpose.)\\
13.2897 +\end{tabular}
13.2898 +
13.2899 +\medskip
13.2900 +
13.2901 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2902 +\multicolumn{2}{@{}l}{{\tt double mip\_gap} (default: {\tt 0.0})}\\
13.2903 +&The relative mip gap tolerance. If the relative mip gap for currently
13.2904 +known best integer feasible solution falls below this tolerance, the
13.2905 +solver terminates the search. This allows obtainig suboptimal integer
13.2906 +feasible solutions if solving the problem to optimality takes too long
13.2907 +time.\\
13.2908 +\end{tabular}
13.2909 +
13.2910 +\medskip
13.2911 +
13.2912 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2913 +\multicolumn{2}{@{}l}{{\tt int tm\_lim} (default: {\tt INT\_MAX})}\\
13.2914 +&Searching time limit, in milliseconds.\\
13.2915 +\end{tabular}
13.2916 +
13.2917 +\medskip
13.2918 +
13.2919 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2920 +\multicolumn{2}{@{}l}{{\tt int out\_frq} (default: {\tt 5000})}\\
13.2921 +&Output frequency, in milliseconds. This parameter specifies how
13.2922 +frequently the solver sends information about the solution process to
13.2923 +the terminal.\\
13.2924 +\end{tabular}
13.2925 +
13.2926 +\medskip
13.2927 +
13.2928 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2929 +\multicolumn{2}{@{}l}{{\tt int out\_dly} (default: {\tt 10000})}\\
13.2930 +&Output delay, in milliseconds. This parameter specifies how long the
13.2931 +solver should delay sending information about solution of the current
13.2932 +LP relaxation with the simplex method to the terminal.\\
13.2933 +\end{tabular}
13.2934 +
13.2935 +\medskip
13.2936 +
13.2937 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2938 +\multicolumn{2}{@{}l}
13.2939 +{{\tt void (*cb\_func)(glp\_tree *tree, void *info)}
13.2940 +(default: {\tt NULL})}\\
13.2941 +&Entry point to the user-defined callback routine. \verb|NULL| means
13.2942 +the advanced solver interface is not used. For more details see Chapter
13.2943 +``Branch-and-Cut API Routines''.\\
13.2944 +\end{tabular}
13.2945 +
13.2946 +\medskip
13.2947 +
13.2948 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2949 +\multicolumn{2}{@{}l}{{\tt void *cb\_info} (default: {\tt NULL})}\\
13.2950 +&Transit pointer passed to the routine \verb|cb_func| (see above).\\
13.2951 +\end{tabular}
13.2952 +
13.2953 +\medskip
13.2954 +
13.2955 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2956 +\multicolumn{2}{@{}l}{{\tt int cb\_size} (default: {\tt 0})}\\
13.2957 +&The number of extra (up to 256) bytes allocated for each node of the
13.2958 +branch-and-bound tree to store application-specific data. On creating
13.2959 +a node these bytes are initialized by binary zeros.\\
13.2960 +\end{tabular}
13.2961 +
13.2962 +\medskip
13.2963 +
13.2964 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2965 +\multicolumn{2}{@{}l}{{\tt int presolve} (default: {\tt GLP\_OFF})}\\
13.2966 +&MIP presolver option:\\
13.2967 +&\verb|GLP_ON |---enable using the MIP presolver;\\
13.2968 +&\verb|GLP_OFF|---disable using the MIP presolver.\\
13.2969 +\end{tabular}
13.2970 +
13.2971 +\medskip
13.2972 +
13.2973 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
13.2974 +\multicolumn{2}{@{}l}{{\tt int binarize} (default: {\tt GLP\_OFF})}\\
13.2975 +&Binarization option (used only if the presolver is enabled):\\
13.2976 +&\verb|GLP_ON |---replace general integer variables by binary ones;\\
13.2977 +&\verb|GLP_OFF|---do not use binarization.\\
13.2978 +\end{tabular}
13.2979 +
13.2980 +\subsection{glp\_init\_iocp---initialize integer optimizer control
13.2981 +parameters}
13.2982 +
13.2983 +\subsubsection*{Synopsis}
13.2984 +
13.2985 +\begin{verbatim}
13.2986 +void glp_init_iocp(glp_iocp *parm);
13.2987 +\end{verbatim}
13.2988 +
13.2989 +\subsubsection*{Description}
13.2990 +
13.2991 +The routine \verb|glp_init_iocp| initializes control parameters, which
13.2992 +are used by the branch-and-cut solver, with default values.
13.2993 +
13.2994 +Default values of the control parameters are stored in a \verb|glp_iocp|
13.2995 +structure, which the parameter \verb|parm| points to.
13.2996 +
13.2997 +\subsection{glp\_mip\_status---determine status of MIP solution}
13.2998 +
13.2999 +\subsubsection*{Synopsis}
13.3000 +
13.3001 +\begin{verbatim}
13.3002 +int glp_mip_status(glp_prob *mip);
13.3003 +\end{verbatim}
13.3004 +
13.3005 +\subsubsection*{Returns}
13.3006 +
13.3007 +The routine \verb|glp_mip_status| reports the status of a MIP solution
13.3008 +found by the MIP solver as follows:
13.3009 +
13.3010 +\smallskip
13.3011 +
13.3012 +\begin{tabular}{@{}p{25mm}p{91.3mm}@{}}
13.3013 +\verb|GLP_UNDEF| & MIP solution is undefined. \\
13.3014 +\verb|GLP_OPT| & MIP solution is integer optimal. \\
13.3015 +\verb|GLP_FEAS| & MIP solution is integer feasible, however, its
13.3016 + optimality (or non-optimality) has not been proven, perhaps due to
13.3017 + premature termination of the search. \\
13.3018 +\end{tabular}
13.3019 +
13.3020 +\begin{tabular}{@{}p{25mm}p{91.3mm}@{}}
13.3021 +\verb|GLP_NOFEAS| & problem has no integer feasible solution (proven by
13.3022 + the solver). \\
13.3023 +\end{tabular}
13.3024 +
13.3025 +\subsection{glp\_mip\_obj\_val---retrieve objective value}
13.3026 +
13.3027 +\subsubsection*{Synopsis}
13.3028 +
13.3029 +\begin{verbatim}
13.3030 +double glp_mip_obj_val(glp_prob *mip);
13.3031 +\end{verbatim}
13.3032 +
13.3033 +\subsubsection*{Returns}
13.3034 +
13.3035 +The routine \verb|glp_mip_obj_val| returns value of the objective
13.3036 +function for MIP solution.
13.3037 +
13.3038 +\subsection{glp\_mip\_row\_val---retrieve row value}
13.3039 +
13.3040 +\subsubsection*{Synopsis}
13.3041 +
13.3042 +\begin{verbatim}
13.3043 +double glp_mip_row_val(glp_prob *mip, int i);
13.3044 +\end{verbatim}
13.3045 +
13.3046 +\subsubsection*{Returns}
13.3047 +
13.3048 +The routine \verb|glp_mip_row_val| returns value of the auxiliary
13.3049 +variable associated with \verb|i|-th row for MIP solution.
13.3050 +
13.3051 +\subsection{glp\_mip\_col\_val---retrieve column value}
13.3052 +
13.3053 +\subsubsection*{Synopsis}
13.3054 +
13.3055 +\begin{verbatim}
13.3056 +double glp_mip_col_val(glp_prob *mip, int j);
13.3057 +\end{verbatim}
13.3058 +
13.3059 +\subsubsection*{Returns}
13.3060 +
13.3061 +The routine \verb|glp_mip_col_val| returns value of the structural
13.3062 +variable associated with \verb|j|-th column for MIP solution.
13.3063 +
13.3064 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13.3065 +
13.3066 +\newpage
13.3067 +
13.3068 +\section{Additional routines}
13.3069 +
13.3070 +\subsection{lpx\_check\_kkt---check Karush-Kuhn-Tucker optimality
13.3071 +conditions}
13.3072 +
13.3073 +\subsubsection*{Synopsis}
13.3074 +
13.3075 +\begin{verbatim}
13.3076 +void lpx_check_kkt(glp_prob *lp, int scaled, LPXKKT *kkt);
13.3077 +\end{verbatim}
13.3078 +
13.3079 +\subsubsection*{Description}
13.3080 +
13.3081 +The routine \verb|lpx_check_kkt| checks Karush-Kuhn-Tucker optimality
13.3082 +conditions for basic solution. It is assumed that both primal and dual
13.3083 +components of basic solution are valid.
13.3084 +
13.3085 +If the parameter \verb|scaled| is zero, the optimality conditions are
13.3086 +checked for the original, unscaled LP problem. Otherwise, if the
13.3087 +parameter \verb|scaled| is non-zero, the routine checks the conditions
13.3088 +for an internally scaled LP problem.
13.3089 +
13.3090 +The parameter \verb|kkt| is a pointer to the structure \verb|LPXKKT|,
13.3091 +to which the routine stores results of the check. Members of this
13.3092 +structure are shown in the table below.
13.3093 +
13.3094 +\begin{table}[h]
13.3095 +\begin{center}
13.3096 +\begin{tabular}{@{}c|l|l@{}}
13.3097 +Condition & Member & Comment \\
13.3098 +\hline
13.3099 +(KKT.PE) & \verb|pe_ae_max| &
13.3100 + Largest absolute error \\
13.3101 + & \verb|pe_ae_row| &
13.3102 + Number of row with largest absolute error \\
13.3103 + & \verb|pe_re_max| &
13.3104 + Largest relative error \\
13.3105 + & \verb|pe_re_row| &
13.3106 + Number of row with largest relative error \\
13.3107 + & \verb|pe_quality| &
13.3108 + Quality of primal solution \\
13.3109 +\hline
13.3110 +(KKT.PB) & \verb|pb_ae_max| &
13.3111 + Largest absolute error \\
13.3112 + & \verb|pb_ae_ind| &
13.3113 + Number of variable with largest absolute error \\
13.3114 + & \verb|pb_re_max| &
13.3115 + Largest relative error \\
13.3116 + & \verb|pb_re_ind| &
13.3117 + Number of variable with largest relative error \\
13.3118 + & \verb|pb_quality| &
13.3119 + Quality of primal feasibility \\
13.3120 +\hline
13.3121 +(KKT.DE) & \verb|de_ae_max| &
13.3122 + Largest absolute error \\
13.3123 + & \verb|de_ae_col| &
13.3124 + Number of column with largest absolute error \\
13.3125 + & \verb|de_re_max| &
13.3126 + Largest relative error \\
13.3127 + & \verb|de_re_col| &
13.3128 + Number of column with largest relative error \\
13.3129 + & \verb|de_quality| &
13.3130 + Quality of dual solution \\
13.3131 +\hline
13.3132 +(KKT.DB) & \verb|db_ae_max| &
13.3133 + Largest absolute error \\
13.3134 + & \verb|db_ae_ind| &
13.3135 + Number of variable with largest absolute error \\
13.3136 + & \verb|db_re_max| &
13.3137 + Largest relative error \\
13.3138 + & \verb|db_re_ind| &
13.3139 + Number of variable with largest relative error \\
13.3140 + & \verb|db_quality| &
13.3141 + Quality of dual feasibility \\
13.3142 +\end{tabular}
13.3143 +\end{center}
13.3144 +\end{table}
13.3145 +
13.3146 +The routine performs all computations using only components of the
13.3147 +given LP problem and the current basic solution.
13.3148 +
13.3149 +\subsubsection*{Background}
13.3150 +
13.3151 +The first condition checked by the routine is:
13.3152 +$$x_R - A x_S = 0, \eqno{\rm (KKT.PE)}$$
13.3153 +where $x_R$ is the subvector of auxiliary variables (rows), $x_S$ is the
13.3154 +subvector of structural variables (columns), $A$ is the constraint
13.3155 +matrix. This condition expresses the requirement that all primal
13.3156 +variables must satisfy to the system of equality constraints of the
13.3157 +original LP problem. In case of exact arithmetic this condition would be
13.3158 +satisfied for any basic solution; however, in case of inexact
13.3159 +(floating-point) arithmetic, this condition shows how accurate the
13.3160 +primal basic solution is, that depends on accuracy of a representation
13.3161 +of the basis matrix used by the simplex method routines.
13.3162 +
13.3163 +The second condition checked by the routine is:
13.3164 +$$l_k \leq x_k \leq u_k {\rm \ \ \ for\ all}\ k=1,\dots,m+n,
13.3165 +\eqno{\rm (KKT.PB)}$$
13.3166 +where $x_k$ is auxiliary ($1\leq k\leq m$) or structural
13.3167 +($m+1\leq k\leq m+n$) variable, $l_k$ and $u_k$ are, respectively,
13.3168 +lower and upper bounds of the variable $x_k$ (including cases of
13.3169 +infinite bounds). This condition expresses the requirement that all
13.3170 +primal variables must satisfy to bound constraints of the original LP
13.3171 +problem. Since in case of basic solution all non-basic variables are
13.3172 +placed on their bounds, actually the condition (KKT.PB) needs to be
13.3173 +checked for basic variables only. If the primal basic solution has
13.3174 +sufficient accuracy, this condition shows primal feasibility of the
13.3175 +solution.
13.3176 +
13.3177 +The third condition checked by the routine is:
13.3178 +$${\rm grad}\;Z = c = (\tilde{A})^T \pi + d,$$
13.3179 +where $Z$ is the objective function, $c$ is the vector of objective
13.3180 +coefficients, $(\tilde{A})^T$ is a matrix transposed to the expanded
13.3181 +constraint matrix $\tilde{A} = (I|-A)$, $\pi$ is a vector of Lagrange
13.3182 +multipliers that correspond to equality constraints of the original LP
13.3183 +problem, $d$ is a vector of Lagrange multipliers that correspond to
13.3184 +bound constraints for all (auxiliary and structural) variables of the
13.3185 +original LP problem. Geometrically the third condition expresses the
13.3186 +requirement that the gradient of the objective function must belong to
13.3187 +the orthogonal complement of a linear subspace defined by the equality
13.3188 +and active bound constraints, i.e. that the gradient must be a linear
13.3189 +combination of normals to the constraint planes, where Lagrange
13.3190 +multipliers $\pi$ and $d$ are coefficients of that linear combination.
13.3191 +
13.3192 +To eliminate the vector $\pi$ the third condition can be rewritten as:
13.3193 +$$
13.3194 +\left(\begin{array}{@{}c@{}}I \\ -A^T\end{array}\right) \pi =
13.3195 +\left(\begin{array}{@{}c@{}}d_R \\ d_S\end{array}\right) +
13.3196 +\left(\begin{array}{@{}c@{}}c_R \\ c_S\end{array}\right),
13.3197 +$$
13.3198 +or, equivalently:
13.3199 +$$
13.3200 +\begin{array}{r@{}c@{}c}
13.3201 +\pi + d_R&\ =\ &c_R, \\
13.3202 +-A^T\pi + d_S&\ =\ &c_S. \\
13.3203 +\end{array}
13.3204 +$$
13.3205 +Then substituting the vector $\pi$ from the first equation into the
13.3206 +second one we have:
13.3207 +$$A^T (d_R - c_R) + (d_S - c_S) = 0, \eqno{\rm (KKT.DE)}$$
13.3208 +where $d_R$ is the subvector of reduced costs of auxiliary variables
13.3209 +(rows), $d_S$ is the subvector of reduced costs of structural variables
13.3210 +(columns), $c_R$ and $c_S$ are subvectors of objective coefficients at,
13.3211 +respectively, auxiliary and structural variables, $A^T$ is a matrix
13.3212 +transposed to the constraint matrix of the original LP problem. In case
13.3213 +of exact arithmetic this condition would be satisfied for any basic
13.3214 +solution; however, in case of inexact (floating-point) arithmetic, this
13.3215 +condition shows how accurate the dual basic solution is, that depends on
13.3216 +accuracy of a representation of the basis matrix used by the simplex
13.3217 +method routines.
13.3218 +
13.3219 +The last, fourth condition checked by the routine is (KKT.DB):
13.3220 +
13.3221 +\medskip
13.3222 +
13.3223 +\begin{tabular}{r@{}c@{}ll}
13.3224 +&$\ d_k\ $& $=0,$&if $x_k$ is basic or free non-basic variable \\
13.3225 +$0\leq$&$\ d_k\ $&$<+\infty$&if $x_k$ is non-basic on its lower
13.3226 +(minimization) \\
13.3227 +&&&or upper (maximization) bound \\
13.3228 +$-\infty<$&$\ d_k\ $&$\leq 0$&if $x_k$ is non-basic on its upper
13.3229 +(minimization) \\
13.3230 +&&&or lower (maximization) bound \\
13.3231 +$-\infty<$&$\ d_k\ $&$<+\infty$&if $x_k$ is non-basic fixed variable \\
13.3232 +\end{tabular}
13.3233 +
13.3234 +\medskip
13.3235 +
13.3236 +\noindent
13.3237 +for all $k=1,\dots,m+n$, where $d_k$ is a reduced cost (Lagrange
13.3238 +multiplier) of auxiliary ($1\leq k\leq m$) or structural
13.3239 +($m+1\leq k\leq m+n$) variable $x_k$. Geometrically this condition
13.3240 +expresses the requirement that constraints of the original problem must
13.3241 +"hold" the point preventing its movement along the anti-gradient (in
13.3242 +case of minimization) or the gradient (in case of maximization) of the
13.3243 +objective function. Since in case of basic solution reduced costs of
13.3244 +all basic variables are placed on their (zero) bounds, actually the
13.3245 +condition (KKT.DB) needs to be checked for non-basic variables only.
13.3246 +If the dual basic solution has sufficient accuracy, this condition shows
13.3247 +dual feasibility of the solution.
13.3248 +
13.3249 +Should note that the complete set of Karush-Kuhn-Tucker optimality
13.3250 +conditions also includes the fifth, so called complementary slackness
13.3251 +condition, which expresses the requirement that at least either a primal
13.3252 +variable $x_k$ or its dual counterpart $d_k$ must be on its bound for
13.3253 +all $k=1,\dots,m+n$. However, being always satisfied by definition for
13.3254 +any basic solution that condition is not checked by the routine.
13.3255 +
13.3256 +To check the first condition (KKT.PE) the routine computes a vector of
13.3257 +residuals:
13.3258 +$$g = x_R - A x_S,$$
13.3259 +determines component of this vector that correspond to largest absolute
13.3260 +and relative errors:
13.3261 +
13.3262 +\medskip
13.3263 +
13.3264 +\hspace{30mm}
13.3265 +\verb|pe_ae_max| $\displaystyle{= \max_{1\leq i\leq m}|g_i|}$,
13.3266 +
13.3267 +\medskip
13.3268 +
13.3269 +\hspace{30mm}
13.3270 +\verb|pe_re_max| $\displaystyle{= \max_{1\leq i\leq m}
13.3271 +\frac{|g_i|}{1+|(x_R)_i|}}$,
13.3272 +
13.3273 +\medskip
13.3274 +
13.3275 +\noindent
13.3276 +and stores these quantities and corresponding row indices to the
13.3277 +structure \verb|LPXKKT|.
13.3278 +
13.3279 +To check the second condition (KKT.PB) the routine computes a vector
13.3280 +of residuals:
13.3281 +$$
13.3282 +h_k = \left\{
13.3283 +\begin{array}{ll}
13.3284 +0, & {\rm if}\ l_k \leq x_k \leq u_k \\
13.3285 +x_k - l_k, & {\rm if}\ x_k < l_k \\
13.3286 +x_k - u_k, & {\rm if}\ x_k > u_k \\
13.3287 +\end{array}
13.3288 +\right.
13.3289 +$$
13.3290 +for all $k=1,\dots,m+n$, determines components of this vector that
13.3291 +correspond to largest absolute and relative errors:
13.3292 +
13.3293 +\medskip
13.3294 +
13.3295 +\hspace{30mm}
13.3296 +\verb|pb_ae_max| $\displaystyle{= \max_{1\leq k \leq m+n}|h_k|}$,
13.3297 +
13.3298 +\medskip
13.3299 +
13.3300 +\hspace{30mm}
13.3301 +\verb|pb_re_max| $\displaystyle{= \max_{1\leq k \leq m+n}
13.3302 +\frac{|h_k|}{1+|x_k|}}$,
13.3303 +
13.3304 +\medskip
13.3305 +
13.3306 +\noindent
13.3307 +and stores these quantities and corresponding variable indices to the
13.3308 +structure \verb|LPXKKT|.
13.3309 +
13.3310 +To check the third condition (KKT.DE) the routine computes a vector of
13.3311 +residuals:
13.3312 +$$u = A^T (d_R - c_R) + (d_S - c_S),$$
13.3313 +determines components of this vector that correspond to largest
13.3314 +absolute and relative errors:
13.3315 +
13.3316 +\medskip
13.3317 +
13.3318 +\hspace{30mm}
13.3319 +\verb|de_ae_max| $\displaystyle{= \max_{1\leq j\leq n}|u_j|}$,
13.3320 +
13.3321 +\medskip
13.3322 +
13.3323 +\hspace{30mm}
13.3324 +\verb|de_re_max| $\displaystyle{= \max_{1\leq j\leq n}
13.3325 +\frac{|u_j|}{1+|(d_S)_j - (c_S)_j|}}$,
13.3326 +
13.3327 +\medskip
13.3328 +
13.3329 +\noindent
13.3330 +and stores these quantities and corresponding column indices to the
13.3331 +structure \verb|LPXKKT|.
13.3332 +
13.3333 +To check the fourth condition (KKT.DB) the routine computes a vector
13.3334 +of residuals:
13.3335 +
13.3336 +$$
13.3337 +v_k = \left\{
13.3338 +\begin{array}{ll}
13.3339 +0, & {\rm if}\ d_k\ {\rm has\ correct\ sign} \\
13.3340 +d_k, & {\rm if}\ d_k\ {\rm has\ wrong\ sign} \\
13.3341 +\end{array}
13.3342 +\right.
13.3343 +$$
13.3344 +for all $k=1,\dots,m+n$, determines components of this vector that
13.3345 +correspond to largest absolute and relative errors:
13.3346 +
13.3347 +\medskip
13.3348 +
13.3349 +\hspace{30mm}
13.3350 +\verb|db_ae_max| $\displaystyle{= \max_{1\leq k\leq m+n}|v_k|}$,
13.3351 +
13.3352 +\medskip
13.3353 +
13.3354 +\hspace{30mm}
13.3355 +\verb|db_re_max| $\displaystyle{= \max_{1\leq k\leq m+n}
13.3356 +\frac{|v_k|}{1+|d_k - c_k|}}$,
13.3357 +
13.3358 +\medskip
13.3359 +
13.3360 +\noindent
13.3361 +and stores these quantities and corresponding variable indices to the
13.3362 +structure \verb|LPXKKT|.
13.3363 +
13.3364 +Using the relative errors for all the four conditions listed above the
13.3365 +routine
13.3366 +\verb|lpx_check_kkt| also estimates a "quality" of the basic solution
13.3367 +from the standpoint of these conditions and stores corresponding
13.3368 +quality indicators to the structure \verb|LPXKKT|:
13.3369 +
13.3370 +\verb|pe_quality|---quality of primal solution;
13.3371 +
13.3372 +\verb|pb_quality|---quality of primal feasibility;
13.3373 +
13.3374 +\verb|de_quality|---quality of dual solution;
13.3375 +
13.3376 +\verb|db_quality|---quality of dual feasibility.
13.3377 +
13.3378 +Each of these indicators is assigned to one of the following four
13.3379 +values:
13.3380 +
13.3381 +\verb|'H'| means high quality,
13.3382 +
13.3383 +\verb|'M'| means medium quality,
13.3384 +
13.3385 +\verb|'L'| means low quality, or
13.3386 +
13.3387 +\verb|'?'| means wrong or infeasible solution.
13.3388 +
13.3389 +If all the indicators show high or medium quality (for an internally
13.3390 +scaled LP problem, i.e. when the parameter \verb|scaled| in a call to
13.3391 +the routine \verb|lpx_check_kkt| is non-zero), the user can be sure that
13.3392 +the obtained basic solution is quite accurate.
13.3393 +
13.3394 +If some of the indicators show low quality, the solution can still be
13.3395 +considered as relevant, though an additional analysis is needed
13.3396 +depending on which indicator shows low quality.
13.3397 +
13.3398 +If the indicator \verb|pe_quality| is assigned to \verb|'?'|, the
13.3399 +primal solution is wrong. If the indicator \verb|de_quality| is assigned
13.3400 +to \verb|'?'|, the dual solution is wrong.
13.3401 +
13.3402 +If the indicator \verb|db_quality| is assigned to \verb|'?'| while
13.3403 +other indicators show a good quality, this means that the current
13.3404 +basic solution being primal feasible is not dual feasible. Similarly,
13.3405 +if the indicator \verb|pb_quality| is assigned to \verb|'?'| while
13.3406 +other indicators are not, this means that the current basic solution
13.3407 +being dual feasible is not primal feasible.
13.3408 +
13.3409 +%* eof *%
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
14.2 +++ b/doc/glpk03.tex Mon Dec 06 13:09:21 2010 +0100
14.3 @@ -0,0 +1,1577 @@
14.4 +%* glpk03.tex *%
14.5 +
14.6 +\chapter{Utility API routines}
14.7 +
14.8 +\section{Problem data reading/writing routines}
14.9 +
14.10 +\subsection{glp\_read\_mps---read problem data in MPS format}
14.11 +
14.12 +\subsubsection*{Synopsis}
14.13 +
14.14 +\begin{verbatim}
14.15 +int glp_read_mps(glp_prob *lp, int fmt, const void *parm,
14.16 + const char *fname);
14.17 +\end{verbatim}
14.18 +
14.19 +\subsubsection*{Description}
14.20 +
14.21 +The routine \verb|glp_read_mps| reads problem data in MPS format from a
14.22 +text file. (The MPS format is described in Appendix \ref{champs}, page
14.23 +\pageref{champs}.)
14.24 +
14.25 +The parameter \verb|fmt| specifies the MPS format version as follows:
14.26 +
14.27 +\begin{tabular}{@{}ll}
14.28 +\verb|GLP_MPS_DECK| & fixed (ancient) MPS format; \\
14.29 +\verb|GLP_MPS_FILE| & free (modern) MPS format. \\
14.30 +\end{tabular}
14.31 +
14.32 +The parameter \verb|parm| is reserved for use in the future and must be
14.33 +specified as \verb|NULL|.
14.34 +
14.35 +The character string \verb|fname| specifies a name of the text file to
14.36 +be read in. (If the file name ends with suffix `\verb|.gz|', the file is
14.37 +assumed to be compressed, in which case the routine \verb|glp_read_mps|
14.38 +decompresses it ``on the fly''.)
14.39 +
14.40 +Note that before reading data the current content of the problem object
14.41 +is completely erased with the routine \verb|glp_erase_prob|.
14.42 +
14.43 +\subsubsection*{Returns}
14.44 +
14.45 +If the operation was successful, the routine \verb|glp_read_mps|
14.46 +returns zero. Otherwise, it prints an error message and returns
14.47 +non-zero.
14.48 +
14.49 +\subsection{glp\_write\_mps---write problem data in MPS format}
14.50 +
14.51 +\subsubsection*{Synopsis}
14.52 +
14.53 +\begin{verbatim}
14.54 +int glp_write_mps(glp_prob *lp, int fmt, const void *parm,
14.55 + const char *fname);
14.56 +\end{verbatim}
14.57 +
14.58 +\subsubsection*{Description}
14.59 +
14.60 +The routine \verb|glp_write_mps| writes problem data in MPS format to a
14.61 +text file. (The MPS format is described in Appendix \ref{champs}, page
14.62 +\pageref{champs}.)
14.63 +
14.64 +The parameter \verb|fmt| specifies the MPS format version as follows:
14.65 +
14.66 +\begin{tabular}{@{}ll}
14.67 +\verb|GLP_MPS_DECK| & fixed (ancient) MPS format; \\
14.68 +\verb|GLP_MPS_FILE| & free (modern) MPS format. \\
14.69 +\end{tabular}
14.70 +
14.71 +The parameter \verb|parm| is reserved for use in the future and must be
14.72 +specified as \verb|NULL|.
14.73 +
14.74 +The character string \verb|fname| specifies a name of the text file to
14.75 +be written out. (If the file name ends with suffix `\verb|.gz|', the
14.76 +file is assumed to be compressed, in which case the routine
14.77 +\verb|glp_write_mps| performs automatic compression on writing it.)
14.78 +
14.79 +\subsubsection*{Returns}
14.80 +
14.81 +If the operation was successful, the routine \verb|glp_write_mps|
14.82 +returns zero. Otherwise, it prints an error message and returns
14.83 +non-zero.
14.84 +
14.85 +\subsection{glp\_read\_lp---read problem data in CPLEX LP format}
14.86 +
14.87 +\subsubsection*{Synopsis}
14.88 +
14.89 +\begin{verbatim}
14.90 +int glp_read_lp(glp_prob *lp, const void *parm,
14.91 + const char *fname);
14.92 +\end{verbatim}
14.93 +
14.94 +\subsubsection*{Description}
14.95 +
14.96 +The routine \verb|glp_read_lp| reads problem data in CPLEX LP format
14.97 +from a text file. (The CPLEX LP format is described in Appendix
14.98 +\ref{chacplex}, page \pageref{chacplex}.)
14.99 +
14.100 +The parameter \verb|parm| is reserved for use in the future and must be
14.101 +specified as \verb|NULL|.
14.102 +
14.103 +The character string \verb|fname| specifies a name of the text file to
14.104 +be read in. (If the file name ends with suffix `\verb|.gz|', the file is
14.105 +assumed to be compressed, in which case the routine \verb|glp_read_lp|
14.106 +decompresses it ``on the fly''.)
14.107 +
14.108 +Note that before reading data the current content of the problem object
14.109 +is completely erased with the routine \verb|glp_erase_prob|.
14.110 +
14.111 +\subsubsection*{Returns}
14.112 +
14.113 +If the operation was successful, the routine \verb|glp_read_lp| returns
14.114 +zero. Otherwise, it prints an error message and returns non-zero.
14.115 +
14.116 +\subsection{glp\_write\_lp---write problem data in CPLEX LP format}
14.117 +
14.118 +\subsubsection*{Synopsis}
14.119 +
14.120 +\begin{verbatim}
14.121 +int glp_write_lp(glp_prob *lp, const void *parm,
14.122 + const char *fname);
14.123 +\end{verbatim}
14.124 +
14.125 +\subsubsection*{Description}
14.126 +
14.127 +The routine \verb|glp_write_lp| writes problem data in CPLEX LP format
14.128 +to a text file. (The CPLEX LP format is described in Appendix
14.129 +\ref{chacplex}, page \pageref{chacplex}.)
14.130 +
14.131 +The parameter \verb|parm| is reserved for use in the future and must be
14.132 +specified as \verb|NULL|.
14.133 +
14.134 +The character string \verb|fname| specifies a name of the text file to
14.135 +be written out. (If the file name ends with suffix `\verb|.gz|', the
14.136 +file is assumed to be compressed, in which case the routine
14.137 +\verb|glp_write_lp| performs automatic compression on writing it.)
14.138 +
14.139 +\subsubsection*{Returns}
14.140 +
14.141 +If the operation was successful, the routine \verb|glp_write_lp|
14.142 +returns zero. Otherwise, it prints an error message and returns
14.143 +non-zero.
14.144 +
14.145 +\subsection{glp\_read\_prob---read problem data in GLPK format}
14.146 +
14.147 +\subsubsection*{Synopsis}
14.148 +
14.149 +\begin{verbatim}
14.150 +int glp_read_prob(glp_prob *P, int flags, const char *fname);
14.151 +\end{verbatim}
14.152 +
14.153 +\subsubsection*{Description}
14.154 +
14.155 +The routine \verb|glp_read_prob| reads problem data in the GLPK LP/MIP
14.156 +format from a text file. (For description of the GLPK LP/MIP format see
14.157 +below.)
14.158 +
14.159 +The parameter \verb|flags| is reserved for use in the future and should
14.160 +be specified as zero.
14.161 +
14.162 +The character string \verb|fname| specifies a name of the text file to
14.163 +be read in. (If the file name ends with suffix `\verb|.gz|', the file
14.164 +is assumed to be compressed, in which case the routine
14.165 +\verb|glp_read_prob| decompresses it ``on the fly''.)
14.166 +
14.167 +Note that before reading data the current content of the problem object
14.168 +is completely erased with the routine \verb|glp_erase_prob|.
14.169 +
14.170 +\subsubsection*{Returns}
14.171 +
14.172 +If the operation was successful, the routine \verb|glp_read_prob|
14.173 +returns zero. Otherwise, it prints an error message and returns
14.174 +non-zero.
14.175 +
14.176 +\subsubsection*{GLPK LP/MIP format}
14.177 +
14.178 +The GLPK LP/MIP format is a DIMACS-like format.\footnote{The DIMACS
14.179 +formats were developed by the Center for Discrete Mathematics and
14.180 +Theoretical Computer Science (DIMACS) to facilitate exchange of problem
14.181 +data. For details see: {\tt <http://dimacs.rutgers.edu/Challenges/>}. }
14.182 +The file in this format is a plain ASCII text file containing lines of
14.183 +several types described below. A line is terminated with the end-of-line
14.184 +character. Fields in each line are separated by at least one blank
14.185 +space. Each line begins with a one-character designator to identify the
14.186 +line type.
14.187 +
14.188 +The first line of the data file must be the problem line (except
14.189 +optional comment lines, which may precede the problem line). The last
14.190 +line of the data file must be the end line. Other lines may follow in
14.191 +arbitrary order, however, duplicate lines are not allowed.
14.192 +
14.193 +\paragraph{Comment lines.} Comment lines give human-readable
14.194 +information about the data file and are ignored by GLPK routines.
14.195 +Comment lines can appear anywhere in the data file. Each comment line
14.196 +begins with the lower-case character \verb|c|.
14.197 +
14.198 +\begin{verbatim}
14.199 + c This is an example of comment line
14.200 +\end{verbatim}
14.201 +
14.202 +\paragraph{Problem line.} There must be exactly one problem line in the
14.203 +data file. This line must appear before any other lines except comment
14.204 +lines and has the following format:
14.205 +
14.206 +\begin{verbatim}
14.207 + p CLASS DIR ROWS COLS NONZ
14.208 +\end{verbatim}
14.209 +
14.210 +The lower-case letter \verb|p| specifies that this is the problem line.
14.211 +
14.212 +The \verb|CLASS| field defines the problem class and can contain either
14.213 +the keyword \verb|lp| (that means linear programming problem) or
14.214 +\verb|mip| (that means mixed integer programming problem).
14.215 +
14.216 +The \verb|DIR| field defines the optimization direction (that is, the
14.217 +objective function sense) and can contain either the keyword \verb|min|
14.218 +(that means minimization) or \verb|max| (that means maximization).
14.219 +
14.220 +The \verb|ROWS|, \verb|COLS|, and \verb|NONZ| fields contain
14.221 +non-negative integer values specifying, respectively, the number of
14.222 +rows (constraints), columns (variables), and non-zero constraint
14.223 +coefficients in the problem instance. Note that \verb|NONZ| value does
14.224 +not account objective coefficients.
14.225 +
14.226 +\paragraph{Row descriptors.} There must be at most one row descriptor
14.227 +line in the data file for each row (constraint). This line has one of
14.228 +the following formats:
14.229 +
14.230 +\begin{verbatim}
14.231 + i ROW f
14.232 + i ROW l RHS
14.233 + i ROW u RHS
14.234 + i ROW d RHS1 RHS2
14.235 + i ROW s RHS
14.236 +\end{verbatim}
14.237 +
14.238 +The lower-case letter \verb|i| specifies that this is the row
14.239 +descriptor line.
14.240 +
14.241 +The \verb|ROW| field specifies the row ordinal number, an integer
14.242 +between 1 and $m$, where $m$ is the number of rows in the problem
14.243 +instance.
14.244 +
14.245 +The next lower-case letter specifies the row type as follows:
14.246 +
14.247 +\verb|f| --- free (unbounded) row: $-\infty<\sum a_jx_j<+\infty$;
14.248 +
14.249 +\verb|l| --- inequality constraint of `$\geq$' type:
14.250 +$\sum a_jx_j\geq b$;
14.251 +
14.252 +\verb|u| --- inequality constraint of `$\leq$' type:
14.253 +$\sum a_jx_j\leq b$;
14.254 +
14.255 +\verb|d| --- double-sided inequality constraint:
14.256 +$b_1\leq\sum a_jx_j\leq b_2$;
14.257 +
14.258 +\verb|s| --- equality constraint: $\sum a_jx_j=b$.
14.259 +
14.260 +The \verb|RHS| field contains a floaing-point value specifying the
14.261 +row right-hand side. The \verb|RHS1| and \verb|RHS2| fields contain
14.262 +floating-point values specifying, respectively, the lower and upper
14.263 +right-hand sides for the double-sided row.
14.264 +
14.265 +If for some row its descriptor line does not appear in the data file,
14.266 +by default that row is assumed to be an equality constraint with zero
14.267 +right-hand side.
14.268 +
14.269 +\paragraph{Column descriptors.} There must be at most one column
14.270 +descriptor line in the data file for each column (variable). This line
14.271 +has one of the following formats depending on the problem class
14.272 +specified in the problem line:
14.273 +
14.274 +\bigskip
14.275 +
14.276 +\begin{tabular}{@{}l@{\hspace*{40pt}}l}
14.277 +LP class & MIP class \\
14.278 +\hline
14.279 +\verb|j COL f| & \verb|j COL KIND f| \\
14.280 +\verb|j COL l BND| & \verb|j COL KIND l BND| \\
14.281 +\verb|j COL u BND| & \verb|j COL KIND u BND| \\
14.282 +\verb|j COL d BND1 BND2| & \verb|j COL KIND d BND1 BND2| \\
14.283 +\verb|j COL s BND| & \verb|j COL KIND s BND| \\
14.284 +\end{tabular}
14.285 +
14.286 +\bigskip
14.287 +
14.288 +The lower-case letter \verb|j| specifies that this is the column
14.289 +descriptor line.
14.290 +
14.291 +The \verb|COL| field specifies the column ordinal number, an integer
14.292 +between 1 and $n$, where $n$ is the number of columns in the problem
14.293 +instance.
14.294 +
14.295 +The \verb|KIND| field is used only for MIP problems and specifies the
14.296 +column kind as follows:
14.297 +
14.298 +\verb|c| --- continuous column;
14.299 +
14.300 +\verb|i| --- integer column;
14.301 +
14.302 +\verb|b| --- binary column (in this case all remaining fields must be
14.303 +omitted).
14.304 +
14.305 +The next lower-case letter specifies the column type as follows:
14.306 +
14.307 +\verb|f| --- free (unbounded) column: $-\infty<x<+\infty$;
14.308 +
14.309 +\verb|l| --- column with lower bound: $x\geq l$;
14.310 +
14.311 +\verb|u| --- column with upper bound: $x\leq u$;
14.312 +
14.313 +\verb|d| --- double-bounded column: $l\leq x\leq u$;
14.314 +
14.315 +\verb|s| --- fixed column: $x=s$.
14.316 +
14.317 +The \verb|BND| field contains a floating-point value that specifies the
14.318 +column bound. The \verb|BND1| and \verb|BND2| fields contain
14.319 +floating-point values specifying, respectively, the lower and upper
14.320 +bounds for the double-bounded column.
14.321 +
14.322 +If for some column its descriptor line does not appear in the file, by
14.323 +default that column is assumed to be non-negative (in case of LP class)
14.324 +or binary (in case of MIP class).
14.325 +
14.326 +\paragraph{Coefficient descriptors.} There must be exactly one
14.327 +coefficient descriptor line in the data file for each non-zero
14.328 +objective or constraint coefficient. This line has the following format:
14.329 +
14.330 +\begin{verbatim}
14.331 + a ROW COL VAL
14.332 +\end{verbatim}
14.333 +
14.334 +The lower-case letter \verb|a| specifies that this is the coefficient
14.335 +descriptor line.
14.336 +
14.337 +For objective coefficients the \verb|ROW| field must contain 0. For
14.338 +constraint coefficients the \verb|ROW| field specifies the row ordinal
14.339 +number, an integer between 1 and $m$, where $m$ is the number of rows
14.340 +in the problem instance.
14.341 +
14.342 +The \verb|COL| field specifies the column ordinal number, an integer
14.343 +between 1 and $n$, where $n$ is the number of columns in the problem
14.344 +instance.
14.345 +
14.346 +If both the \verb|ROW| and \verb|COL| fields contain 0, the line
14.347 +specifies the constant term (``shift'') of the objective function
14.348 +rather than objective coefficient.
14.349 +
14.350 +The \verb|VAL| field contains a floating-point coefficient value (it is
14.351 +allowed to specify zero value in this field).
14.352 +
14.353 +The number of constraint coefficient descriptor lines must be exactly
14.354 +the same as specified in the field \verb|NONZ| of the problem line.
14.355 +
14.356 +\paragraph{Symbolic name descriptors.} There must be at most one
14.357 +symbolic name descriptor line for the problem instance, objective
14.358 +function, each row (constraint), and each column (variable). This line
14.359 +has one of the following formats:
14.360 +
14.361 +\begin{verbatim}
14.362 + n p NAME
14.363 + n z NAME
14.364 + n i ROW NAME
14.365 + n j COL NAME
14.366 +\end{verbatim}
14.367 +
14.368 +The lower-case letter \verb|n| specifies that this is the symbolic name
14.369 +descriptor line.
14.370 +
14.371 +The next lower-case letter specifies which object should be assigned a
14.372 +symbolic name:
14.373 +
14.374 +\verb|p| --- problem instance;
14.375 +
14.376 +\verb|z| --- objective function;
14.377 +
14.378 +\verb|i| --- row (constraint);
14.379 +
14.380 +\verb|j| --- column (variable).
14.381 +
14.382 +The \verb|ROW| field specifies the row ordinal number, an integer
14.383 +between 1 and $m$, where $m$ is the number of rows in the problem
14.384 +instance.
14.385 +
14.386 +The \verb|COL| field specifies the column ordinal number, an integer
14.387 +between 1 and $n$, where $n$ is the number of columns in the problem
14.388 +instance.
14.389 +
14.390 +The \verb|NAME| field contains the symbolic name, a sequence from 1 to
14.391 +255 arbitrary graphic ASCII characters, assigned to corresponding
14.392 +object.
14.393 +
14.394 +\paragraph{End line.} There must be exactly one end line in the data
14.395 +file. This line must appear last in the file and has the following
14.396 +format:
14.397 +
14.398 +\begin{verbatim}
14.399 + e
14.400 +\end{verbatim}
14.401 +
14.402 +The lower-case letter \verb|e| specifies that this is the end line.
14.403 +Anything that follows the end line is ignored by GLPK routines.
14.404 +
14.405 +\subsubsection*{Example of data file in GLPK LP/MIP format}
14.406 +
14.407 +The following example of a data file in GLPK LP/MIP format specifies
14.408 +the same LP problem as in Subsection ``Example of MPS file''.
14.409 +
14.410 +\begin{center}
14.411 +\footnotesize\tt
14.412 +\begin{tabular}{l@{\hspace*{50pt}}}
14.413 +p lp min 8 7 48 \\
14.414 +n p PLAN \\
14.415 +n z VALUE \\
14.416 +i 1 f \\
14.417 +n i 1 VALUE \\
14.418 +i 2 s 2000 \\
14.419 +n i 2 YIELD \\
14.420 +i 3 u 60 \\
14.421 +n i 3 FE \\
14.422 +i 4 u 100 \\
14.423 +n i 4 CU \\
14.424 +i 5 u 40 \\
14.425 +n i 5 MN \\
14.426 +i 6 u 30 \\
14.427 +n i 6 MG \\
14.428 +i 7 l 1500 \\
14.429 +n i 7 AL \\
14.430 +i 8 d 250 300 \\
14.431 +n i 8 SI \\
14.432 +j 1 d 0 200 \\
14.433 +n j 1 BIN1 \\
14.434 +j 2 d 0 2500 \\
14.435 +n j 2 BIN2 \\
14.436 +j 3 d 400 800 \\
14.437 +n j 3 BIN3 \\
14.438 +j 4 d 100 700 \\
14.439 +n j 4 BIN4 \\
14.440 +j 5 d 0 1500 \\
14.441 +n j 5 BIN5 \\
14.442 +n j 6 ALUM \\
14.443 +n j 7 SILICON \\
14.444 +a 0 1 0.03 \\
14.445 +a 0 2 0.08 \\
14.446 +a 0 3 0.17 \\
14.447 +a 0 4 0.12 \\
14.448 +a 0 5 0.15 \\
14.449 +a 0 6 0.21 \\
14.450 +a 0 7 0.38 \\
14.451 +a 1 1 0.03 \\
14.452 +a 1 2 0.08 \\
14.453 +a 1 3 0.17 \\
14.454 +a 1 4 0.12 \\
14.455 +a 1 5 0.15 \\
14.456 +a 1 6 0.21 \\
14.457 +\end{tabular}
14.458 +\begin{tabular}{|@{\hspace*{80pt}}l}
14.459 +a 1 7 0.38 \\
14.460 +a 2 1 1 \\
14.461 +a 2 2 1 \\
14.462 +a 2 3 1 \\
14.463 +a 2 4 1 \\
14.464 +a 2 5 1 \\
14.465 +a 2 6 1 \\
14.466 +a 2 7 1 \\
14.467 +a 3 1 0.15 \\
14.468 +a 3 2 0.04 \\
14.469 +a 3 3 0.02 \\
14.470 +a 3 4 0.04 \\
14.471 +a 3 5 0.02 \\
14.472 +a 3 6 0.01 \\
14.473 +a 3 7 0.03 \\
14.474 +a 4 1 0.03 \\
14.475 +a 4 2 0.05 \\
14.476 +a 4 3 0.08 \\
14.477 +a 4 4 0.02 \\
14.478 +a 4 5 0.06 \\
14.479 +a 4 6 0.01 \\
14.480 +a 5 1 0.02 \\
14.481 +a 5 2 0.04 \\
14.482 +a 5 3 0.01 \\
14.483 +a 5 4 0.02 \\
14.484 +a 5 5 0.02 \\
14.485 +a 6 1 0.02 \\
14.486 +a 6 2 0.03 \\
14.487 +a 6 5 0.01 \\
14.488 +a 7 1 0.7 \\
14.489 +a 7 2 0.75 \\
14.490 +a 7 3 0.8 \\
14.491 +a 7 4 0.75 \\
14.492 +a 7 5 0.8 \\
14.493 +a 7 6 0.97 \\
14.494 +a 8 1 0.02 \\
14.495 +a 8 2 0.06 \\
14.496 +a 8 3 0.08 \\
14.497 +a 8 4 0.12 \\
14.498 +a 8 5 0.02 \\
14.499 +a 8 6 0.01 \\
14.500 +a 8 7 0.97 \\
14.501 +e o f \\
14.502 +\\
14.503 +\end{tabular}
14.504 +\end{center}
14.505 +
14.506 +\newpage
14.507 +
14.508 +\subsection{glp\_write\_prob---write problem data in GLPK format}
14.509 +
14.510 +\subsubsection*{Synopsis}
14.511 +
14.512 +\begin{verbatim}
14.513 +int glp_write_prob(glp_prob *P, int flags, const char *fname);
14.514 +\end{verbatim}
14.515 +
14.516 +\subsubsection*{Description}
14.517 +
14.518 +The routine \verb|glp_write_prob| writes problem data in the GLPK
14.519 +LP/MIP format to a text file. (For description of the GLPK LP/MIP
14.520 +format see Subsection ``Read problem data in GLPK format''.)
14.521 +
14.522 +The parameter \verb|flags| is reserved for use in the future and should
14.523 +be specified as zero.
14.524 +
14.525 +The character string \verb|fname| specifies a name of the text file to
14.526 +be written out. (If the file name ends with suffix `\verb|.gz|', the
14.527 +file is assumed to be compressed, in which case the routine
14.528 +\verb|glp_write_prob| performs automatic compression on writing it.)
14.529 +
14.530 +\subsubsection*{Returns}
14.531 +
14.532 +If the operation was successful, the routine \verb|glp_read_prob|
14.533 +returns zero. Otherwise, it prints an error message and returns
14.534 +non-zero.
14.535 +
14.536 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14.537 +
14.538 +\newpage
14.539 +
14.540 +\section{Routines for processing MathProg models}
14.541 +
14.542 +\subsection{Introduction}
14.543 +
14.544 +GLPK supports the {\it GNU MathProg modeling language}.\footnote{The
14.545 +GNU MathProg modeling language is a subset of the AMPL language. For
14.546 +its detailed description see the document ``Modeling Language GNU
14.547 +MathProg: Language Reference'' included in the GLPK distribution.}
14.548 +As a rule, models written in MathProg are solved with the GLPK LP/MIP
14.549 +stand-alone solver \verb|glpsol| (see Appendix D) and do not need any
14.550 +programming with API routines. However, for various reasons the user
14.551 +may need to process MathProg models directly in his/her application
14.552 +program, in which case he/she may use API routines described in this
14.553 +section. These routines provide an interface to the {\it MathProg
14.554 +translator}, a component of GLPK, which translates MathProg models into
14.555 +an internal code and then interprets (executes) this code.
14.556 +
14.557 +The processing of a model written in GNU MathProg includes several
14.558 +steps, which should be performed in the following order:
14.559 +
14.560 +\begin{enumerate}
14.561 +\item{\it Allocating the workspace.}
14.562 +The translator allocates the workspace, an internal data structure used
14.563 +on all subsequent steps.
14.564 +\item{\it Reading model section.} The translator reads model section
14.565 +and, optionally, data section from a specified text file and translates
14.566 +them into the internal code. If necessary, on this step data section
14.567 +may be ignored.
14.568 +\item{\it Reading data section(s).} The translator reads one or more
14.569 +data sections from specified text file(s) and translates them into the
14.570 +internal code.
14.571 +\item{\it Generating the model.} The translator executes the internal
14.572 +code to evaluate the content of the model objects such as sets,
14.573 +parameters, variables, constraints, and objectives. On this step the
14.574 +execution is suspended at the solve statement.
14.575 +\item {\it Building the problem object.} The translator obtains all
14.576 +necessary information from the workspace and builds the standard
14.577 +problem object (that is, the program object of type \verb|glp_prob|).
14.578 +\item{\it Solving the problem.} On this step the problem object built
14.579 +on the previous step is passed to a solver, which solves the problem
14.580 +instance and stores its solution back to the problem object.
14.581 +\item{\it Postsolving the model.} The translator copies the solution
14.582 +from the problem object to the workspace and then executes the internal
14.583 +code from the solve statement to the end of the model. (If model has
14.584 +no solve statement, the translator does nothing on this step.)
14.585 +\item{\it Freeing the workspace.} The translator frees all the memory
14.586 +allocated to the workspace.
14.587 +\end{enumerate}
14.588 +
14.589 +Note that the MathProg translator performs no error correction, so if
14.590 +any of steps 2 to 7 fails (due to errors in the model), the application
14.591 +program should terminate processing and go to step 8.
14.592 +
14.593 +\subsubsection*{Example 1}
14.594 +
14.595 +In this example the program reads model and data sections from input
14.596 +file \verb|egypt.mod|\footnote{This is an example model included in
14.597 +the GLPK distribution.} and writes the model to output file
14.598 +\verb|egypt.mps| in free MPS format (see Appendix B). No solution is
14.599 +performed.
14.600 +
14.601 +\begin{small}
14.602 +\begin{verbatim}
14.603 +/* mplsamp1.c */
14.604 +
14.605 +#include <stdio.h>
14.606 +#include <stdlib.h>
14.607 +#include <glpk.h>
14.608 +
14.609 +int main(void)
14.610 +{ glp_prob *lp;
14.611 + glp_tran *tran;
14.612 + int ret;
14.613 + lp = glp_create_prob();
14.614 + tran = glp_mpl_alloc_wksp();
14.615 + ret = glp_mpl_read_model(tran, "egypt.mod", 0);
14.616 + if (ret != 0)
14.617 + { fprintf(stderr, "Error on translating model\n");
14.618 + goto skip;
14.619 + }
14.620 + ret = glp_mpl_generate(tran, NULL);
14.621 + if (ret != 0)
14.622 + { fprintf(stderr, "Error on generating model\n");
14.623 + goto skip;
14.624 + }
14.625 + glp_mpl_build_prob(tran, lp);
14.626 + ret = glp_write_mps(lp, GLP_MPS_FILE, NULL, "egypt.mps");
14.627 + if (ret != 0)
14.628 + fprintf(stderr, "Error on writing MPS file\n");
14.629 +skip: glp_mpl_free_wksp(tran);
14.630 + glp_delete_prob(lp);
14.631 + return 0;
14.632 +}
14.633 +
14.634 +/* eof */
14.635 +\end{verbatim}
14.636 +\end{small}
14.637 +
14.638 +\subsubsection*{Example 2}
14.639 +
14.640 +In this example the program reads model section from file
14.641 +\verb|sudoku.mod|\footnote{This is an example model which is included
14.642 +in the GLPK distribution along with alternative data file
14.643 +{\tt sudoku.dat}.} ignoring data section in this file, reads alternative
14.644 +data section from file \verb|sudoku.dat|, solves the problem instance
14.645 +and passes the solution found back to the model.
14.646 +
14.647 +\begin{small}
14.648 +\begin{verbatim}
14.649 +/* mplsamp2.c */
14.650 +
14.651 +#include <stdio.h>
14.652 +#include <stdlib.h>
14.653 +#include <glpk.h>
14.654 +
14.655 +int main(void)
14.656 +{ glp_prob *mip;
14.657 + glp_tran *tran;
14.658 + int ret;
14.659 + mip = glp_create_prob();
14.660 + tran = glp_mpl_alloc_wksp();
14.661 + ret = glp_mpl_read_model(tran, "sudoku.mod", 1);
14.662 + if (ret != 0)
14.663 + { fprintf(stderr, "Error on translating model\n");
14.664 + goto skip;
14.665 + }
14.666 + ret = glp_mpl_read_data(tran, "sudoku.dat");
14.667 + if (ret != 0)
14.668 + { fprintf(stderr, "Error on translating data\n");
14.669 + goto skip;
14.670 + }
14.671 + ret = glp_mpl_generate(tran, NULL);
14.672 + if (ret != 0)
14.673 + { fprintf(stderr, "Error on generating model\n");
14.674 + goto skip;
14.675 + }
14.676 + glp_mpl_build_prob(tran, mip);
14.677 + glp_simplex(mip, NULL);
14.678 + glp_intopt(mip, NULL);
14.679 + ret = glp_mpl_postsolve(tran, mip, GLP_MIP);
14.680 + if (ret != 0)
14.681 + fprintf(stderr, "Error on postsolving model\n");
14.682 +skip: glp_mpl_free_wksp(tran);
14.683 + glp_delete_prob(mip);
14.684 + return 0;
14.685 +}
14.686 +
14.687 +/* eof */
14.688 +\end{verbatim}
14.689 +\end{small}
14.690 +
14.691 +\subsection{glp\_mpl\_alloc\_wksp---allocate the translator workspace}
14.692 +
14.693 +\subsubsection*{Synopsis}
14.694 +
14.695 +\begin{verbatim}
14.696 +glp_tran *glp_mpl_alloc_wksp(void);
14.697 +\end{verbatim}
14.698 +
14.699 +\subsubsection*{Description}
14.700 +
14.701 +The routine \verb|glp_mpl_alloc_wksp| allocates the MathProg translator
14.702 +work\-space. (Note that multiple instances of the workspace may be
14.703 +allocated, if necessary.)
14.704 +
14.705 +\subsubsection*{Returns}
14.706 +
14.707 +The routine returns a pointer to the workspace, which should be used in
14.708 +all subsequent operations.
14.709 +
14.710 +\subsection{glp\_mpl\_read\_model---read and translate model section}
14.711 +
14.712 +\subsubsection*{Synopsis}
14.713 +
14.714 +\begin{verbatim}
14.715 +int glp_mpl_read_model(glp_tran *tran, const char *fname,
14.716 + int skip);
14.717 +\end{verbatim}
14.718 +
14.719 +\subsubsection*{Description}
14.720 +
14.721 +The routine \verb|glp_mpl_read_model| reads model section and,
14.722 +optionally, data section, which may follow the model section, from a
14.723 +text file, whose name is the character string \verb|fname|, performs
14.724 +translation of model statements and data blocks, and stores all the
14.725 +information in the workspace.
14.726 +
14.727 +The parameter \verb|skip| is a flag. If the input file contains the
14.728 +data section and this flag is non-zero, the data section is not read as
14.729 +if there were no data section and a warning message is printed. This
14.730 +allows reading data section(s) from other file(s).
14.731 +
14.732 +\subsubsection*{Returns}
14.733 +
14.734 +If the operation is successful, the routine returns zero. Otherwise
14.735 +the routine prints an error message and returns non-zero.
14.736 +
14.737 +\subsection{glp\_mpl\_read\_data---read and translate data section}
14.738 +
14.739 +\subsubsection*{Synopsis}
14.740 +
14.741 +\begin{verbatim}
14.742 +int glp_mpl_read_data(glp_tran *tran, const char *fname);
14.743 +\end{verbatim}
14.744 +
14.745 +\subsubsection*{Description}
14.746 +
14.747 +The routine \verb|glp_mpl_read_data| reads data section from a text
14.748 +file, whose name is the character string \verb|fname|, performs
14.749 +translation of data blocks, and stores the data read in the translator
14.750 +workspace. If necessary, this routine may be called more than once.
14.751 +
14.752 +\subsubsection*{Returns}
14.753 +
14.754 +If the operation is successful, the routine returns zero. Otherwise
14.755 +the routine prints an error message and returns non-zero.
14.756 +
14.757 +\subsection{glp\_mpl\_generate---generate the model}
14.758 +
14.759 +\subsubsection*{Synopsis}
14.760 +
14.761 +\begin{verbatim}
14.762 +int glp_mpl_generate(glp_tran *tran, const char *fname);
14.763 +\end{verbatim}
14.764 +
14.765 +\subsubsection*{Description}
14.766 +
14.767 +The routine \verb|glp_mpl_generate| generates the model using its
14.768 +description stored in the translator workspace. This operation means
14.769 +generating all variables, constraints, and objectives, executing check
14.770 +and display statements, which precede the solve statement (if it is
14.771 +presented).
14.772 +
14.773 +The character string \verb|fname| specifies the name of an output text
14.774 +file, to which output produced by display statements should be written.
14.775 +If \verb|fname| is \verb|NULL|, the output is sent to the terminal.
14.776 +
14.777 +\subsubsection*{Returns}
14.778 +
14.779 +If the operation is successful, the routine returns zero. Otherwise
14.780 +the routine prints an error message and returns non-zero.
14.781 +
14.782 +\subsection{glp\_mpl\_build\_prob---build problem instance from the
14.783 +model}
14.784 +
14.785 +\subsubsection*{Synopsis}
14.786 +
14.787 +\begin{verbatim}
14.788 +void glp_mpl_build_prob(glp_tran *tran, glp_prob *prob);
14.789 +\end{verbatim}
14.790 +
14.791 +\subsubsection*{Description}
14.792 +
14.793 +The routine \verb|glp_mpl_build_prob| obtains all necessary information
14.794 +from the translator workspace and stores it in the specified problem
14.795 +object \verb|prob|. Note that before building the current content of
14.796 +the problem object is erased with the routine \verb|glp_erase_prob|.
14.797 +
14.798 +\subsection{glp\_mpl\_postsolve---postsolve the model}
14.799 +
14.800 +\subsubsection*{Synopsis}
14.801 +
14.802 +\begin{verbatim}
14.803 +int glp_mpl_postsolve(glp_tran *tran, glp_prob *prob,
14.804 + int sol);
14.805 +\end{verbatim}
14.806 +
14.807 +\subsubsection*{Description}
14.808 +
14.809 +The routine \verb|glp_mpl_postsolve| copies the solution from the
14.810 +specified problem object \verb|prob| to the translator workspace and
14.811 +then executes all the remaining model statements, which follow the
14.812 +solve statement.
14.813 +
14.814 +The parameter \verb|sol| specifies which solution should be copied
14.815 +from the problem object to the workspace as follows:
14.816 +
14.817 +\begin{tabular}{@{}ll}
14.818 +\verb|GLP_SOL| & basic solution; \\
14.819 +\verb|GLP_IPT| & interior-point solution; \\
14.820 +\verb|GLP_MIP| & mixed integer solution. \\
14.821 +\end{tabular}
14.822 +
14.823 +\subsubsection*{Returns}
14.824 +
14.825 +If the operation is successful, the routine returns zero. Otherwise
14.826 +the routine prints an error message and returns non-zero.
14.827 +
14.828 +\subsection{glp\_mpl\_free\_wksp---free the translator workspace}
14.829 +
14.830 +\subsubsection*{Synopsis}
14.831 +
14.832 +\begin{verbatim}
14.833 +void glp_mpl_free_wksp(glp_tran *tran);
14.834 +\end{verbatim}
14.835 +
14.836 +\subsubsection*{Description}
14.837 +
14.838 +The routine \verb|glp_mpl_free_wksp| frees all the memory allocated to
14.839 +the translator workspace. It also frees all other resources, which are
14.840 +still used by the translator.
14.841 +
14.842 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14.843 +
14.844 +\newpage
14.845 +
14.846 +\section{Problem solution reading/writing routines}
14.847 +
14.848 +\subsection{glp\_print\_sol---write basic solution in printable format}
14.849 +
14.850 +\subsubsection*{Synopsis}
14.851 +
14.852 +\begin{verbatim}
14.853 +int glp_print_sol(glp_prob *lp, const char *fname);
14.854 +\end{verbatim}
14.855 +
14.856 +\subsubsection*{Description}
14.857 +
14.858 +The routine \verb|glp_print_sol writes| the current basic solution of
14.859 +an LP problem, which is specified by the pointer \verb|lp|, to a text
14.860 +file, whose name is the character string \verb|fname|, in printable
14.861 +format.
14.862 +
14.863 +Information reported by the routine \verb|glp_print_sol| is intended
14.864 +mainly for visual analysis.
14.865 +
14.866 +\subsubsection*{Returns}
14.867 +
14.868 +If no errors occurred, the routine returns zero. Otherwise the routine
14.869 +prints an error message and returns non-zero.
14.870 +
14.871 +\subsection{glp\_read\_sol---read basic solution from text file}
14.872 +
14.873 +\subsubsection*{Synopsis}
14.874 +
14.875 +\begin{verbatim}
14.876 +int glp_read_sol(glp_prob *lp, const char *fname);
14.877 +\end{verbatim}
14.878 +
14.879 +\subsubsection*{Description}
14.880 +
14.881 +The routine \verb|glp_read_sol| reads basic solution from a text file
14.882 +whose name is specified by the parameter \verb|fname| into the problem
14.883 +object.
14.884 +
14.885 +For the file format see description of the routine \verb|glp_write_sol|.
14.886 +
14.887 +\subsubsection*{Returns}
14.888 +
14.889 +On success the routine returns zero, otherwise non-zero.
14.890 +
14.891 +\newpage
14.892 +
14.893 +\subsection{glp\_write\_sol---write basic solution to text file}
14.894 +
14.895 +\subsubsection*{Synopsis}
14.896 +
14.897 +\begin{verbatim}
14.898 +int glp_write_sol(glp_prob *lp, const char *fname);
14.899 +\end{verbatim}
14.900 +
14.901 +\subsubsection*{Description}
14.902 +
14.903 +The routine \verb|glp_write_sol| writes the current basic solution to a
14.904 +text file whose name is specified by the parameter \verb|fname|. This
14.905 +file can be read back with the routine \verb|glp_read_sol|.
14.906 +
14.907 +\subsubsection*{Returns}
14.908 +
14.909 +On success the routine returns zero, otherwise non-zero.
14.910 +
14.911 +\subsubsection*{File format}
14.912 +
14.913 +The file created by the routine \verb|glp_write_sol| is a plain text
14.914 +file, which contains the following information:
14.915 +
14.916 +\begin{verbatim}
14.917 + m n
14.918 + p_stat d_stat obj_val
14.919 + r_stat[1] r_prim[1] r_dual[1]
14.920 + . . .
14.921 + r_stat[m] r_prim[m] r_dual[m]
14.922 + c_stat[1] c_prim[1] c_dual[1]
14.923 + . . .
14.924 + c_stat[n] c_prim[n] c_dual[n]
14.925 +\end{verbatim}
14.926 +
14.927 +\noindent
14.928 +where:
14.929 +
14.930 +\noindent
14.931 +$m$ is the number of rows (auxiliary variables);
14.932 +
14.933 +\noindent
14.934 +$n$ is the number of columns (structural variables);
14.935 +
14.936 +\noindent
14.937 +\verb|p_stat| is the primal status of the basic solution
14.938 +(\verb|GLP_UNDEF| = 1, \verb|GLP_FEAS| = 2, \verb|GLP_INFEAS| = 3, or
14.939 +\verb|GLP_NOFEAS| = 4);
14.940 +
14.941 +\noindent
14.942 +\verb|d_stat| is the dual status of the basic solution
14.943 +(\verb|GLP_UNDEF| = 1, \verb|GLP_FEAS| = 2, \verb|GLP_INFEAS| = 3, or
14.944 +\verb|GLP_NOFEAS| = 4);
14.945 +
14.946 +\noindent
14.947 +\verb|obj_val| is the objective value;
14.948 +
14.949 +\noindent
14.950 +\verb|r_stat[i]|, $i=1,\dots,m$, is the status of $i$-th row
14.951 +(\verb|GLP_BS| = 1, \verb|GLP_NL| = 2, \verb|GLP_NU| = 3,
14.952 +\verb|GLP_NF| = 4, or \verb|GLP_NS| = 5);
14.953 +
14.954 +\noindent
14.955 +\verb|r_prim[i]|, $i=1,\dots,m$, is the primal value of $i$-th row;
14.956 +
14.957 +\noindent
14.958 +\verb|r_dual[i]|, $i=1,\dots,m$, is the dual value of $i$-th row;
14.959 +
14.960 +\noindent
14.961 +\verb|c_stat[j]|, $j=1,\dots,n$, is the status of $j$-th column
14.962 +(\verb|GLP_BS| = 1, \verb|GLP_NL| = 2, \verb|GLP_NU| = 3,
14.963 +\verb|GLP_NF| = 4, or \verb|GLP_NS| = 5);
14.964 +
14.965 +\noindent
14.966 +\verb|c_prim[j]|, $j=1,\dots,n$, is the primal value of $j$-th column;
14.967 +
14.968 +\noindent
14.969 +\verb|c_dual[j]|, $j=1,\dots,n$, is the dual value of $j$-th column.
14.970 +
14.971 +\subsection{glp\_print\_ipt---write interior-point solution in
14.972 +printable format}
14.973 +
14.974 +\subsubsection*{Synopsis}
14.975 +
14.976 +\begin{verbatim}
14.977 +int glp_print_ipt(glp_prob *lp, const char *fname);
14.978 +\end{verbatim}
14.979 +
14.980 +\subsubsection*{Description}
14.981 +
14.982 +The routine \verb|glp_print_ipt| writes the current interior point
14.983 +solution of an LP problem, which the parameter \verb|lp| points to, to
14.984 +a text file, whose name is the character string \verb|fname|, in
14.985 +printable format.
14.986 +
14.987 +Information reported by the routine \verb|glp_print_ipt| is intended
14.988 +mainly for visual analysis.
14.989 +
14.990 +\subsubsection*{Returns}
14.991 +
14.992 +If no errors occurred, the routine returns zero. Otherwise the routine
14.993 +prints an error message and returns non-zero.
14.994 +
14.995 +\subsection{glp\_read\_ipt---read interior-point solution from text
14.996 +file}
14.997 +
14.998 +\subsubsection*{Synopsis}
14.999 +
14.1000 +\begin{verbatim}
14.1001 +int glp_read_ipt(glp_prob *lp, const char *fname);
14.1002 +\end{verbatim}
14.1003 +
14.1004 +\subsubsection*{Description}
14.1005 +
14.1006 +The routine \verb|glp_read_ipt| reads interior-point solution from a
14.1007 +text file whose name is specified by the parameter \verb|fname| into the
14.1008 +problem object.
14.1009 +
14.1010 +For the file format see description of the routine \verb|glp_write_ipt|.
14.1011 +
14.1012 +\subsubsection*{Returns}
14.1013 +
14.1014 +On success the routine returns zero, otherwise non-zero.
14.1015 +
14.1016 +\subsection{glp\_write\_ipt---write interior-point solution to text
14.1017 +file}
14.1018 +
14.1019 +\subsubsection*{Synopsis}
14.1020 +
14.1021 +\begin{verbatim}
14.1022 +int glp_write_ipt(glp_prob *lp, const char *fname);
14.1023 +\end{verbatim}
14.1024 +
14.1025 +\subsubsection*{Description}
14.1026 +
14.1027 +The routine \verb|glp_write_ipt| writes the current interior-point
14.1028 +solution to a text file whose name is specified by the parameter
14.1029 +\verb|fname|. This file can be read back with the routine
14.1030 +\verb|glp_read_ipt|.
14.1031 +
14.1032 +\subsubsection*{Returns}
14.1033 +
14.1034 +On success the routine returns zero, otherwise non-zero.
14.1035 +
14.1036 +\subsubsection*{File format}
14.1037 +
14.1038 +The file created by the routine \verb|glp_write_ipt| is a plain text
14.1039 +file, which contains the following information:
14.1040 +
14.1041 +\begin{verbatim}
14.1042 + m n
14.1043 + stat obj_val
14.1044 + r_prim[1] r_dual[1]
14.1045 + . . .
14.1046 + r_prim[m] r_dual[m]
14.1047 + c_prim[1] c_dual[1]
14.1048 + . . .
14.1049 + c_prim[n] c_dual[n]
14.1050 +\end{verbatim}
14.1051 +
14.1052 +\noindent
14.1053 +where:
14.1054 +
14.1055 +\noindent
14.1056 +$m$ is the number of rows (auxiliary variables);
14.1057 +
14.1058 +\noindent
14.1059 +$n$ is the number of columns (structural variables);
14.1060 +
14.1061 +\noindent
14.1062 +\verb|stat| is the solution status (\verb|GLP_UNDEF| = 1 or
14.1063 +\verb|GLP_OPT| = 5);
14.1064 +
14.1065 +\noindent
14.1066 +\verb|obj_val| is the objective value;
14.1067 +
14.1068 +\noindent
14.1069 +\verb|r_prim[i]|, $i=1,\dots,m$, is the primal value of $i$-th row;
14.1070 +
14.1071 +\noindent
14.1072 +\verb|r_dual[i]|, $i=1,\dots,m$, is the dual value of $i$-th row;
14.1073 +
14.1074 +\noindent
14.1075 +\verb|c_prim[j]|, $j=1,\dots,n$, is the primal value of $j$-th column;
14.1076 +
14.1077 +\noindent
14.1078 +\verb|c_dual[j]|, $j=1,\dots,n$, is the dual value of $j$-th column.
14.1079 +
14.1080 +\subsection{glp\_print\_mip---write MIP solution in printable format}
14.1081 +
14.1082 +\subsubsection*{Synopsis}
14.1083 +
14.1084 +\begin{verbatim}
14.1085 +int glp_print_mip(glp_prob *lp, const char *fname);
14.1086 +\end{verbatim}
14.1087 +
14.1088 +\subsubsection*{Description}
14.1089 +
14.1090 +The routine \verb|glp_print_mip| writes a best known integer solution
14.1091 +of a MIP problem, which is specified by the pointer \verb|lp|, to a text
14.1092 +file, whose name is the character string \verb|fname|, in printable
14.1093 +format.
14.1094 +
14.1095 +Information reported by the routine \verb|glp_print_mip| is intended
14.1096 +mainly for visual analysis.
14.1097 +
14.1098 +\subsubsection*{Returns}
14.1099 +
14.1100 +If no errors occurred, the routine returns zero. Otherwise the routine
14.1101 +prints an error message and returns non-zero.
14.1102 +
14.1103 +\newpage
14.1104 +
14.1105 +\subsection{glp\_read\_mip---read MIP solution from text file}
14.1106 +
14.1107 +\subsubsection*{Synopsis}
14.1108 +
14.1109 +\begin{verbatim}
14.1110 +int glp_read_mip(glp_prob *mip, const char *fname);
14.1111 +\end{verbatim}
14.1112 +
14.1113 +\subsubsection*{Description}
14.1114 +
14.1115 +The routine \verb|glp_read_mip| reads MIP solution from a text file
14.1116 +whose name is specified by the parameter \verb|fname| into the problem
14.1117 +object.
14.1118 +
14.1119 +For the file format see description of the routine \verb|glp_write_mip|.
14.1120 +
14.1121 +\subsubsection*{Returns}
14.1122 +
14.1123 +On success the routine returns zero, otherwise non-zero.
14.1124 +
14.1125 +\subsection{glp\_write\_mip---write MIP solution to text file}
14.1126 +
14.1127 +\subsubsection*{Synopsis}
14.1128 +
14.1129 +\begin{verbatim}
14.1130 +int glp_write_mip(glp_prob *mip, const char *fname);
14.1131 +\end{verbatim}
14.1132 +
14.1133 +\subsubsection*{Description}
14.1134 +
14.1135 +The routine \verb|glp_write_mip| writes the current MIP solution to a
14.1136 +text file whose name is specified by the parameter \verb|fname|. This
14.1137 +file can be read back with the routine \verb|glp_read_mip|.
14.1138 +
14.1139 +\subsubsection*{Returns}
14.1140 +
14.1141 +On success the routine returns zero, otherwise non-zero.
14.1142 +
14.1143 +\subsubsection*{File format}
14.1144 +
14.1145 +The file created by the routine \verb|glp_write_sol| is a plain text
14.1146 +file, which contains the following information:
14.1147 +
14.1148 +\begin{verbatim}
14.1149 + m n
14.1150 + stat obj_val
14.1151 + r_val[1]
14.1152 + . . .
14.1153 + r_val[m]
14.1154 + c_val[1]
14.1155 + . . .
14.1156 + c_val[n]
14.1157 +\end{verbatim}
14.1158 +
14.1159 +\noindent
14.1160 +where:
14.1161 +
14.1162 +\noindent
14.1163 +$m$ is the number of rows (auxiliary variables);
14.1164 +
14.1165 +\noindent
14.1166 +$n$ is the number of columns (structural variables);
14.1167 +
14.1168 +\noindent
14.1169 +\verb|stat| is the solution status (\verb|GLP_UNDEF| = 1,
14.1170 +\verb|GLP_FEAS| = 2, \verb|GLP_NOFEAS| = 4, or \verb|GLP_OPT| = 5);
14.1171 +
14.1172 +\noindent
14.1173 +\verb|obj_val| is the objective value;
14.1174 +
14.1175 +\noindent
14.1176 +\verb|r_val[i]|, $i=1,\dots,m$, is the value of $i$-th row;
14.1177 +
14.1178 +\noindent
14.1179 +\verb|c_val[j]|, $j=1,\dots,n$, is the value of $j$-th column.
14.1180 +
14.1181 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14.1182 +
14.1183 +\newpage
14.1184 +
14.1185 +\section{Post-optimal analysis routines}
14.1186 +
14.1187 +\subsection{glp\_print\_ranges---print sensitivity analysis report}
14.1188 +
14.1189 +\subsubsection*{Synopsis}
14.1190 +
14.1191 +\begin{verbatim}
14.1192 +int glp_print_ranges(glp_prob *P, int len, const int list[],
14.1193 + int flags, const char *fname);
14.1194 +\end{verbatim}
14.1195 +
14.1196 +\subsubsection*{Description}
14.1197 +
14.1198 +The routine \verb|glp_print_ranges| performs sensitivity analysis of
14.1199 +current optimal basic solution and writes the analysis report in
14.1200 +human-readable format to a text file, whose name is the character
14.1201 +string {\it fname}. (Detailed description of the report structure is
14.1202 +given below.)
14.1203 +
14.1204 +The parameter {\it len} specifies the length of the row/column list.
14.1205 +
14.1206 +The array {\it list} specifies ordinal number of rows and columns to be
14.1207 +analyzed. The ordinal numbers should be passed in locations
14.1208 +{\it list}[1], {\it list}[2], \dots, {\it list}[{\it len}]. Ordinal
14.1209 +numbers from 1 to $m$ refer to rows, and ordinal numbers from $m+1$ to
14.1210 +$m+n$ refer to columns, where $m$ and $n$ are, resp., the total number
14.1211 +of rows and columns in the problem object. Rows and columns appear in
14.1212 +the analysis report in the same order as they follow in the array list.
14.1213 +
14.1214 +It is allowed to specify $len=0$, in which case the array {\it list} is
14.1215 +not used (so it can be specified as \verb|NULL|), and the routine
14.1216 +performs analysis for all rows and columns of the problem object.
14.1217 +
14.1218 +The parameter {\it flags} is reserved for use in the future and must be
14.1219 +specified as zero.
14.1220 +
14.1221 +On entry to the routine \verb|glp_print_ranges| the current basic
14.1222 +solution must be optimal and the basis factorization must exist.
14.1223 +The application program can check that with the routine
14.1224 +\verb|glp_bf_exists|, and if the factorization does
14.1225 +not exist, compute it with the routine \verb|glp_factorize|. Note that
14.1226 +if the LP preprocessor is not used, on normal exit from the simplex
14.1227 +solver routine \verb|glp_simplex| the basis factorization always exists.
14.1228 +
14.1229 +\subsubsection*{Returns}
14.1230 +
14.1231 +If the operation was successful, the routine \verb|glp_print_ranges|
14.1232 +returns zero. Otherwise, it prints an error message and returns
14.1233 +non-zero.
14.1234 +
14.1235 +\subsubsection*{Analysis report example}
14.1236 +
14.1237 +An example of the sensitivity analysis report is shown on the next two
14.1238 +pages. This example corresponds to the example of LP problem described
14.1239 +in Subsection ``Example of MPS file''.
14.1240 +
14.1241 +\subsubsection*{Structure of the analysis report}
14.1242 +
14.1243 +For each row and column specified in the array {\it list} the routine
14.1244 +prints two lines containing generic information and analysis
14.1245 +information, which depends on the status of corresponding row or column.
14.1246 +
14.1247 +Note that analysis of a row is analysis of its auxiliary variable,
14.1248 +which is equal to the row linear form $\sum a_jx_j$, and analysis of
14.1249 +a column is analysis of corresponding structural variable. Therefore,
14.1250 +formally, on performing the sensitivity analysis there is no difference
14.1251 +between rows and columns.
14.1252 +
14.1253 +\bigskip
14.1254 +
14.1255 +\noindent
14.1256 +{\it Generic information}
14.1257 +
14.1258 +\medskip
14.1259 +
14.1260 +\noindent
14.1261 +{\tt No.} is the row or column ordinal number in the problem object.
14.1262 +Rows are numbered from 1 to $m$, and columns are numbered from 1 to $n$,
14.1263 +where $m$ and $n$ are, resp., the total number of rows and columns in
14.1264 +the problem object.
14.1265 +
14.1266 +\medskip
14.1267 +
14.1268 +\noindent
14.1269 +{\tt Row name} is the symbolic name assigned to the row. If the row has
14.1270 +no name assigned, this field contains blanks.
14.1271 +
14.1272 +\medskip
14.1273 +
14.1274 +\noindent
14.1275 +{\tt Column name} is the symbolic name assigned to the column. If the
14.1276 +column has no name assigned, this field contains blanks.
14.1277 +
14.1278 +\medskip
14.1279 +
14.1280 +\noindent
14.1281 +{\tt St} is the status of the row or column in the optimal solution:
14.1282 +
14.1283 +{\tt BS} --- non-active constraint (row), basic column;
14.1284 +
14.1285 +{\tt NL} --- inequality constraint having its lower right-hand side
14.1286 +active (row), non-basic column having its lower bound active;
14.1287 +
14.1288 +{\tt NU} --- inequality constraint having its upper right-hand side
14.1289 +active (row), non-basic column having its upper bound active;
14.1290 +
14.1291 +{\tt NS} --- active equality constraint (row), non-basic fixed column.
14.1292 +
14.1293 +{\tt NF} --- active free row, non-basic free (unbounded) column. (This
14.1294 +case means that the optimal solution is dual degenerate.)
14.1295 +
14.1296 +\medskip
14.1297 +
14.1298 +\noindent
14.1299 +{\tt Activity} is the (primal) value of the auxiliary variable (row) or
14.1300 +structural variable (column) in the optimal solution.
14.1301 +
14.1302 +\medskip
14.1303 +
14.1304 +\noindent
14.1305 +{\tt Slack} is the (primal) value of the row slack variable.
14.1306 +
14.1307 +\medskip
14.1308 +
14.1309 +\noindent
14.1310 +{\tt Obj coef} is the objective coefficient of the column (structural
14.1311 +variable).
14.1312 +
14.1313 +\begin{landscape}
14.1314 +\begin{scriptsize}
14.1315 +\begin{verbatim}
14.1316 +GLPK 4.42 - SENSITIVITY ANALYSIS REPORT Page 1
14.1317 +
14.1318 +Problem: PLAN
14.1319 +Objective: VALUE = 296.2166065 (MINimum)
14.1320 +
14.1321 + No. Row name St Activity Slack Lower bound Activity Obj coef Obj value at Limiting
14.1322 + Marginal Upper bound range range break point variable
14.1323 +------ ------------ -- ------------- ------------- ------------- ------------- ------------- ------------- ------------
14.1324 + 1 VALUE BS 296.21661 -296.21661 -Inf 299.25255 -1.00000 . MN
14.1325 + . +Inf 296.21661 +Inf +Inf
14.1326 +
14.1327 + 2 YIELD NS 2000.00000 . 2000.00000 1995.06864 -Inf 296.28365 BIN3
14.1328 + -.01360 2000.00000 2014.03479 +Inf 296.02579 CU
14.1329 +
14.1330 + 3 FE NU 60.00000 . -Inf 55.89016 -Inf 306.77162 BIN4
14.1331 + -2.56823 60.00000 62.69978 2.56823 289.28294 BIN3
14.1332 +
14.1333 + 4 CU BS 83.96751 16.03249 -Inf 93.88467 -.30613 270.51157 MN
14.1334 + . 100.00000 79.98213 .21474 314.24798 BIN5
14.1335 +
14.1336 + 5 MN NU 40.00000 . -Inf 34.42336 -Inf 299.25255 BIN4
14.1337 + -.54440 40.00000 41.68691 .54440 295.29825 BIN3
14.1338 +
14.1339 + 6 MG BS 19.96029 10.03971 -Inf 24.74427 -1.79618 260.36433 BIN1
14.1340 + . 30.00000 9.40292 .28757 301.95652 MN
14.1341 +
14.1342 + 7 AL NL 1500.00000 . 1500.00000 1485.78425 -.25199 292.63444 CU
14.1343 + .25199 +Inf 1504.92126 +Inf 297.45669 BIN3
14.1344 +
14.1345 + 8 SI NL 250.00000 50.00000 250.00000 235.32871 -.48520 289.09812 CU
14.1346 + .48520 300.00000 255.06073 +Inf 298.67206 BIN3
14.1347 +\end{verbatim}
14.1348 +\end{scriptsize}
14.1349 +\end{landscape}
14.1350 +
14.1351 +\begin{landscape}
14.1352 +\begin{scriptsize}
14.1353 +\begin{verbatim}
14.1354 +GLPK 4.42 - SENSITIVITY ANALYSIS REPORT Page 2
14.1355 +
14.1356 +Problem: PLAN
14.1357 +Objective: VALUE = 296.2166065 (MINimum)
14.1358 +
14.1359 + No. Column name St Activity Obj coef Lower bound Activity Obj coef Obj value at Limiting
14.1360 + Marginal Upper bound range range break point variable
14.1361 +------ ------------ -- ------------- ------------- ------------- ------------- ------------- ------------- ------------
14.1362 + 1 BIN1 NL . .03000 . -28.82475 -.22362 288.90594 BIN4
14.1363 + .25362 200.00000 33.88040 +Inf 304.80951 BIN4
14.1364 +
14.1365 + 2 BIN2 BS 665.34296 .08000 . 802.22222 .01722 254.44822 BIN1
14.1366 + . 2500.00000 313.43066 .08863 301.95652 MN
14.1367 +
14.1368 + 3 BIN3 BS 490.25271 .17000 400.00000 788.61314 .15982 291.22807 MN
14.1369 + . 800.00000 -347.42857 .17948 300.86548 BIN5
14.1370 +
14.1371 + 4 BIN4 BS 424.18773 .12000 100.00000 710.52632 .10899 291.54745 MN
14.1372 + . 700.00000 -256.15524 .14651 307.46010 BIN1
14.1373 +
14.1374 + 5 BIN5 NL . .15000 . -201.78739 .13544 293.27940 BIN3
14.1375 + .01456 1500.00000 58.79586 +Inf 297.07244 BIN3
14.1376 +
14.1377 + 6 ALUM BS 299.63899 .21000 . 358.26772 .18885 289.87879 AL
14.1378 + . +Inf 112.40876 .22622 301.07527 MN
14.1379 +
14.1380 + 7 SILICON BS 120.57762 .38000 . 124.27093 .14828 268.27586 BIN5
14.1381 + . +Inf 85.54745 .46667 306.66667 MN
14.1382 +
14.1383 +End of report
14.1384 +\end{verbatim}
14.1385 +\end{scriptsize}
14.1386 +\end{landscape}
14.1387 +
14.1388 +\noindent
14.1389 +{\tt Marginal} is the reduced cost (dual activity) of the auxiliary
14.1390 +variable (row) or structural variable (column).
14.1391 +
14.1392 +\medskip
14.1393 +
14.1394 +\noindent
14.1395 +{\tt Lower bound} is the lower right-hand side (row) or lower bound
14.1396 +(column). If the row or column has no lower bound, this field contains
14.1397 +{\tt -Inf}.
14.1398 +
14.1399 +\medskip
14.1400 +
14.1401 +\noindent
14.1402 +{\tt Upper bound} is the upper right-hand side (row) or upper bound
14.1403 +(column). If the row or column has no upper bound, this field contains
14.1404 +{\tt +Inf}.
14.1405 +
14.1406 +\bigskip
14.1407 +
14.1408 +\noindent
14.1409 +{\it Sensitivity analysis of active bounds}
14.1410 +
14.1411 +\medskip
14.1412 +
14.1413 +\noindent
14.1414 +The sensitivity analysis of active bounds is performed only for rows,
14.1415 +which are active constraints, and only for non-basic columns, because
14.1416 +inactive constraints and basic columns have no active bounds.
14.1417 +
14.1418 +For every auxiliary (row) or structural (column) non-basic variable the
14.1419 +routine starts changing its active bound in both direction. The first
14.1420 +of the two lines in the report corresponds to decreasing, and the
14.1421 +second line corresponds to increasing of the active bound. Since the
14.1422 +variable being analyzed is non-basic, its activity, which is equal to
14.1423 +its active bound, also starts changing. This changing leads to changing
14.1424 +of basic (auxiliary and structural) variables, which depend on the
14.1425 +non-basic variable. The current basis remains primal feasible and
14.1426 +therefore optimal while values of all basic variables are primal
14.1427 +feasible, i.e. are within their bounds. Therefore, if some basic
14.1428 +variable called the {\it limiting variable} reaches its (lower or
14.1429 +upper) bound first, before any other basic variables, it thereby limits
14.1430 +further changing of the non-basic variable, because otherwise the
14.1431 +current basis would become primal infeasible. The point, at which this
14.1432 +happens, is called the {\it break point}. Note that there are two break
14.1433 +points: the lower break point, which corresponds to decreasing of the
14.1434 +non-basic variable, and the upper break point, which corresponds to
14.1435 +increasing of the non-basic variable.
14.1436 +
14.1437 +In the analysis report values of the non-basic variable (i.e. of its
14.1438 +active bound) being analyzed at both lower and upper break points are
14.1439 +printed in the field `{\tt Activity range}'. Corresponding values of
14.1440 +the objective function are printed in the field `{\tt Obj value at
14.1441 +break point}', and symbolic names of corresponding limiting basic
14.1442 +variables are printed in the field `{\tt Limiting variable}'.
14.1443 +If the active bound can decrease or/and increase unlimitedly, the field
14.1444 +`{\tt Activity range}' contains {\tt -Inf} or/and {\tt +Inf}, resp.
14.1445 +
14.1446 +For example (see the example report above), row SI is a double-sided
14.1447 +constraint, which is active on its lower bound (right-hand side), and
14.1448 +its activity in the optimal solution being equal to the lower bound is
14.1449 +250. The activity range for this row is $[235.32871,255.06073]$. This
14.1450 +means that the basis remains optimal while the lower bound is
14.1451 +increasing up to 255.06073, and further increasing is limited by
14.1452 +(structural) variable BIN3. If the lower bound reaches this upper break
14.1453 +point, the objective value becomes equal to 298.67206.
14.1454 +
14.1455 +Note that if the basis does not change, the objective function depends
14.1456 +on the non-basic variable linearly, and the per-unit change of the
14.1457 +objective function is the reduced cost (marginal value) of the
14.1458 +non-basic variable.
14.1459 +
14.1460 +\bigskip
14.1461 +
14.1462 +\noindent
14.1463 +{\it Sensitivity analysis of objective coefficients at non-basic
14.1464 +variables}
14.1465 +
14.1466 +\medskip
14.1467 +
14.1468 +\noindent
14.1469 +The sensitivity analysis of the objective coefficient at a non-basic
14.1470 +variable is quite simple, because in this case change in the objective
14.1471 +coefficient leads to equivalent change in the reduced cost (marginal
14.1472 +value).
14.1473 +
14.1474 +For every auxiliary (row) or structural (column) non-basic variable the
14.1475 +routine starts changing its objective coefficient in both direction.
14.1476 +(Note that auxiliary variables are not included in the objective
14.1477 +function and therefore always have zero objective coefficients.) The
14.1478 +first of the two lines in the report corresponds to decreasing, and the
14.1479 +second line corresponds to increasing of the objective coefficient.
14.1480 +This changing leads to changing of the reduced cost of the non-basic
14.1481 +variable to be analyzed and does affect reduced costs of all other
14.1482 +non-basic variables. The current basis remains dual feasible and
14.1483 +therefore optimal while the reduced cost keeps its sign. Therefore, if
14.1484 +the reduced cost reaches zero, it limits further changing of the
14.1485 +objective coefficient (if only the non-basic variable is non-fixed).
14.1486 +
14.1487 +In the analysis report minimal and maximal values of the objective
14.1488 +coefficient, on which the basis remains optimal, are printed in the
14.1489 +field `\verb|Obj coef range|'. If the objective coefficient can
14.1490 +decrease or/and increase unlimitedly, this field contains {\tt -Inf}
14.1491 +or/and {\tt +Inf}, resp.
14.1492 +
14.1493 +For example (see the example report above), column BIN5 is non-basic
14.1494 +having its lower bound active. Its objective coefficient is 0.15, and
14.1495 +reduced cost in the optimal solution 0.01456. The column lower bound
14.1496 +remains active while the column reduced cost remains non-negative,
14.1497 +thus, minimal value of the objective coefficient, on which the current
14.1498 +basis still remains optimal, is $0.15-0.01456=0.13644$, that is
14.1499 +indicated in the field `\verb|Obj coef range|'.
14.1500 +
14.1501 +\bigskip
14.1502 +
14.1503 +\noindent
14.1504 +{\it Sensitivity analysis of objective coefficients at basic variables}
14.1505 +
14.1506 +\medskip
14.1507 +
14.1508 +\noindent
14.1509 +To perform sensitivity analysis for every auxiliary (row) or structural
14.1510 +(column) variable the routine starts changing its objective coefficient
14.1511 +in both direction. (Note that auxiliary variables are not included in
14.1512 +the objective function and therefore always have zero objective
14.1513 +coefficients.) The first of the two lines in the report corresponds to
14.1514 +decreasing, and the second line corresponds to increasing of the
14.1515 +objective coefficient. This changing leads to changing of reduced costs
14.1516 +of non-basic variables. The current basis remains dual feasible and
14.1517 +therefore optimal while reduced costs of all non-basic variables
14.1518 +(except fixed variables) keep their signs. Therefore, if the reduced
14.1519 +cost of some non-basic non-fixed variable called the {\it limiting
14.1520 +variable} reaches zero first, before reduced cost of any other
14.1521 +non-basic non-fixed variable, it thereby limits further changing of the
14.1522 +objective coefficient, because otherwise the current basis would become
14.1523 +dual infeasible (non-optimal). The point, at which this happens, is
14.1524 +called the {\it break point}. Note that there are two break points: the
14.1525 +lower break point, which corresponds to decreasing of the objective
14.1526 +coefficient, and the upper break point, which corresponds to increasing
14.1527 +of the objective coefficient. Let the objective coefficient reach its
14.1528 +limit value and continue changing a bit further in the same direction
14.1529 +that makes the current basis dual infeasible (non-optimal). Then the
14.1530 +reduced cost of the non-basic limiting variable becomes ``a bit'' dual
14.1531 +infeasible that forces the limiting variable to enter the basis
14.1532 +replacing there some basic variable, which leaves the basis to keep its
14.1533 +primal feasibility. It should be understood that if we change the
14.1534 +current basis in this way exactly at the break point, both the current
14.1535 +and adjacent bases will be optimal with the same objective value,
14.1536 +because at the break point the limiting variable has zero reduced cost.
14.1537 +On the other hand, in the adjacent basis the value of the limiting
14.1538 +variable changes, because there it becomes basic, that leads to
14.1539 +changing of the value of the basic variable being analyzed. Note that
14.1540 +on determining the adjacent basis the bounds of the analyzed basic
14.1541 +variable are ignored as if it were a free (unbounded) variable, so it
14.1542 +cannot leave the current basis.
14.1543 +
14.1544 +In the analysis report lower and upper limits of the objective
14.1545 +coefficient at the basic variable being analyzed, when the basis
14.1546 +remains optimal, are printed in the field `{\tt Obj coef range}'.
14.1547 +Corresponding values of the objective function at both lower and upper
14.1548 +break points are printed in the field `{\tt Obj value at break point}',
14.1549 +symbolic names of corresponding non-basic limiting variables are
14.1550 +printed in the field `{\tt Limiting variable}', and values of the basic
14.1551 +variable, which it would take on in the adjacent bases (as was
14.1552 +explained above) are printed in the field `{\tt Activity range}'.
14.1553 +If the objective coefficient can increase or/and decrease unlimitedly,
14.1554 +the field `{\tt Obj coef range}' contains {\tt -Inf} and/or {\tt +Inf},
14.1555 +resp. It also may happen that no dual feasible adjacent basis exists
14.1556 +(i.e. on entering the basis the limiting variable can increase or
14.1557 +decrease unlimitedly), in which case the field `{\tt Activity range}'
14.1558 +contains {\tt -Inf} and/or {\tt +Inf}.
14.1559 +
14.1560 +\newpage
14.1561 +
14.1562 +For example (see the example report above), structural variable
14.1563 +(column) BIN3 is basic, its optimal value is 490.25271, and its
14.1564 +objective coefficient is 0.17. The objective coefficient range for this
14.1565 +column is $[0.15982,0.17948]$. This means that the basis remains
14.1566 +optimal while the objective coefficient is decreasing down to 0.15982,
14.1567 +and further decreasing is limited by (auxiliary) variable MN. If we
14.1568 +make the objective coefficient a bit less than 0.15982, the limiting
14.1569 +variable MN will enter the basis, and in that adjacent basis the
14.1570 +structural variable BIN3 will take on new optimal value 788.61314. At
14.1571 +the lower break point, where the objective coefficient is exactly
14.1572 +0.15982, the objective function takes on the value 291.22807 in both
14.1573 +the current and adjacent bases.
14.1574 +
14.1575 +Note that if the basis does not change, the objective function depends
14.1576 +on the objective coefficient at the basic variable linearly, and the
14.1577 +per-unit change of the objective function is the value of the basic
14.1578 +variable.
14.1579 +
14.1580 +%* eof *%
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
15.2 +++ b/doc/glpk04.tex Mon Dec 06 13:09:21 2010 +0100
15.3 @@ -0,0 +1,1411 @@
15.4 +%* glpk04.tex *%
15.5 +
15.6 +\chapter{Advanced API Routines}
15.7 +
15.8 +\section{Background}
15.9 +\label{basbgd}
15.10 +
15.11 +Using vector and matrix notations LP problem (1.1)---(1.3) (see Section
15.12 +\ref{seclp}, page \pageref{seclp}) can be stated as follows:
15.13 +
15.14 +\medskip
15.15 +
15.16 +\noindent
15.17 +\hspace{.5in} minimize (or maximize)
15.18 +$$z=c^Tx_S+c_0\eqno(3.1)$$
15.19 +\hspace{.5in} subject to linear constraints
15.20 +$$x_R=Ax_S\eqno(3.2)$$
15.21 +\hspace{.5in} and bounds of variables
15.22 +$$
15.23 +\begin{array}{l@{\ }c@{\ }l@{\ }c@{\ }l}
15.24 +l_R&\leq&x_R&\leq&u_R\\
15.25 +l_S&\leq&x_S&\leq&u_S\\
15.26 +\end{array}\eqno(3.3)
15.27 +$$
15.28 +where:
15.29 +
15.30 +\noindent
15.31 +$x_R=(x_1,\dots,x_m)$ is the vector of auxiliary variables;
15.32 +
15.33 +\noindent
15.34 +$x_S=(x_{m+1},\dots,x_{m+n})$ is the vector of structural
15.35 +variables;
15.36 +
15.37 +\noindent
15.38 +$z$ is the objective function;
15.39 +
15.40 +\noindent
15.41 +$c=(c_1,\dots,c_n)$ is the vector of objective coefficients;
15.42 +
15.43 +\noindent
15.44 +$c_0$ is the constant term (``shift'') of the objective function;
15.45 +
15.46 +\noindent
15.47 +$A=(a_{11},\dots,a_{mn})$ is the constraint matrix;
15.48 +
15.49 +\noindent
15.50 +$l_R=(l_1,\dots,l_m)$ is the vector of lower bounds of auxiliary
15.51 +variables;
15.52 +
15.53 +\noindent
15.54 +$u_R=(u_1,\dots,u_m)$ is the vector of upper bounds of auxiliary
15.55 +variables;
15.56 +
15.57 +\noindent
15.58 +$l_S=(l_{m+1},\dots,l_{m+n})$ is the vector of lower bounds of
15.59 +structural variables;
15.60 +
15.61 +\noindent
15.62 +$u_S=(u_{m+1},\dots,u_{m+n})$ is the vector of upper bounds of
15.63 +structural variables.
15.64 +
15.65 +\medskip
15.66 +
15.67 +From the simplex method's standpoint there is no difference between
15.68 +auxiliary and structural variables. This allows combining all these
15.69 +variables into one vector that leads to the following problem statement:
15.70 +
15.71 +\medskip
15.72 +
15.73 +\noindent
15.74 +\hspace{.5in} minimize (or maximize)
15.75 +$$z=(0\ |\ c)^Tx+c_0\eqno(3.4)$$
15.76 +\hspace{.5in} subject to linear constraints
15.77 +$$(I\ |-\!A)x=0\eqno(3.5)$$
15.78 +\hspace{.5in} and bounds of variables
15.79 +$$l\leq x\leq u\eqno(3.6)$$
15.80 +where:
15.81 +
15.82 +\noindent
15.83 +$x=(x_R\ |\ x_S)$ is the $(m+n)$-vector of (all) variables;
15.84 +
15.85 +\noindent
15.86 +$(0\ |\ c)$ is the $(m+n)$-vector of objective
15.87 +coefficients;\footnote{Subvector 0 corresponds to objective coefficients
15.88 +at auxiliary variables.}
15.89 +
15.90 +\noindent
15.91 +$(I\ |-\!A)$ is the {\it augmented} constraint
15.92 +$m\times(m+n)$-matrix;\footnote{Note that due to auxiliary variables
15.93 +matrix $(I\ |-\!A)$ contains the unity submatrix and therefore has full
15.94 +rank. This means, in particular, that the system (3.5) has no linearly
15.95 +dependent constraints.}
15.96 +
15.97 +\noindent
15.98 +$l=(l_R\ |\ l_S)$ is the $(m+n)$-vector of lower bounds of (all)
15.99 +variables;
15.100 +
15.101 +\noindent
15.102 +$u=(u_R\ |\ u_S)$ is the $(m+n)$-vector of upper bounds of (all)
15.103 +variables.
15.104 +
15.105 +\medskip
15.106 +
15.107 +By definition an {\it LP basic solution} geometrically is a point in
15.108 +the space of all variables, which is the intersection of planes
15.109 +corresponding to active constraints\footnote{A constraint is called
15.110 +{\it active} if in a given point it is satisfied as equality, otherwise
15.111 +it is called {\it inactive}.}. The space of all variables has the
15.112 +dimension $m+n$, therefore, to define some basic solution we have to
15.113 +define $m+n$ active constraints. Note that $m$ constraints (3.5) being
15.114 +linearly independent equalities are always active, so remaining $n$
15.115 +active constraints can be chosen only from bound constraints (3.6).
15.116 +
15.117 +A variable is called {\it non-basic}, if its (lower or upper) bound is
15.118 +active, otherwise it is called {\it basic}. Since, as was said above,
15.119 +exactly $n$ bound constraints must be active, in any basic solution
15.120 +there are always $n$ non-basic variables and $m$ basic variables.
15.121 +(Note that a free variable also can be non-basic. Although such
15.122 +variable has no bounds, we can think it as the difference between two
15.123 +non-negative variables, which both are non-basic in this case.)
15.124 +
15.125 +Now consider how to determine numeric values of all variables for a
15.126 +given basic solution.
15.127 +
15.128 +Let $\Pi$ be an appropriate permutation matrix of the order $(m+n)$.
15.129 +Then we can write:
15.130 +$$\left(\begin{array}{@{}c@{}}x_B\\x_N\\\end{array}\right)=
15.131 +\Pi\left(\begin{array}{@{}c@{}}x_R\\x_S\\\end{array}\right)=\Pi x,
15.132 +\eqno(3.7)$$
15.133 +where $x_B$ is the vector of basic variables, $x_N$ is the vector of
15.134 +non-basic variables, $x=(x_R\ |\ x_S)$ is the vector of all variables
15.135 +in the original order. In this case the system of linear constraints
15.136 +(3.5) can be rewritten as follows:
15.137 +$$(I\ |-\!A)\Pi^T\Pi x=0\ \ \ \Rightarrow\ \ \ (B\ |\ N)
15.138 +\left(\begin{array}{@{}c@{}}x_B\\x_N\\\end{array}\right)=0,\eqno(3.8)$$
15.139 +where
15.140 +$$(B\ |\ N)=(I\ |-\!A)\Pi^T.\eqno(3.9)$$
15.141 +Matrix $B$ is a square non-singular $m\times m$-matrix, which is
15.142 +composed from columns of the augmented constraint matrix corresponding
15.143 +to basic variables. It is called the {\it basis matrix} or simply the
15.144 +{\it basis}. Matrix $N$ is a rectangular $m\times n$-matrix, which is
15.145 +composed from columns of the augmented constraint matrix corresponding
15.146 +to non-basic variables.
15.147 +
15.148 +From (3.8) it follows that:
15.149 +$$Bx_B+Nx_N=0,\eqno(3.10)$$
15.150 +therefore,
15.151 +$$x_B=-B^{-1}Nx_N.\eqno(3.11)$$
15.152 +Thus, the formula (3.11) shows how to determine numeric values of basic
15.153 +variables $x_B$ assuming that non-basic variables $x_N$ are fixed on
15.154 +their active bounds.
15.155 +
15.156 +The $m\times n$-matrix
15.157 +$$\Xi=-B^{-1}N,\eqno(3.12)$$
15.158 +which appears in (3.11), is called the {\it simplex
15.159 +tableau}.\footnote{This definition corresponds to the GLPK
15.160 +implementation.} It shows how basic variables depend on non-basic
15.161 +variables:
15.162 +$$x_B=\Xi x_N.\eqno(3.13)$$
15.163 +
15.164 +The system (3.13) is equivalent to the system (3.5) in the sense that
15.165 +they both define the same set of points in the space of (primal)
15.166 +variables, which satisfy to these systems. If, moreover, values of all
15.167 +basic variables satisfy to their bound constraints (3.3), the
15.168 +corresponding basic solution is called {\it (primal) feasible},
15.169 +otherwise {\it (primal) infeasible}. It is understood that any (primal)
15.170 +feasible basic solution satisfy to all constraints (3.2) and (3.3).
15.171 +
15.172 +The LP theory says that if LP has optimal solution, it has (at least
15.173 +one) basic feasible solution, which corresponds to the optimum. And the
15.174 +most natural way to determine whether a given basic solution is optimal
15.175 +or not is to use the Karush---Kuhn---Tucker optimality conditions.
15.176 +
15.177 +\def\arraystretch{1.5}
15.178 +
15.179 +For the problem statement (3.4)---(3.6) the optimality conditions are
15.180 +the following:\footnote{These conditions can be appiled to any solution,
15.181 +not only to a basic solution.}
15.182 +$$(I\ |-\!A)x=0\eqno(3.14)$$
15.183 +$$(I\ |-\!A)^T\pi+\lambda_l+\lambda_u=\nabla z=(0\ |\ c)^T\eqno(3.15)$$
15.184 +$$l\leq x\leq u\eqno(3.16)$$
15.185 +$$\lambda_l\geq 0,\ \ \lambda_u\leq 0\ \ \mbox{(minimization)}
15.186 +\eqno(3.17)$$
15.187 +$$\lambda_l\leq 0,\ \ \lambda_u\geq 0\ \ \mbox{(maximization)}
15.188 +\eqno(3.18)$$
15.189 +$$(\lambda_l)_k(x_k-l_k)=0,\ \ (\lambda_u)_k(x_k-u_k)=0,\ \ k=1,2,\dots,
15.190 +m+n\eqno(3.19)$$
15.191 +where:
15.192 +$\pi=(\pi_1,\pi_2,\dots,\pi_m)$ is a $m$-vector of Lagrange
15.193 +multipliers for equality constraints (3.5);
15.194 +$\lambda_l=[(\lambda_l)_1,(\lambda_l)_2,\dots,(\lambda_l)_n]$ is a
15.195 +$n$-vector of Lagrange multipliers for lower bound constraints (3.6);
15.196 +$\lambda_u=[(\lambda_u)_1,(\lambda_u)_2,\dots,(\lambda_u)_n]$ is a
15.197 +$n$-vector of Lagrange multipliers for upper bound constraints (3.6).
15.198 +
15.199 +Condition (3.14) is the {\it primal} (original) system of equality
15.200 +constraints (3.5).
15.201 +
15.202 +Condition (3.15) is the {\it dual} system of equality constraints.
15.203 +It requires the gradient of the objective function to be a linear
15.204 +combination of normals to the planes defined by constraints of the
15.205 +original problem.
15.206 +
15.207 +Condition (3.16) is the primal (original) system of bound constraints
15.208 +(3.6).
15.209 +
15.210 +Condition (3.17) (or (3.18) in case of maximization) is the dual system
15.211 +of bound constraints.
15.212 +
15.213 +Condition (3.19) is the {\it complementary slackness condition}. It
15.214 +requires, for each original (auxiliary or structural) variable $x_k$,
15.215 +that either its (lower or upper) bound must be active, or zero bound of
15.216 +the corresponding Lagrange multiplier ($(\lambda_l)_k$ or
15.217 +$(\lambda_u)_k$) must be active.
15.218 +
15.219 +In GLPK two multipliers $(\lambda_l)_k$ and $(\lambda_u)_k$ for each
15.220 +primal (original) variable $x_k$, $k=1,2,\dots,m+n$, are combined into
15.221 +one multiplier:
15.222 +$$\lambda_k=(\lambda_l)_k+(\lambda_u)_k,\eqno(3.20)$$
15.223 +which is called a {\it dual variable} for $x_k$. This {\it cannot} lead
15.224 +to the ambiguity, because both lower and upper bounds of $x_k$ cannot be
15.225 +active at the same time,\footnote{If $x_k$ is a fixed variable, we can
15.226 +think it as double-bounded variable $l_k\leq x_k\leq u_k$, where
15.227 +$l_k=u_k.$} so at least one of $(\lambda_l)_k$ and $(\lambda_u)_k$ must
15.228 +be equal to zero, and because these multipliers have different signs,
15.229 +the combined multiplier, which is their sum, uniquely defines each of
15.230 +them.
15.231 +
15.232 +\def\arraystretch{1}
15.233 +
15.234 +Using dual variables $\lambda_k$ the dual system of bound constraints
15.235 +(3.17) and (3.18) can be written in the form of so called {\it ``rule of
15.236 +signs''} as follows:
15.237 +
15.238 +\begin{center}
15.239 +\begin{tabular}{|@{\,}c@{$\,$}|@{$\,$}c@{$\,$}|@{$\,$}c@{$\,$}|
15.240 +@{$\,$}c|c@{$\,$}|@{$\,$}c@{$\,$}|@{$\,$}c@{$\,$}|}
15.241 +\hline
15.242 +Original bound&\multicolumn{3}{c|}{Minimization}&\multicolumn{3}{c|}
15.243 +{Maximization}\\
15.244 +\cline{2-7}
15.245 +constraint&$(\lambda_l)_k$&$(\lambda_u)_k$&$(\lambda_l)_k+
15.246 +(\lambda_u)_k$&$(\lambda_l)_k$&$(\lambda_u)_k$&$(\lambda_l)_k+
15.247 +(\lambda_u)_k$\\
15.248 +\hline
15.249 +$-\infty<x_k<+\infty$&$=0$&$=0$&$\lambda_k=0$&$=0$&$=0$&$\lambda_k=0$\\
15.250 +$x_k\geq l_k$&$\geq 0$&$=0$&$\lambda_k\geq 0$&$\leq 0$&$=0$&$\lambda_k
15.251 +\leq0$\\
15.252 +$x_k\leq u_k$&$=0$&$\leq 0$&$\lambda_k\leq 0$&$=0$&$\geq 0$&$\lambda_k
15.253 +\geq0$\\
15.254 +$l_k\leq x_k\leq u_k$&$\geq 0$& $\leq 0$& $-\infty\!<\!\lambda_k\!<
15.255 +\!+\infty$
15.256 +&$\leq 0$& $\geq 0$& $-\infty\!<\!\lambda_k\!<\!+\infty$\\
15.257 +$x_k=l_k=u_k$&$\geq 0$& $\leq 0$& $-\infty\!<\!\lambda_k\!<\!+\infty$&
15.258 +$\leq 0$&
15.259 +$\geq 0$& $-\infty\!<\!\lambda_k\!<\!+\infty$\\
15.260 +\hline
15.261 +\end{tabular}
15.262 +\end{center}
15.263 +
15.264 +May note that each primal variable $x_k$ has its dual counterpart
15.265 +$\lambda_k$ and vice versa. This allows applying the same partition for
15.266 +the vector of dual variables as (3.7):
15.267 +$$\left(\begin{array}{@{}c@{}}\lambda_B\\\lambda_N\\\end{array}\right)=
15.268 +\Pi\lambda,\eqno(3.21)$$
15.269 +where $\lambda_B$ is a vector of dual variables for basic variables
15.270 +$x_B$, $\lambda_N$ is a vector of dual variables for non-basic variables
15.271 +$x_N$.
15.272 +
15.273 +By definition, bounds of basic variables are inactive constraints, so in
15.274 +any basic solution $\lambda_B=0$. Corresponding values of dual variables
15.275 +$\lambda_N$ for non-basic variables $x_N$ can be determined in the
15.276 +following way. From the dual system (3.15) we have:
15.277 +$$(I\ |-\!A)^T\pi+\lambda=(0\ |\ c)^T,\eqno(3.22)$$
15.278 +so multiplying both sides of (3.22) by matrix $\Pi$ gives:
15.279 +$$\Pi(I\ |-\!A)^T\pi+\Pi\lambda=\Pi(0\ |\ c)^T.\eqno(3.23)$$
15.280 +From (3.9) it follows that
15.281 +$$\Pi(I\ |-\!A)^T=[(I\ |-\!A)\Pi^T]^T=(B\ |\ N)^T.\eqno(3.24)$$
15.282 +Further, we can apply the partition (3.7) also to the vector of
15.283 +objective coefficients (see (3.4)):
15.284 +$$\left(\begin{array}{@{}c@{}}c_B\\c_N\\\end{array}\right)=
15.285 +\Pi\left(\begin{array}{@{}c@{}}0\\c\\\end{array}\right),\eqno(3.25)$$
15.286 +where $c_B$ is a vector of objective coefficients at basic variables,
15.287 +$c_N$ is a vector of objective coefficients at non-basic variables.
15.288 +Now, substituting (3.24), (3.21), and (3.25) into (3.23), leads to:
15.289 +$$(B\ |\ N)^T\pi+(\lambda_B\ |\ \lambda_N)^T=(c_B\ |\ c_N)^T,
15.290 +\eqno(3.26)$$
15.291 +and transposing both sides of (3.26) gives the system:
15.292 +$$\left(\begin{array}{@{}c@{}}B^T\\N^T\\\end{array}\right)\pi+
15.293 +\left(\begin{array}{@{}c@{}}\lambda_B\\\lambda_N\\\end{array}\right)=
15.294 +\left(\begin{array}{@{}c@{}}c_B\\c_T\\\end{array}\right),\eqno(3.27)$$
15.295 +which can be written as follows:
15.296 +$$\left\{
15.297 +\begin{array}{@{\ }r@{\ }c@{\ }r@{\ }c@{\ }l@{\ }}
15.298 +B^T\pi&+&\lambda_B&=&c_B\\
15.299 +N^T\pi&+&\lambda_N&=&c_N\\
15.300 +\end{array}
15.301 +\right.\eqno(3.28)
15.302 +$$
15.303 +Lagrange multipliers $\pi=(\pi_i)$ correspond to equality constraints
15.304 +(3.5) and therefore can have any sign. This allows resolving the first
15.305 +subsystem of (3.28) as follows:\footnote{$B^{-T}$ means $(B^T)^{-1}=
15.306 +(B^{-1})^T$.}
15.307 +$$\pi=B^{-T}(c_B-\lambda_B)=-B^{-T}\lambda_B+B^{-T}c_B,\eqno(3.29)$$
15.308 +and substitution of $\pi$ from (3.29) into the second subsystem of
15.309 +(3.28) gives:
15.310 +$$\lambda_N=-N^T\pi+c_N=N^TB^{-T}\lambda_B+(c_N-N^TB^{-T}c_B).
15.311 +\eqno(3.30)$$
15.312 +The latter system can be written in the following final form:
15.313 +$$\lambda_N=-\Xi^T\lambda_B+d,\eqno(3.31)$$
15.314 +where $\Xi$ is the simplex tableau (see (3.12)), and
15.315 +$$d=c_N-N^TB^{-T}c_B=c_N+\Xi^Tc_B\eqno(3.32)$$
15.316 +is the vector of so called {\it reduced costs} of non-basic variables.
15.317 +
15.318 +\pagebreak
15.319 +
15.320 +Above it was said that in any basic solution $\lambda_B=0$, so
15.321 +$\lambda_N=d$ as it follows from (3.31).
15.322 +
15.323 +The system (3.31) is equivalent to the system (3.15) in the sense that
15.324 +they both define the same set of points in the space of dual variables
15.325 +$\lambda$, which satisfy to these systems. If, moreover, values of all
15.326 +dual variables $\lambda_N$ (i.e. reduced costs $d$) satisfy to their
15.327 +bound constraints (i.e. to the ``rule of signs''; see the table above),
15.328 +the corresponding basic solution is called {\it dual feasible},
15.329 +otherwise {\it dual infeasible}. It is understood that any dual feasible
15.330 +solution satisfy to all constraints (3.15) and (3.17) (or (3.18) in case
15.331 +of maximization).
15.332 +
15.333 +It can be easily shown that the complementary slackness condition
15.334 +(3.19) is always satisfied for {\it any} basic solution. Therefore,
15.335 +a basic solution\footnote{It is assumed that a complete basic solution
15.336 +has the form $(x,\lambda)$, i.e. it includes primal as well as dual
15.337 +variables.} is {\it optimal} if and only if it is primal and dual
15.338 +feasible, because in this case it satifies to all the optimality
15.339 +conditions (3.14)---(3.19).
15.340 +
15.341 +\def\arraystretch{1.5}
15.342 +
15.343 +The meaning of reduced costs $d=(d_j)$ of non-basic variables can be
15.344 +explained in the following way. From (3.4), (3.7), and (3.25) it follows
15.345 +that:
15.346 +$$z=c_B^Tx_B+c_N^Tx_N+c_0.\eqno(3.33)$$
15.347 +Substituting $x_B$ from (3.11) into (3.33) we can eliminate basic
15.348 +variables and express the objective only through non-basic variables:
15.349 +$$
15.350 +\begin{array}{r@{\ }c@{\ }l}
15.351 +z&=&c_B^T(-B^{-1}Nx_N)+c_N^Tx_N+c_0=\\
15.352 +&=&(c_N^T-c_B^TB^{-1}N)x_N+c_0=\\
15.353 +&=&(c_N-N^TB^{-T}c_B)^Tx_N+c_0=\\
15.354 +&=&d^Tx_N+c_0.
15.355 +\end{array}\eqno(3.34)
15.356 +$$
15.357 +From (3.34) it is seen that reduced cost $d_j$ shows how the objective
15.358 +function $z$ depends on non-basic variable $(x_N)_j$ in the neighborhood
15.359 +of the current basic solution, i.e. while the current basis remains
15.360 +unchanged.
15.361 +
15.362 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15.363 +
15.364 +\newpage
15.365 +
15.366 +\section{LP basis routines}
15.367 +\label{lpbasis}
15.368 +
15.369 +\subsection{glp\_bf\_exists---check if the basis factorization exists}
15.370 +
15.371 +\subsubsection*{Synopsis}
15.372 +
15.373 +\begin{verbatim}
15.374 +int glp_bf_exists(glp_prob *lp);
15.375 +\end{verbatim}
15.376 +
15.377 +\subsubsection*{Returns}
15.378 +
15.379 +If the basis factorization for the current basis associated with the
15.380 +specified problem object exists and therefore is available for
15.381 +computations, the routine \verb|glp_bf_exists| returns non-zero.
15.382 +Otherwise the routine returns zero.
15.383 +
15.384 +\subsubsection*{Comments}
15.385 +
15.386 +Let the problem object have $m$ rows and $n$ columns. In GLPK the
15.387 +{\it basis matrix} $B$ is a square non-singular matrix of the order $m$,
15.388 +whose columns correspond to basic (auxiliary and/or structural)
15.389 +variables. It is defined by the following main
15.390 +equality:\footnote{For more details see Subsection \ref{basbgd},
15.391 +page \pageref{basbgd}.}
15.392 +$$(B\ |\ N)=(I\ |-\!A)\Pi^T,$$
15.393 +where $I$ is the unity matrix of the order $m$, whose columns correspond
15.394 +to auxiliary variables; $A$ is the original constraint
15.395 +$m\times n$-matrix, whose columns correspond to structural variables;
15.396 +$(I\ |-\!A)$ is the augmented constraint\linebreak
15.397 +$m\times(m+n)$-matrix, whose columns correspond to all (auxiliary and
15.398 +structural) variables following in the original order; $\Pi$ is a
15.399 +permutation matrix of the order $m+n$; and $N$ is a rectangular
15.400 +$m\times n$-matrix, whose columns correspond to non-basic (auxiliary
15.401 +and/or structural) variables.
15.402 +
15.403 +For various reasons it may be necessary to solve linear systems with
15.404 +matrix $B$. To provide this possibility the GLPK implementation
15.405 +maintains an invertable form of $B$ (that is, some representation of
15.406 +$B^{-1}$) called the {\it basis factorization}, which is an internal
15.407 +component of the problem object. Typically, the basis factorization is
15.408 +computed by the simplex solver, which keeps it in the problem object
15.409 +to be available for other computations.
15.410 +
15.411 +Should note that any changes in the problem object, which affects the
15.412 +basis matrix (e.g. changing the status of a row or column, changing
15.413 +a basic column of the constraint matrix, removing an active constraint,
15.414 +etc.), invalidates the basis factorization. So before calling any API
15.415 +routine, which uses the basis factorization, the application program
15.416 +must make sure (using the routine \verb|glp_bf_exists|) that the
15.417 +factorization exists and therefore available for computations.
15.418 +
15.419 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15.420 +
15.421 +\subsection{glp\_factorize---compute the basis factorization}
15.422 +
15.423 +\subsubsection*{Synopsis}
15.424 +
15.425 +\begin{verbatim}
15.426 +int glp_factorize(glp_prob *lp);
15.427 +\end{verbatim}
15.428 +
15.429 +\subsubsection*{Description}
15.430 +
15.431 +The routine \verb|glp_factorize| computes the basis factorization for
15.432 +the current basis associated with the specified problem
15.433 +object.\footnote{The current basis is defined by the current statuses
15.434 +of rows (auxiliary variables) and columns (structural variables).}
15.435 +
15.436 +The basis factorization is computed from ``scratch'' even if it exists,
15.437 +so the application program may use the routine \verb|glp_bf_exists|,
15.438 +and, if the basis factorization already exists, not to call the routine
15.439 +\verb|glp_factorize| to prevent an extra work.
15.440 +
15.441 +The routine \verb|glp_factorize| {\it does not} compute components of
15.442 +the basic solution (i.e. primal and dual values).
15.443 +
15.444 +\subsubsection*{Returns}
15.445 +
15.446 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
15.447 +0 & The basis factorization has been successfully computed.\\
15.448 +\verb|GLP_EBADB| & The basis matrix is invalid, because the number of
15.449 +basic (auxiliary and structural) variables is not the same as the number
15.450 +of rows in the problem object.\\
15.451 +\verb|GLP_ESING| & The basis matrix is singular within the working
15.452 +precision.\\
15.453 +\verb|GLP_ECOND| & The basis matrix is ill-conditioned, i.e. its
15.454 +condition number is too large.\\
15.455 +\end{tabular}
15.456 +
15.457 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15.458 +
15.459 +\newpage
15.460 +
15.461 +\subsection{glp\_bf\_updated---check if the basis factorization has\\
15.462 +been updated}
15.463 +
15.464 +\subsubsection*{Synopsis}
15.465 +
15.466 +\begin{verbatim}
15.467 +int glp_bf_updated(glp_prob *lp);
15.468 +\end{verbatim}
15.469 +
15.470 +\subsubsection*{Returns}
15.471 +
15.472 +If the basis factorization has been just computed from ``scratch'', the
15.473 +routine \verb|glp_bf_updated| returns zero. Otherwise, if the
15.474 +factorization has been updated at least once, the routine returns
15.475 +non-zero.
15.476 +
15.477 +\subsubsection*{Comments}
15.478 +
15.479 +{\it Updating} the basis factorization means recomputing it to reflect
15.480 +changes in the basis matrix. For example, on every iteration of the
15.481 +simplex method some column of the current basis matrix is replaced by a
15.482 +new column that gives a new basis matrix corresponding to the adjacent
15.483 +basis. In this case computing the basis factorization for the adjacent
15.484 +basis from ``scratch'' (as the routine \verb|glp_factorize| does) would
15.485 +be too time-consuming.
15.486 +
15.487 +On the other hand, since the basis factorization update is a numeric
15.488 +computational procedure, applying it many times may lead to accumulating
15.489 +round-off errors. Therefore the basis is periodically refactorized
15.490 +(reinverted) from ``scratch'' (with the routine \verb|glp_factorize|)
15.491 +that allows improving its numerical properties.
15.492 +
15.493 +The routine \verb|glp_bf_updated| allows determining if the basis
15.494 +factorization has been updated at least once since it was computed from
15.495 +``scratch''.
15.496 +
15.497 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15.498 +
15.499 +\newpage
15.500 +
15.501 +\subsection{glp\_get\_bfcp---retrieve basis factorization control
15.502 +parameters}
15.503 +
15.504 +\subsubsection*{Synopsis}
15.505 +
15.506 +\begin{verbatim}
15.507 +void glp_get_bfcp(glp_prob *lp, glp_bfcp *parm);
15.508 +\end{verbatim}
15.509 +
15.510 +\subsubsection*{Description}
15.511 +
15.512 +The routine \verb|glp_get_bfcp| retrieves control parameters, which are
15.513 +used on computing and updating the basis factorization associated with
15.514 +the specified problem object.
15.515 +
15.516 +Current values of the control parameters are stored in a \verb|glp_bfcp|
15.517 +structure, which the parameter \verb|parm| points to. For a detailed
15.518 +description of the structure \verb|glp_bfcp| see comments to the routine
15.519 +\verb|glp_set_bfcp| in the next subsection.
15.520 +
15.521 +\subsubsection*{Comments}
15.522 +
15.523 +The purpose of the routine \verb|glp_get_bfcp| is two-fold. First, it
15.524 +allows the application program obtaining current values of control
15.525 +parameters used by internal GLPK routines, which compute and update the
15.526 +basis factorization.
15.527 +
15.528 +The second purpose of this routine is to provide proper values for all
15.529 +fields of the structure \verb|glp_bfcp| in the case when the application
15.530 +program needs to change some control parameters.
15.531 +
15.532 +\subsection{glp\_set\_bfcp---change basis factorization control
15.533 +parameters}
15.534 +
15.535 +\subsubsection*{Synopsis}
15.536 +
15.537 +\begin{verbatim}
15.538 +void glp_set_bfcp(glp_prob *lp, const glp_bfcp *parm);
15.539 +\end{verbatim}
15.540 +
15.541 +\subsubsection*{Description}
15.542 +
15.543 +The routine \verb|glp_set_bfcp| changes control parameters, which are
15.544 +used by internal GLPK routines on computing and updating the basis
15.545 +factorization associated with the specified problem object.
15.546 +
15.547 +New values of the control parameters should be passed in a structure
15.548 +\verb|glp_bfcp|, which the parameter \verb|parm| points to. For a
15.549 +detailed description of the structure \verb|glp_bfcp| see paragraph
15.550 +``Control parameters'' below.
15.551 +
15.552 +The parameter \verb|parm| can be specified as \verb|NULL|, in which case
15.553 +all control parameters are reset to their default values.
15.554 +
15.555 +\subsubsection*{Comments}
15.556 +
15.557 +Before changing some control parameters with the routine
15.558 +\verb|glp_set_bfcp| the application program should retrieve current
15.559 +values of all control parameters with the routine \verb|glp_get_bfcp|.
15.560 +This is needed for backward compatibility, because in the future there
15.561 +may appear new members in the structure \verb|glp_bfcp|.
15.562 +
15.563 +Note that new values of control parameters come into effect on a next
15.564 +computation of the basis factorization, not immediately.
15.565 +
15.566 +\subsubsection*{Example}
15.567 +
15.568 +\begin{verbatim}
15.569 +glp_prob *lp;
15.570 +glp_bfcp parm;
15.571 +. . .
15.572 +/* retrieve current values of control parameters */
15.573 +glp_get_bfcp(lp, &parm);
15.574 +/* change the threshold pivoting tolerance */
15.575 +parm.piv_tol = 0.05;
15.576 +/* set new values of control parameters */
15.577 +glp_set_bfcp(lp, &parm);
15.578 +. . .
15.579 +\end{verbatim}
15.580 +
15.581 +\subsubsection*{Control parameters}
15.582 +
15.583 +This paragraph describes all basis factorization control parameters
15.584 +currently used in the package. Symbolic names of control parameters are
15.585 +names of corresponding members in the structure \verb|glp_bfcp|.
15.586 +
15.587 +\def\arraystretch{1}
15.588 +
15.589 +\medskip
15.590 +
15.591 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
15.592 +\multicolumn{2}{@{}l}{{\tt int type} (default: {\tt GLP\_BF\_FT})} \\
15.593 +&Basis factorization type:\\
15.594 +&\verb|GLP_BF_FT|---$LU$ + Forrest--Tomlin update;\\
15.595 +&\verb|GLP_BF_BG|---$LU$ + Schur complement + Bartels--Golub update;\\
15.596 +&\verb|GLP_BF_GR|---$LU$ + Schur complement + Givens rotation update.
15.597 +\\
15.598 +&In case of \verb|GLP_BF_FT| the update is applied to matrix $U$, while
15.599 +in cases of \verb|GLP_BF_BG| and \verb|GLP_BF_GR| the update is applied
15.600 +to the Schur complement.
15.601 +\end{tabular}
15.602 +
15.603 +\medskip
15.604 +
15.605 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
15.606 +\multicolumn{2}{@{}l}{{\tt int lu\_size} (default: {\tt 0})} \\
15.607 +&The initial size of the Sparse Vector Area, in non-zeros, used on
15.608 +computing $LU$-factorization of the basis matrix for the first time.
15.609 +If this parameter is set to 0, the initial SVA size is determined
15.610 +automatically.\\
15.611 +\end{tabular}
15.612 +
15.613 +\medskip
15.614 +
15.615 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
15.616 +\multicolumn{2}{@{}l}{{\tt double piv\_tol} (default: {\tt 0.10})} \\
15.617 +&Threshold pivoting (Markowitz) tolerance, 0 $<$ \verb|piv_tol| $<$ 1,
15.618 +used on computing $LU$-factorization of the basis matrix. Element
15.619 +$u_{ij}$ of the active submatrix of factor $U$ fits to be pivot if it
15.620 +satisfies to the stability criterion
15.621 +$|u_{ij}| >= {\tt piv\_tol}\cdot\max|u_{i*}|$, i.e. if it is not very
15.622 +small in the magnitude among other elements in the same row. Decreasing
15.623 +this parameter may lead to better sparsity at the expense of numerical
15.624 +accuracy, and vice versa.\\
15.625 +\end{tabular}
15.626 +
15.627 +\medskip
15.628 +
15.629 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
15.630 +\multicolumn{2}{@{}l}{{\tt int piv\_lim} (default: {\tt 4})} \\
15.631 +&This parameter is used on computing $LU$-factorization of the basis
15.632 +matrix and specifies how many pivot candidates needs to be considered
15.633 +on choosing a pivot element, \verb|piv_lim| $\geq$ 1. If \verb|piv_lim|
15.634 +candidates have been considered, the pivoting routine prematurely
15.635 +terminates the search with the best candidate found.\\
15.636 +\end{tabular}
15.637 +
15.638 +\medskip
15.639 +
15.640 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
15.641 +\multicolumn{2}{@{}l}{{\tt int suhl} (default: {\tt GLP\_ON})} \\
15.642 +&This parameter is used on computing $LU$-factorization of the basis
15.643 +matrix. Being set to {\tt GLP\_ON} it enables applying the following
15.644 +heuristic proposed by Uwe Suhl: if a column of the active submatrix has
15.645 +no eligible pivot candidates, it is no more considered until it becomes
15.646 +a column singleton. In many cases this allows reducing the time needed
15.647 +for pivot searching. To disable this heuristic the parameter \verb|suhl|
15.648 +should be set to {\tt GLP\_OFF}.\\
15.649 +\end{tabular}
15.650 +
15.651 +\medskip
15.652 +
15.653 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
15.654 +\multicolumn{2}{@{}l}{{\tt double eps\_tol} (default: {\tt 1e-15})} \\
15.655 +&Epsilon tolerance, \verb|eps_tol| $\geq$ 0, used on computing
15.656 +$LU$-factorization of the basis matrix. If an element of the active
15.657 +submatrix of factor $U$ is less than \verb|eps_tol| in the magnitude,
15.658 +it is replaced by exact zero.\\
15.659 +\end{tabular}
15.660 +
15.661 +\medskip
15.662 +
15.663 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
15.664 +\multicolumn{2}{@{}l}{{\tt double max\_gro} (default: {\tt 1e+10})} \\
15.665 +&Maximal growth of elements of factor $U$, \verb|max_gro| $\geq$ 1,
15.666 +allowable on computing $LU$-factorization of the basis matrix. If on
15.667 +some elimination step the ratio $u_{big}/b_{max}$ (where $u_{big}$ is
15.668 +the largest magnitude of elements of factor $U$ appeared in its active
15.669 +submatrix during all the factorization process, $b_{max}$ is the largest
15.670 +magnitude of elements of the basis matrix to be factorized), the basis
15.671 +matrix is considered as ill-conditioned.\\
15.672 +\end{tabular}
15.673 +
15.674 +\medskip
15.675 +
15.676 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
15.677 +\multicolumn{2}{@{}l}{{\tt int nfs\_max} (default: {\tt 100})} \\
15.678 +&Maximal number of additional row-like factors (entries of the eta
15.679 +file), \verb|nfs_max| $\geq$ 1, which can be added to $LU$-factorization
15.680 +of the basis matrix on updating it with the Forrest--Tomlin technique.
15.681 +This parameter is used only once, before $LU$-factorization is computed
15.682 +for the first time, to allocate working arrays. As a rule, each update
15.683 +adds one new factor (however, some updates may need no addition), so
15.684 +this parameter limits the number of updates between refactorizations.\\
15.685 +\end{tabular}
15.686 +
15.687 +\medskip
15.688 +
15.689 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
15.690 +\multicolumn{2}{@{}l}{{\tt double upd\_tol} (default: {\tt 1e-6})} \\
15.691 +&Update tolerance, 0 $<$ \verb|upd_tol| $<$ 1, used on updating
15.692 +$LU$-factorization of the basis matrix with the Forrest--Tomlin
15.693 +technique. If after updating the magnitude of some diagonal element
15.694 +$u_{kk}$ of factor $U$ becomes less than
15.695 +${\tt upd\_tol}\cdot\max(|u_{k*}|, |u_{*k}|)$, the factorization is
15.696 +considered as inaccurate.\\
15.697 +\end{tabular}
15.698 +
15.699 +\medskip
15.700 +
15.701 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
15.702 +\multicolumn{2}{@{}l}{{\tt int nrs\_max} (default: {\tt 100})} \\
15.703 +&Maximal number of additional rows and columns, \verb|nrs_max| $\geq$ 1,
15.704 +which can be added to $LU$-factorization of the basis matrix on updating
15.705 +it with the Schur complement technique. This parameter is used only
15.706 +once, before $LU$-factorization is computed for the first time, to
15.707 +allocate working arrays. As a rule, each update adds one new row and
15.708 +column (however, some updates may need no addition), so this parameter
15.709 +limits the number of updates between refactorizations.\\
15.710 +\end{tabular}
15.711 +
15.712 +\medskip
15.713 +
15.714 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
15.715 +\multicolumn{2}{@{}l}{{\tt int rs\_size} (default: {\tt 0})} \\
15.716 +&The initial size of the Sparse Vector Area, in non-zeros, used to
15.717 +store non-zero elements of additional rows and columns introduced on
15.718 +updating $LU$-factorization of the basis matrix with the Schur
15.719 +complement technique. If this parameter is set to 0, the initial SVA
15.720 +size is determined automatically.\\
15.721 +\end{tabular}
15.722 +
15.723 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15.724 +
15.725 +\newpage
15.726 +
15.727 +\subsection{glp\_get\_bhead---retrieve the basis header information}
15.728 +
15.729 +\subsubsection*{Synopsis}
15.730 +
15.731 +\begin{verbatim}
15.732 +int glp_get_bhead(glp_prob *lp, int k);
15.733 +\end{verbatim}
15.734 +
15.735 +\subsubsection*{Description}
15.736 +
15.737 +The routine \verb|glp_get_bhead| returns the basis header information
15.738 +for the current basis associated with the specified problem object.
15.739 +
15.740 +\subsubsection*{Returns}
15.741 +
15.742 +If basic variable $(x_B)_k$, $1\leq k\leq m$, is $i$-th auxiliary
15.743 +variable ($1\leq i\leq m$), the routine returns $i$. Otherwise, if
15.744 +$(x_B)_k$ is $j$-th structural variable ($1\leq j\leq n$), the routine
15.745 +returns $m+j$. Here $m$ is the number of rows and $n$ is the number of
15.746 +columns in the problem object.
15.747 +
15.748 +\subsubsection*{Comments}
15.749 +
15.750 +Sometimes the application program may need to know which original
15.751 +(auxiliary and structural) variable correspond to a given basic
15.752 +variable, or, that is the same, which column of the augmented constraint
15.753 +matrix $(I\ |-\!A)$ correspond to a given column of the basis matrix
15.754 +$B$.
15.755 +
15.756 +\def\arraystretch{1}
15.757 +
15.758 +The correspondence is defined as follows:\footnote{For more details see
15.759 +Subsection \ref{basbgd}, page \pageref{basbgd}.}
15.760 +$$\left(\begin{array}{@{}c@{}}x_B\\x_N\\\end{array}\right)=
15.761 +\Pi\left(\begin{array}{@{}c@{}}x_R\\x_S\\\end{array}\right)
15.762 +\ \ \Leftrightarrow
15.763 +\ \ \left(\begin{array}{@{}c@{}}x_R\\x_S\\\end{array}\right)=
15.764 +\Pi^T\left(\begin{array}{@{}c@{}}x_B\\x_N\\\end{array}\right),$$
15.765 +where $x_B$ is the vector of basic variables, $x_N$ is the vector of
15.766 +non-basic variables, $x_R$ is the vector of auxiliary variables
15.767 +following in their original order,\footnote{The original order of
15.768 +auxiliary and structural variables is defined by the ordinal numbers
15.769 +of corresponding rows and columns in the problem object.} $x_S$ is the
15.770 +vector of structural variables following in their original order, $\Pi$
15.771 +is a permutation matrix (which is a component of the basis
15.772 +factorization).
15.773 +
15.774 +Thus, if $(x_B)_k=(x_R)_i$ is $i$-th auxiliary variable, the routine
15.775 +returns $i$, and if $(x_B)_k=(x_S)_j$ is $j$-th structural variable,
15.776 +the routine returns $m+j$, where $m$ is the number of rows in the
15.777 +problem object.
15.778 +
15.779 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15.780 +
15.781 +\newpage
15.782 +
15.783 +\subsection{glp\_get\_row\_bind---retrieve row index in the basis\\
15.784 +header}
15.785 +
15.786 +\subsubsection*{Synopsis}
15.787 +
15.788 +\begin{verbatim}
15.789 +int glp_get_row_bind(glp_prob *lp, int i);
15.790 +\end{verbatim}
15.791 +
15.792 +\subsubsection*{Returns}
15.793 +
15.794 +The routine \verb|glp_get_row_bind| returns the index $k$ of basic
15.795 +variable $(x_B)_k$, $1\leq k\leq m$, which is $i$-th auxiliary variable
15.796 +(that is, the auxiliary variable corresponding to $i$-th row),
15.797 +$1\leq i\leq m$, in the current basis associated with the specified
15.798 +problem object, where $m$ is the number of rows. However, if $i$-th
15.799 +auxiliary variable is non-basic, the routine returns zero.
15.800 +
15.801 +\subsubsection*{Comments}
15.802 +
15.803 +The routine \verb|glp_get_row_bind| is an inverse to the routine
15.804 +\verb|glp_get_bhead|: if \verb|glp_get_bhead|$(lp,k)$ returns $i$,
15.805 +\verb|glp_get_row_bind|$(lp,i)$ returns $k$, and vice versa.
15.806 +
15.807 +\subsection{glp\_get\_col\_bind---retrieve column index in the basis
15.808 +header}
15.809 +
15.810 +\subsubsection*{Synopsis}
15.811 +
15.812 +\begin{verbatim}
15.813 +int glp_get_col_bind(glp_prob *lp, int j);
15.814 +\end{verbatim}
15.815 +
15.816 +\subsubsection*{Returns}
15.817 +
15.818 +The routine \verb|glp_get_col_bind| returns the index $k$ of basic
15.819 +variable $(x_B)_k$, $1\leq k\leq m$, which is $j$-th structural
15.820 +variable (that is, the structural variable corresponding to $j$-th
15.821 +column), $1\leq j\leq n$, in the current basis associated with the
15.822 +specified problem object, where $m$ is the number of rows, $n$ is the
15.823 +number of columns. However, if $j$-th structural variable is non-basic,
15.824 +the routine returns zero.
15.825 +
15.826 +\subsubsection*{Comments}
15.827 +
15.828 +The routine \verb|glp_get_col_bind| is an inverse to the routine
15.829 +\verb|glp_get_bhead|: if \verb|glp_get_bhead|$(lp,k)$ returns $m+j$,
15.830 +\verb|glp_get_col_bind|$(lp,j)$ returns $k$, and vice versa.
15.831 +
15.832 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15.833 +
15.834 +\newpage
15.835 +
15.836 +\subsection{glp\_ftran---perform forward transformation}
15.837 +
15.838 +\subsubsection*{Synopsis}
15.839 +
15.840 +\begin{verbatim}
15.841 +void glp_ftran(glp_prob *lp, double x[]);
15.842 +\end{verbatim}
15.843 +
15.844 +\subsubsection*{Description}
15.845 +
15.846 +The routine \verb|glp_ftran| performs forward transformation (FTRAN),
15.847 +i.e. it solves the system $Bx=b$, where $B$ is the basis matrix
15.848 +associated with the specified problem object, $x$ is the vector of
15.849 +unknowns to be computed, $b$ is the vector of right-hand sides.
15.850 +
15.851 +On entry to the routine elements of the vector $b$ should be stored in
15.852 +locations \verb|x[1]|, \dots, \verb|x[m]|, where $m$ is the number of
15.853 +rows. On exit the routine stores elements of the vector $x$ in the same
15.854 +locations.
15.855 +
15.856 +\subsection{glp\_btran---perform backward transformation}
15.857 +
15.858 +\subsubsection*{Synopsis}
15.859 +
15.860 +\begin{verbatim}
15.861 +void glp_btran(glp_prob *lp, double x[]);
15.862 +\end{verbatim}
15.863 +
15.864 +\subsubsection*{Description}
15.865 +
15.866 +The routine \verb|glp_btran| performs backward transformation (BTRAN),
15.867 +i.e. it solves the system $B^Tx=b$, where $B^T$ is a matrix transposed
15.868 +to the basis matrix $B$ associated with the specified problem object,
15.869 +$x$ is the vector of unknowns to be computed, $b$ is the vector of
15.870 +right-hand sides.
15.871 +
15.872 +On entry to the routine elements of the vector $b$ should be stored in
15.873 +locations \verb|x[1]|, \dots, \verb|x[m]|, where $m$ is the number of
15.874 +rows. On exit the routine stores elements of the vector $x$ in the same
15.875 +locations.
15.876 +
15.877 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15.878 +
15.879 +\newpage
15.880 +
15.881 +\subsection{glp\_warm\_up---``warm up'' LP basis}
15.882 +
15.883 +\subsubsection*{Synopsis}
15.884 +
15.885 +\begin{verbatim}
15.886 +int glp_warm_up(glp_prob *P);
15.887 +\end{verbatim}
15.888 +
15.889 +\subsubsection*{Description}
15.890 +
15.891 +The routine \verb|glp_warm_up| ``warms up'' the LP basis for the
15.892 +specified problem object using current statuses assigned to rows and
15.893 +columns (that is, to auxiliary and structural variables).
15.894 +
15.895 +This operation includes computing factorization of the basis matrix
15.896 +(if it does not exist), computing primal and dual components of basic
15.897 +solution, and determining the solution status.
15.898 +
15.899 +\subsubsection*{Returns}
15.900 +
15.901 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
15.902 +0 & The operation has been successfully performed.\\
15.903 +\verb|GLP_EBADB| & The basis matrix is invalid, because the number of
15.904 +basic (auxiliary and structural) variables is not the same as the number
15.905 +of rows in the problem object.\\
15.906 +\verb|GLP_ESING| & The basis matrix is singular within the working
15.907 +precision.\\
15.908 +\verb|GLP_ECOND| & The basis matrix is ill-conditioned, i.e. its
15.909 +condition number is too large.\\
15.910 +\end{tabular}
15.911 +
15.912 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15.913 +
15.914 +\newpage
15.915 +
15.916 +\section{Simplex tableau routines}
15.917 +
15.918 +\subsection{glp\_eval\_tab\_row---compute row of the tableau}
15.919 +
15.920 +\subsubsection*{Synopsis}
15.921 +
15.922 +\begin{verbatim}
15.923 +int glp_eval_tab_row(glp_prob *lp, int k, int ind[],
15.924 + double val[]);
15.925 +\end{verbatim}
15.926 +
15.927 +\subsubsection*{Description}
15.928 +
15.929 +The routine \verb|glp_eval_tab_row| computes a row of the current
15.930 +simplex tableau (see Subsection 3.1.1, formula (3.12)), which (row)
15.931 +corresponds to some basic variable specified by the parameter $k$ as
15.932 +follows: if $1\leq k\leq m$, the basic variable is $k$-th auxiliary
15.933 +variable, and if $m+1\leq k\leq m+n$, the basic variable is $(k-m)$-th
15.934 +structural variable, where $m$ is the number of rows and $n$ is the
15.935 +number of columns in the specified problem object. The basis
15.936 +factorization must exist.
15.937 +
15.938 +The computed row shows how the specified basic variable depends on
15.939 +non-basic variables:
15.940 +$$x_k=(x_B)_i=\xi_{i1}(x_N)_1+\xi_{i2}(x_N)_2+\dots+\xi_{in}(x_N)_n,$$
15.941 +where $\xi_{i1}$, $\xi_{i2}$, \dots, $\xi_{in}$ are elements of the
15.942 +simplex table row, $(x_N)_1$, $(x_N)_2$, \dots, $(x_N)_n$ are non-basic
15.943 +(auxiliary and structural) variables.
15.944 +
15.945 +The routine stores column indices and corresponding numeric values of
15.946 +non-zero elements of the computed row in unordered sparse format in
15.947 +locations \verb|ind[1]|, \dots, \verb|ind[len]| and \verb|val[1]|,
15.948 +\dots, \verb|val[len]|, respectively, where $0\leq{\tt len}\leq n$ is
15.949 +the number of non-zero elements in the row returned on exit.
15.950 +
15.951 +Element indices stored in the array \verb|ind| have the same sense as
15.952 +index $k$, i.e. indices 1 to $m$ denote auxiliary variables while
15.953 +indices $m+1$ to $m+n$ denote structural variables (all these variables
15.954 +are obviously non-basic by definition).
15.955 +
15.956 +\subsubsection*{Returns}
15.957 +
15.958 +The routine \verb|glp_eval_tab_row| returns \verb|len|, which is the
15.959 +number of non-zero elements in the simplex table row stored in the
15.960 +arrays \verb|ind| and \verb|val|.
15.961 +
15.962 +\subsubsection*{Comments}
15.963 +
15.964 +A row of the simplex table is computed as follows. At first, the
15.965 +routine checks that the specified variable $x_k$ is basic and uses the
15.966 +permutation matrix $\Pi$ (3.7) to determine index $i$ of basic variable
15.967 +$(x_B)_i$, which corresponds to $x_k$.
15.968 +
15.969 +The row to be computed is $i$-th row of the matrix $\Xi$ (3.12),
15.970 +therefore:
15.971 +$$\xi_i=e_i^T\Xi=-e_i^TB^{-1}N=-(B^{-T}e_i)^TN,$$
15.972 +where $e_i$ is $i$-th unity vector. So the routine performs BTRAN to
15.973 +obtain $i$-th row of the inverse $B^{-1}$:
15.974 +$$\varrho_i=B^{-T}e_i,$$
15.975 +and then computes elements of the simplex table row as inner products:
15.976 +$$\xi_{ij}=-\varrho_i^TN_j,\ \ j=1,2,\dots,n,$$
15.977 +where $N_j$ is $j$-th column of matrix $N$ (3.9), which (column)
15.978 +corresponds to non-basic variable $(x_N)_j$. The permutation matrix
15.979 +$\Pi$ is used again to convert indices $j$ of non-basic columns to
15.980 +original ordinal numbers of auxiliary and structural variables.
15.981 +
15.982 +\subsection{glp\_eval\_tab\_col---compute column of the tableau}
15.983 +
15.984 +\subsubsection*{Synopsis}
15.985 +
15.986 +\begin{verbatim}
15.987 +int glp_eval_tab_col(glp_prob *lp, int k, int ind[],
15.988 + double val[]);
15.989 +\end{verbatim}
15.990 +
15.991 +\subsubsection*{Description}
15.992 +
15.993 +The routine \verb|glp_eval_tab_col| computes a column of the current
15.994 +simplex tableau (see Subsection 3.1.1, formula (3.12)), which (column)
15.995 +corresponds to some non-basic variable specified by the parameter $k$:
15.996 +if $1\leq k\leq m$, the non-basic variable is $k$-th auxiliary variable,
15.997 +and if $m+1\leq k\leq m+n$, the non-basic variable is $(k-m)$-th
15.998 +structural variable, where $m$ is the number of rows and $n$ is the
15.999 +number of columns in the specified problem object. The basis
15.1000 +factorization must exist.
15.1001 +
15.1002 +The computed column shows how basic variables depends on the specified
15.1003 +non-basic variable $x_k=(x_N)_j$:
15.1004 +$$
15.1005 +\begin{array}{r@{\ }c@{\ }l@{\ }l}
15.1006 +(x_B)_1&=&\dots+\xi_{1j}(x_N)_j&+\dots\\
15.1007 +(x_B)_2&=&\dots+\xi_{2j}(x_N)_j&+\dots\\
15.1008 +.\ \ .&.&.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\\
15.1009 +(x_B)_m&=&\dots+\xi_{mj}(x_N)_j&+\dots\\
15.1010 +\end{array}
15.1011 +$$
15.1012 +where $\xi_{1j}$, $\xi_{2j}$, \dots, $\xi_{mj}$ are elements of the
15.1013 +simplex table column, $(x_B)_1$, $(x_B)_2$, \dots, $(x_B)_m$ are basic
15.1014 +(auxiliary and structural) variables.
15.1015 +
15.1016 +The routine stores row indices and corresponding numeric values of
15.1017 +non-zero elements of the computed column in unordered sparse format in
15.1018 +locations \verb|ind[1]|, \dots, \verb|ind[len]| and \verb|val[1]|,
15.1019 +\dots, \verb|val[len]|, respectively, where $0\leq{\tt len}\leq m$ is
15.1020 +the number of non-zero elements in the column returned on exit.
15.1021 +
15.1022 +Element indices stored in the array \verb|ind| have the same sense as
15.1023 +index $k$, i.e. indices 1 to $m$ denote auxiliary variables while
15.1024 +indices $m+1$ to $m+n$ denote structural variables (all these variables
15.1025 +are obviously basic by definition).
15.1026 +
15.1027 +\subsubsection*{Returns}
15.1028 +
15.1029 +The routine \verb|glp_eval_tab_col| returns \verb|len|, which is the
15.1030 +number of non-zero elements in the simplex table column stored in the
15.1031 +arrays \verb|ind| and \verb|val|.
15.1032 +
15.1033 +\subsubsection*{Comments}
15.1034 +
15.1035 +A column of the simplex table is computed as follows. At first, the
15.1036 +routine checks that the specified variable $x_k$ is non-basic and uses
15.1037 +the permutation matrix $\Pi$ (3.7) to determine index $j$ of non-basic
15.1038 +variable $(x_N)_j$, which corresponds to $x_k$.
15.1039 +
15.1040 +The column to be computed is $j$-th column of the matrix $\Xi$ (3.12),
15.1041 +therefore:
15.1042 +$$\Xi_j=\Xi e_j=-B^{-1}Ne_j=-B^{-1}N_j,$$
15.1043 +where $e_j$ is $j$-th unity vector, $N_j$ is $j$-th column of matrix
15.1044 +$N$ (3.9). So the routine performs FTRAN to transform $N_j$ to the
15.1045 +simplex table column $\Xi_j=(\xi_{ij})$ and uses the permutation matrix
15.1046 +$\Pi$ to convert row indices $i$ to original ordinal numbers of
15.1047 +auxiliary and structural variables.
15.1048 +
15.1049 +\newpage
15.1050 +
15.1051 +\subsection{glp\_transform\_row---transform explicitly specified\\
15.1052 +row}
15.1053 +
15.1054 +\subsubsection*{Synopsis}
15.1055 +
15.1056 +\begin{verbatim}
15.1057 +int glp_transform_row(glp_prob *P, int len, int ind[],
15.1058 + double val[]);
15.1059 +\end{verbatim}
15.1060 +
15.1061 +\subsubsection*{Description}
15.1062 +
15.1063 +The routine \verb|glp_transform_row| performs the same operation as the
15.1064 +routine \verb|glp_eval_tab_row| with exception that the row to be
15.1065 +transformed is specified explicitly as a sparse vector.
15.1066 +
15.1067 +The explicitly specified row may be thought as a linear form:
15.1068 +$$x=a_1x_{m+1}+a_2x_{m+2}+\dots+a_nx_{m+n},$$
15.1069 +where $x$ is an auxiliary variable for this row, $a_j$ are coefficients
15.1070 +of the linear form, $x_{m+j}$ are structural variables.
15.1071 +
15.1072 +On entry column indices and numerical values of non-zero coefficients
15.1073 +$a_j$ of the specified row should be placed in locations \verb|ind[1]|,
15.1074 +\dots, \verb|ind[len]| and \verb|val[1]|, \dots, \verb|val[len]|, where
15.1075 +\verb|len| is number of non-zero coefficients.
15.1076 +
15.1077 +This routine uses the system of equality constraints and the current
15.1078 +basis in order to express the auxiliary variable $x$ through the current
15.1079 +non-basic variables (as if the transformed row were added to the problem
15.1080 +object and the auxiliary variable $x$ were basic), i.e. the resultant
15.1081 +row has the form:
15.1082 +$$x=\xi_1(x_N)_1+\xi_2(x_N)_2+\dots+\xi_n(x_N)_n,$$
15.1083 +where $\xi_j$ are influence coefficients, $(x_N)_j$ are non-basic
15.1084 +(auxiliary and structural) variables, $n$ is the number of columns in
15.1085 +the problem object.
15.1086 +
15.1087 +On exit the routine stores indices and numerical values of non-zero
15.1088 +coefficients $\xi_j$ of the resultant row in locations \verb|ind[1]|,
15.1089 +\dots, \verb|ind[len']| and \verb|val[1]|, \dots, \verb|val[len']|,
15.1090 +where $0\leq{\tt len'}\leq n$ is the number of non-zero coefficients in
15.1091 +the resultant row returned by the routine. Note that indices of
15.1092 +non-basic variables stored in the array \verb|ind| correspond to
15.1093 +original ordinal numbers of variables: indices 1 to $m$ mean auxiliary
15.1094 +variables and indices $m+1$ to $m+n$ mean structural ones.
15.1095 +
15.1096 +\subsubsection*{Returns}
15.1097 +
15.1098 +The routine \verb|glp_transform_row| returns \verb|len'|, the number of
15.1099 +non-zero coefficients in the resultant row stored in the arrays
15.1100 +\verb|ind| and \verb|val|.
15.1101 +
15.1102 +\subsection{glp\_transform\_col---transform explicitly specified\\
15.1103 +column}
15.1104 +
15.1105 +\subsubsection*{Synopsis}
15.1106 +
15.1107 +\begin{verbatim}
15.1108 +int glp_transform_col(glp_prob *P, int len, int ind[],
15.1109 + double val[]);
15.1110 +\end{verbatim}
15.1111 +
15.1112 +\subsubsection*{Description}
15.1113 +
15.1114 +The routine \verb|glp_transform_col| performs the same operation as the
15.1115 +routine \verb|glp_eval_tab_col| with exception that the column to be
15.1116 +transformed is specified explicitly as a sparse vector.
15.1117 +
15.1118 +The explicitly specified column may be thought as it were added to
15.1119 +the original system of equality constraints:
15.1120 +$$
15.1121 +\begin{array}{l@{\ }c@{\ }r@{\ }c@{\ }r@{\ }c@{\ }r}
15.1122 +x_1&=&a_{11}x_{m+1}&+\dots+&a_{1n}x_{m+n}&+&a_1x \\
15.1123 +x_2&=&a_{21}x_{m+1}&+\dots+&a_{2n}x_{m+n}&+&a_2x \\
15.1124 +\multicolumn{7}{c}
15.1125 +{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}\\
15.1126 +x_m&=&a_{m1}x_{m+1}&+\dots+&a_{mn}x_{m+n}&+&a_mx \\
15.1127 +\end{array}
15.1128 +$$
15.1129 +where $x_i$ are auxiliary variables, $x_{m+j}$ are structural variables
15.1130 +(presented in the problem object), $x$ is a structural variable for the
15.1131 +explicitly specified column, $a_i$ are constraint coefficients at $x$.
15.1132 +
15.1133 +On entry row indices and numerical values of non-zero coefficients
15.1134 +$a_i$ of the specified column should be placed in locations
15.1135 +\verb|ind[1]|, \dots, \verb|ind[len]| and \verb|val[1]|, \dots,
15.1136 +\verb|val[len]|, where \verb|len| is number of non-zero coefficients.
15.1137 +
15.1138 +This routine uses the system of equality constraints and the current
15.1139 +basis in order to express the current basic variables through the
15.1140 +structural variable $x$ (as if the transformed column were added to the
15.1141 +problem object and the variable $x$ were non-basic):
15.1142 +$$
15.1143 +\begin{array}{l@{\ }c@{\ }r}
15.1144 +(x_B)_1&=\dots+&\xi_{1}x\\
15.1145 +(x_B)_2&=\dots+&\xi_{2}x\\
15.1146 +\multicolumn{3}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .}\\
15.1147 +(x_B)_m&=\dots+&\xi_{m}x\\
15.1148 +\end{array}
15.1149 +$$
15.1150 +where $\xi_i$ are influence coefficients, $x_B$ are basic (auxiliary
15.1151 +and structural) variables, $m$ is the number of rows in the problem
15.1152 +object.
15.1153 +
15.1154 +On exit the routine stores indices and numerical values of non-zero
15.1155 +coefficients $\xi_i$ of the resultant column in locations \verb|ind[1]|,
15.1156 +\dots, \verb|ind[len']| and \verb|val[1]|, \dots, \verb|val[len']|,
15.1157 +where $0\leq{\tt len'}\leq m$ is the number of non-zero coefficients in
15.1158 +the resultant column returned by the routine. Note that indices of basic
15.1159 +variables stored in the array \verb|ind| correspond to original ordinal
15.1160 +numbers of variables, i.e. indices 1 to $m$ mean auxiliary variables,
15.1161 +indices $m+1$ to $m+n$ mean structural ones.
15.1162 +
15.1163 +\subsubsection*{Returns}
15.1164 +
15.1165 +The routine \verb|glp_transform_col| returns \verb|len'|, the number of
15.1166 +non-zero coefficients in the resultant column stored in the arrays
15.1167 +\verb|ind| and \verb|val|.
15.1168 +
15.1169 +\subsection{glp\_prim\_rtest---perform primal ratio test}
15.1170 +
15.1171 +\subsubsection*{Synopsis}
15.1172 +
15.1173 +\begin{verbatim}
15.1174 +int glp_prim_rtest(glp_prob *P, int len, const int ind[],
15.1175 + const double val[], int dir, double eps);
15.1176 +\end{verbatim}
15.1177 +
15.1178 +\subsubsection*{Description}
15.1179 +
15.1180 +The routine \verb|glp_prim_rtest| performs the primal ratio test using
15.1181 +an explicitly specified column of the simplex table.
15.1182 +
15.1183 +The current basic solution associated with the LP problem object must be
15.1184 +primal feasible.
15.1185 +
15.1186 +The explicitly specified column of the simplex table shows how the basic
15.1187 +variables $x_B$ depend on some non-basic variable $x$ (which is not
15.1188 +necessarily presented in the problem object):
15.1189 +$$
15.1190 +\begin{array}{l@{\ }c@{\ }r}
15.1191 +(x_B)_1&=\dots+&\xi_{1}x\\
15.1192 +(x_B)_2&=\dots+&\xi_{2}x\\
15.1193 +\multicolumn{3}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .}\\
15.1194 +(x_B)_m&=\dots+&\xi_{m}x\\
15.1195 +\end{array}
15.1196 +$$
15.1197 +
15.1198 +The column is specifed on entry to the routine in sparse format. Ordinal
15.1199 +numbers of basic variables $(x_B)_i$ should be placed in locations
15.1200 +\verb|ind[1]|, \dots, \verb|ind[len]|, where ordinal number 1 to $m$
15.1201 +denote auxiliary variables, and ordinal numbers $m+1$ to $m+n$ denote
15.1202 +structural variables. The corresponding non-zero coefficients $\xi_i$
15.1203 +should be placed in locations \verb|val[1]|, \dots, \verb|val[len]|. The
15.1204 +arrays \verb|ind| and \verb|val| are not changed by the routine.
15.1205 +
15.1206 +The parameter \verb|dir| specifies direction in which the variable $x$
15.1207 +changes on entering the basis: $+1$ means increasing, $-1$ means
15.1208 +decreasing.
15.1209 +
15.1210 +The parameter \verb|eps| is an absolute tolerance (small positive
15.1211 +number, say, $10^{-9}$) used by the routine to skip $\xi_i$'s whose
15.1212 +magnitude is less than \verb|eps|.
15.1213 +
15.1214 +The routine determines which basic variable (among those specified in
15.1215 +\verb|ind[1]|, \dots, \verb|ind[len]|) reaches its (lower or upper)
15.1216 +bound first before any other basic variables do, and which, therefore,
15.1217 +should leave the basis in order to keep primal feasibility.
15.1218 +
15.1219 +\subsubsection*{Returns}
15.1220 +
15.1221 +The routine \verb|glp_prim_rtest| returns the index, \verb|piv|, in the
15.1222 +arrays \verb|ind| and \verb|val| corresponding to the pivot element
15.1223 +chosen, $1\leq$ \verb|piv| $\leq$ \verb|len|. If the adjacent basic
15.1224 +solution is primal unbounded, and therefore the choice cannot be made,
15.1225 +the routine returns zero.
15.1226 +
15.1227 +\subsubsection*{Comments}
15.1228 +
15.1229 +If the non-basic variable $x$ is presented in the LP problem object, the
15.1230 +input column can be computed with the routine \verb|glp_eval_tab_col|;
15.1231 +otherwise, it can be computed with the routine \verb|glp_transform_col|.
15.1232 +
15.1233 +\subsection{glp\_dual\_rtest---perform dual ratio test}
15.1234 +
15.1235 +\subsubsection*{Synopsis}
15.1236 +
15.1237 +\begin{verbatim}
15.1238 +int glp_dual_rtest(glp_prob *P, int len, const int ind[],
15.1239 + const double val[], int dir, double eps);
15.1240 +\end{verbatim}
15.1241 +
15.1242 +\subsubsection*{Description}
15.1243 +
15.1244 +The routine \verb|glp_dual_rtest| performs the dual ratio test using
15.1245 +an explicitly specified row of the simplex table.
15.1246 +
15.1247 +The current basic solution associated with the LP problem object must be
15.1248 +dual feasible.
15.1249 +
15.1250 +The explicitly specified row of the simplex table is a linear form
15.1251 +that shows how some basic variable $x$ (which is not necessarily
15.1252 +presented in the problem object) depends on non-basic variables $x_N$:
15.1253 +$$x=\xi_1(x_N)_1+\xi_2(x_N)_2+\dots+\xi_n(x_N)_n.$$
15.1254 +
15.1255 +The row is specified on entry to the routine in sparse format. Ordinal
15.1256 +numbers of non-basic variables $(x_N)_j$ should be placed in locations
15.1257 +\verb|ind[1]|, \dots, \verb|ind[len]|, where ordinal numbers 1 to $m$
15.1258 +denote auxiliary variables, and ordinal numbers $m+1$ to $m+n$ denote
15.1259 +structural variables. The corresponding non-zero coefficients $\xi_j$
15.1260 +should be placed in locations \verb|val[1]|, \dots, \verb|val[len]|.
15.1261 +The arrays \verb|ind| and \verb|val| are not changed by the routine.
15.1262 +
15.1263 +The parameter \verb|dir| specifies direction in which the variable $x$
15.1264 +changes on leaving the basis: $+1$ means that $x$ goes on its lower
15.1265 +bound, so its reduced cost (dual variable) is increasing (minimization)
15.1266 +or decreasing (maximization); $-1$ means that $x$ goes on its upper
15.1267 +bound, so its reduced cost is decreasing (minimization) or increasing
15.1268 +(maximization).
15.1269 +
15.1270 +The parameter \verb|eps| is an absolute tolerance (small positive
15.1271 +number, say, $10^{-9}$) used by the routine to skip $\xi_j$'s whose
15.1272 +magnitude is less than \verb|eps|.
15.1273 +
15.1274 +The routine determines which non-basic variable (among those specified
15.1275 +in \verb|ind[1]|, \dots, \verb|ind[len]|) should enter the basis in
15.1276 +order to keep dual feasibility, because its reduced cost reaches the
15.1277 +(zero) bound first before this occurs for any other non-basic variables.
15.1278 +
15.1279 +\subsubsection*{Returns}
15.1280 +
15.1281 +The routine \verb|glp_dual_rtest| returns the index, \verb|piv|, in the
15.1282 +arrays \verb|ind| and \verb|val| corresponding to the pivot element
15.1283 +chosen, $1\leq$ \verb|piv| $\leq$ \verb|len|. If the adjacent basic
15.1284 +solution is dual unbounded, and therefore the choice cannot be made,
15.1285 +the routine returns zero.
15.1286 +
15.1287 +\subsubsection*{Comments}
15.1288 +
15.1289 +If the basic variable $x$ is presented in the LP problem object, the
15.1290 +input row can be computed with the routine \verb|glp_eval_tab_row|;
15.1291 +otherwise, it can be computed with the routine \verb|glp_transform_row|.
15.1292 +
15.1293 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15.1294 +
15.1295 +\newpage
15.1296 +
15.1297 +\section{Post-optimal analysis routines}
15.1298 +
15.1299 +\subsection{glp\_analyze\_bound---analyze active bound of non-basic
15.1300 +variable}
15.1301 +
15.1302 +\subsubsection*{Synopsis}
15.1303 +
15.1304 +\begin{verbatim}
15.1305 +void glp_analyze_bound(glp_prob *P, int k, double *limit1,
15.1306 + int *var1, double *limit2, int *var2);
15.1307 +\end{verbatim}
15.1308 +
15.1309 +\subsubsection*{Description}
15.1310 +
15.1311 +The routine \verb|glp_analyze_bound| analyzes the effect of varying the
15.1312 +active bound of specified non-basic variable.
15.1313 +
15.1314 +The non-basic variable is specified by the parameter $k$, where
15.1315 +$1\leq k\leq m$ means auxiliary variable of corresponding row, and
15.1316 +$m+1\leq k\leq m+n$ means structural variable (column).
15.1317 +
15.1318 +Note that the current basic solution must be optimal, and the basis
15.1319 +factorization must exist.
15.1320 +
15.1321 +Results of the analysis have the following meaning.
15.1322 +
15.1323 +\verb|value1| is the minimal value of the active bound, at which the
15.1324 +basis still remains primal feasible and thus optimal. \verb|-DBL_MAX|
15.1325 +means that the active bound has no lower limit.
15.1326 +
15.1327 +\verb|var1| is the ordinal number of an auxiliary (1 to $m$) or
15.1328 +structural ($m+1$ to $m+n$) basic variable, which reaches its bound
15.1329 +first and thereby limits further decreasing the active bound being
15.1330 +analyzed. if \verb|value1| = \verb|-DBL_MAX|, \verb|var1| is set to 0.
15.1331 +
15.1332 +\verb|value2| is the maximal value of the active bound, at which the
15.1333 +basis still remains primal feasible and thus optimal. \verb|+DBL_MAX|
15.1334 +means that the active bound has no upper limit.
15.1335 +
15.1336 +\verb|var2| is the ordinal number of an auxiliary (1 to $m$) or
15.1337 +structural ($m+1$ to $m+n$) basic variable, which reaches its bound
15.1338 +first and thereby limits further increasing the active bound being
15.1339 +analyzed. if \verb|value2| = \verb|+DBL_MAX|, \verb|var2| is set to 0.
15.1340 +
15.1341 +The parameters \verb|value1|, \verb|var1|, \verb|value2|, \verb|var2|
15.1342 +can be specified as \verb|NULL|, in which case corresponding information
15.1343 +is not stored.
15.1344 +
15.1345 +\newpage
15.1346 +
15.1347 +\subsection{glp\_analyze\_coef---analyze objective coefficient at basic
15.1348 +variable}
15.1349 +
15.1350 +\subsubsection*{Synopsis}
15.1351 +
15.1352 +\begin{verbatim}
15.1353 +void glp_analyze_coef(glp_prob *P, int k, double *coef1,
15.1354 + int *var1, double *value1, double *coef2, int *var2,
15.1355 + double *value2);
15.1356 +\end{verbatim}
15.1357 +
15.1358 +\subsubsection*{Description}
15.1359 +
15.1360 +The routine \verb|glp_analyze_coef| analyzes the effect of varying the
15.1361 +objective coefficient at specified basic variable.
15.1362 +
15.1363 +The basic variable is specified by the parameter $k$, where
15.1364 +$1\leq k\leq m$ means auxiliary variable of corresponding row, and
15.1365 +$m+1\leq k\leq m+n$ means structural variable (column).
15.1366 +
15.1367 +Note that the current basic solution must be optimal, and the basis
15.1368 +factorization must exist.
15.1369 +
15.1370 +Results of the analysis have the following meaning.
15.1371 +
15.1372 +\verb|coef1| is the minimal value of the objective coefficient, at
15.1373 +which the basis still remains dual feasible and thus optimal.
15.1374 +\verb|-DBL_MAX| means that the objective coefficient has no lower limit.
15.1375 +
15.1376 +\verb|var1| is the ordinal number of an auxiliary (1 to $m$) or
15.1377 +structural ($m+1$ to $m+n$) non-basic variable, whose reduced cost
15.1378 +reaches its zero bound first and thereby limits further decreasing the
15.1379 +objective coefficient being analyzed. If \verb|coef1| = \verb|-DBL_MAX|,
15.1380 +\verb|var1| is set to 0.
15.1381 +
15.1382 +\verb|value1| is value of the basic variable being analyzed in an
15.1383 +adjacent basis, which is defined as follows. Let the objective
15.1384 +coefficient reaches its minimal value (\verb|coef1|) and continues
15.1385 +decreasing. Then the reduced cost of the limiting non-basic variable
15.1386 +(\verb|var1|) becomes dual infeasible and the current basis becomes
15.1387 +non-optimal that forces the limiting non-basic variable to enter the
15.1388 +basis replacing there some basic variable that leaves the basis to keep
15.1389 +primal feasibility. Should note that on determining the adjacent basis
15.1390 +current bounds of the basic variable being analyzed are ignored as if
15.1391 +it were free (unbounded) variable, so it cannot leave the basis. It may
15.1392 +happen that no dual feasible adjacent basis exists, in which case
15.1393 +\verb|value1| is set to \verb|-DBL_MAX| or \verb|+DBL_MAX|.
15.1394 +
15.1395 +\verb|coef2| is the maximal value of the objective coefficient, at
15.1396 +which the basis still remains dual feasible and thus optimal.
15.1397 +\verb|+DBL_MAX| means that the objective coefficient has no upper limit.
15.1398 +
15.1399 +\verb|var2| is the ordinal number of an auxiliary (1 to $m$) or
15.1400 +structural ($m+1$ to $m+n$) non-basic variable, whose reduced cost
15.1401 +reaches its zero bound first and thereby limits further increasing the
15.1402 +objective coefficient being analyzed. If \verb|coef2| = \verb|+DBL_MAX|,
15.1403 +\verb|var2| is set to 0.
15.1404 +
15.1405 +\verb|value2| is value of the basic variable being analyzed in an
15.1406 +adjacent basis, which is defined exactly in the same way as
15.1407 +\verb|value1| above with exception that now the objective coefficient
15.1408 +is increasing.
15.1409 +
15.1410 +The parameters \verb|coef1|, \verb|var1|, \verb|value1|, \verb|coef2|,
15.1411 +\verb|var2|, \verb|value2| can be specified as \verb|NULL|, in which
15.1412 +case corresponding information is not stored.
15.1413 +
15.1414 +%* eof *%
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
16.2 +++ b/doc/glpk05.tex Mon Dec 06 13:09:21 2010 +0100
16.3 @@ -0,0 +1,1100 @@
16.4 +%* glpk05.tex *%
16.5 +
16.6 +\chapter{Branch-and-Cut API Routines}
16.7 +
16.8 +\section{Introduction}
16.9 +
16.10 +\subsection{Using the callback routine}
16.11 +
16.12 +The GLPK MIP solver based on the branch-and-cut method allows the
16.13 +application program to control the solution process. This is attained
16.14 +by means of the user-defined callback routine, which is called by the
16.15 +solver at various points of the branch-and-cut algorithm.
16.16 +
16.17 +The callback routine passed to the MIP solver should be written by the
16.18 +user and has the following specification:\footnote{The name
16.19 +{\tt foo\_bar} used here is a placeholder for the callback routine
16.20 +name.}
16.21 +
16.22 +\begin{verbatim}
16.23 + void foo_bar(glp_tree *tree, void *info);
16.24 +\end{verbatim}
16.25 +
16.26 +\noindent
16.27 +where \verb|tree| is a pointer to the data structure \verb|glp_tree|,
16.28 +which should be used on subsequent calls to branch-and-cut interface
16.29 +routines, and \verb|info| is a transit pointer passed to the routine
16.30 +\verb|glp_intopt|, which may be used by the application program to pass
16.31 +some external data to the callback routine.
16.32 +
16.33 +The callback routine is passed to the MIP solver through the control
16.34 +parameter structure \verb|glp_iocp| (see Chapter ``Basic API Routines'',
16.35 +Section ``Mixed integer programming routines'', Subsection ``Solve MIP
16.36 +problem with the branch-and-cut method'') as follows:
16.37 +
16.38 +\newpage
16.39 +
16.40 +\begin{verbatim}
16.41 + glp_prob *mip;
16.42 + glp_iocp parm;
16.43 + . . .
16.44 + glp_init_iocp(&parm);
16.45 + . . .
16.46 + parm.cb_func = foo_bar;
16.47 + parm.cb_info = ... ;
16.48 + ret = glp_intopt(mip, &parm);
16.49 + . . .
16.50 +\end{verbatim}
16.51 +
16.52 +To determine why it is being called by the MIP solver the callback
16.53 +routine should use the routine \verb|glp_ios_reason| (described in this
16.54 +section below), which returns a code indicating the reason for calling.
16.55 +Depending on the reason the callback routine may perform necessary
16.56 +actions to control the solution process.
16.57 +
16.58 +The reason codes, which correspond to various point of the
16.59 +branch-and-cut algorithm implemented in the MIP solver, are described
16.60 +in Subsection ``Reasons for calling the callback routine'' below.
16.61 +
16.62 +To ignore calls for reasons, which are not processed by the callback
16.63 +routine, it should just return to the MIP solver doing nothing. For
16.64 +example:
16.65 +
16.66 +\begin{verbatim}
16.67 +void foo_bar(glp_tree *tree, void *info)
16.68 +{ . . .
16.69 + switch (glp_ios_reason(tree))
16.70 + { case GLP_IBRANCH:
16.71 + . . .
16.72 + break;
16.73 + case GLP_ISELECT:
16.74 + . . .
16.75 + break;
16.76 + default:
16.77 + /* ignore call for other reasons */
16.78 + break;
16.79 + }
16.80 + return;
16.81 +}
16.82 +\end{verbatim}
16.83 +
16.84 +To control the solution process as well as to obtain necessary
16.85 +information the callback routine may use the branch-and-cut API
16.86 +routines described in this chapter. Names of all these routines begin
16.87 +with `\verb|glp_ios_|'.
16.88 +
16.89 +\subsection{Branch-and-cut algorithm}
16.90 +
16.91 +This section gives a schematic description of the branch-and-cut
16.92 +algorithm as it is implemented in the GLPK MIP solver.
16.93 +
16.94 +\medskip
16.95 +
16.96 +{\it 1. Initialization}
16.97 +
16.98 +Set $L:=\{P_0\}$, where $L$ is the {\it active list} (i.e. the list of
16.99 +active subproblems), $P_0$ is the original MIP problem to be solved.
16.100 +
16.101 +Set $z^{\it best}:=+\infty$ (in case of minimization) or
16.102 +$z^{\it best}:=-\infty$ (in case of maximization), where $z^{\it best}$
16.103 +is {\it incumbent value}, i.e. an upper (minimization) or lower
16.104 +(maximization) global bound for $z^{\it opt}$, the optimal objective
16.105 +value for $P^0$.
16.106 +
16.107 +\medskip
16.108 +
16.109 +{\it 2. Subproblem selection}
16.110 +
16.111 +If $L=\varnothing$ then GO TO 9.
16.112 +
16.113 +Select $P\in L$, i.e. make active subproblem $P$ current.
16.114 +
16.115 +\medskip
16.116 +
16.117 +{\it 3. Solving LP relaxation}
16.118 +
16.119 +Solve $P^{\it LP}$, which is LP relaxation of $P$.
16.120 +
16.121 +If $P^{\it LP}$ has no primal feasible solution then GO TO 8.
16.122 +
16.123 +Let $z^{\it LP}$ be the optimal objective value for $P^{\it LP}$.
16.124 +
16.125 +If $z^{\it LP}\geq z^{\it best}$ (in case of minimization) or
16.126 +$z^{\it LP}\leq z^{\rm best}$ (in case of maximization) then GO TO 8.
16.127 +
16.128 +\medskip
16.129 +
16.130 +{\it 4. Adding ``lazy'' constraints}
16.131 +
16.132 +Let $x^{\it LP}$ be the optimal solution to $P^{\it LP}$.
16.133 +
16.134 +If there are ``lazy'' constraints (i.e. essential constraints not
16.135 +included in the original MIP problem $P_0$), which are violated at the
16.136 +optimal point $x^{\it LP}$, add them to $P$, and GO TO 3.
16.137 +
16.138 +\medskip
16.139 +
16.140 +{\it 5. Check for integrality}
16.141 +
16.142 +Let $x_j$ be a variable, which is required to be integer, and let
16.143 +$x^{\it LP}_j\in x^{\it LP}$ be its value in the optimal solution to
16.144 +$P^{\it LP}$.
16.145 +
16.146 +If $x^{\it LP}_j$ are integral for all integer variables, then a better
16.147 +integer feasible solution is found. Store its components, set
16.148 +$z^{\it best}:=z^{\it LP}$, and GO TO 8.
16.149 +
16.150 +\medskip
16.151 +
16.152 +{\it 6. Adding cutting planes}
16.153 +
16.154 +If there are cutting planes (i.e. valid constraints for $P$),
16.155 +which are violated at the optimal point $x^{\it LP}$, add them to $P$,
16.156 +and GO TO 3.
16.157 +
16.158 +\medskip
16.159 +
16.160 +{\it 7. Branching}
16.161 +
16.162 +Select {\it branching variable} $x_j$, i.e. a variable, which is
16.163 +required to be integer, and whose value $x^{\it LP}_j\in x^{\it LP}$ is
16.164 +fractional in the optimal solution to $P^{\it LP}$.
16.165 +
16.166 +Create new subproblem $P^D$ (so called {\it down branch}), which is
16.167 +identical to the current subproblem $P$ with exception that the upper
16.168 +bound of $x_j$ is replaced by $\lfloor x^{\it LP}_j\rfloor$. (For
16.169 +example, if $x^{\it LP}_j=3.14$, the new upper bound of $x_j$ in the
16.170 +down branch will be $\lfloor 3.14\rfloor=3$.)
16.171 +
16.172 +Create new subproblem $P^U$ (so called {\it up branch}), which is
16.173 +identical to the current subproblem $P$ with exception that the lower
16.174 +bound of $x_j$ is replaced by $\lceil x^{\it LP}_j\rceil$. (For example,
16.175 +if $x^{\it LP}_j=3.14$, the new lower bound of $x_j$ in the up branch
16.176 +will be $\lceil 3.14\rceil=4$.)
16.177 +
16.178 +Set $L:=(L\backslash\{P\})\cup\{P^D,P^U\}$, i.e. remove the current
16.179 +subproblem $P$ from the active list $L$ and add two new subproblems
16.180 +$P^D$ and $P^U$ to it. Then GO TO 2.
16.181 +
16.182 +\medskip
16.183 +
16.184 +{\it 8. Pruning}
16.185 +
16.186 +Remove from the active list $L$ all subproblems (including the current
16.187 +one), whose local bound $\widetilde{z}$ is not better than the global
16.188 +bound $z^{\it best}$, i.e. set $L:=L\backslash\{P\}$ for all $P$, where
16.189 +$\widetilde{z}\geq z^{\it best}$ (in case of minimization) or
16.190 +$\widetilde{z}\leq z^{\it best}$ (in case of maximization), and then
16.191 +GO TO 2.
16.192 +
16.193 +The local bound $\widetilde{z}$ for subproblem $P$ is an lower
16.194 +(minimization) or upper (maximization) bound for integer optimal
16.195 +solution to {\it this} subproblem (not to the original problem). This
16.196 +bound is local in the sense that only subproblems in the subtree rooted
16.197 +at node $P$ cannot have better integer feasible solutions. Note that
16.198 +the local bound is not necessarily the optimal objective value to LP
16.199 +relaxation $P^{\it LP}$.
16.200 +
16.201 +\medskip
16.202 +
16.203 +{\it 9. Termination}
16.204 +
16.205 +If $z^{\it best}=+\infty$ (in case of minimization) or
16.206 +$z^{\it best}=-\infty$ (in case of maximization), the original problem
16.207 +$P_0$ has no integer feasible solution. Otherwise, the last integer
16.208 +feasible solution stored on step 5 is the integer optimal solution to
16.209 +the original problem $P_0$ with $z^{\it opt}=z^{\it best}$. STOP.
16.210 +
16.211 +\subsection{The search tree}
16.212 +
16.213 +On the branching step of the branch-and-cut algorithm the current
16.214 +subproblem is divided into two\footnote{In more general cases the
16.215 +current subproblem may be divided into more than two subproblems.
16.216 +However, currently such feature is not used in GLPK.} new subproblems,
16.217 +so the set of all subproblems can be represented in the form of a rooted
16.218 +tree, which is called the {\it search} or {\it branch-and-bound} tree.
16.219 +An example of the search tree is shown on Fig.~1. Each node of the
16.220 +search tree corresponds to a subproblem, so the terms `node' and
16.221 +`subproblem' may be used synonymously.
16.222 +
16.223 +\newpage
16.224 +
16.225 +\begin{figure}[t]
16.226 +\noindent\hfil
16.227 +\xymatrix @R=20pt @C=10pt
16.228 +{&&&&&&*+<14pt>[o][F=]{A}\ar@{-}[dllll]\ar@{-}[dr]\ar@{-}[drrrr]&&&&\\
16.229 +&&*+<14pt>[o][F=]{B}\ar@{-}[dl]\ar@{-}[dr]&&&&&*+<14pt>[o][F=]{C}
16.230 +\ar@{-}[dll]\ar@{-}[dr]\ar@{-}[drrr]&&&*+<14pt>[o][F-]{\times}\\
16.231 +&*+<14pt>[o][F-]{\times}\ar@{-}[dl]\ar@{-}[d]\ar@{-}[dr]&&
16.232 +*+<14pt>[o][F-]{D}&&*+<14pt>[o][F=]{E}\ar@{-}[dl]\ar@{-}[dr]&&&
16.233 +*+<14pt>[o][F=]{F}\ar@{-}[dl]\ar@{-}[dr]&&*+<14pt>[o][F-]{G}\\
16.234 +*+<14pt>[o][F-]{\times}&*+<14pt>[o][F-]{\times}&*+<14pt>[o][F-]{\times}
16.235 +&&*+<14pt>[][F-]{H}&&*+<14pt>[o][F-]{I}&*+<14pt>[o][F-]{\times}&&
16.236 +*+<14pt>[o][F-]{J}&\\}
16.237 +
16.238 +\bigskip
16.239 +
16.240 +\noindent\hspace{.8in}
16.241 +\xymatrix @R=11pt
16.242 +{*+<20pt>[][F-]{}&*\txt{\makebox[1in][l]{Current}}&&
16.243 +*+<20pt>[o][F-]{}&*\txt{\makebox[1in][l]{Active}}\\
16.244 +*+<20pt>[o][F=]{}&*\txt{\makebox[1in][l]{Non-active}}&&
16.245 +*+<14pt>[o][F-]{\times}&*\txt{\makebox[1in][l]{Fathomed}}\\
16.246 +}
16.247 +
16.248 +\begin{center}
16.249 +Fig. 1. An example of the search tree.
16.250 +\end{center}
16.251 +\end{figure}
16.252 +
16.253 +In GLPK each node may have one of the following four statuses:
16.254 +
16.255 +$\bullet$ {\it current node} is the active node currently being
16.256 +processed;
16.257 +
16.258 +$\bullet$ {\it active node} is a leaf node, which still has to be
16.259 +processed;
16.260 +
16.261 +$\bullet$ {\it non-active node} is a node, which has been processed,
16.262 +but not fathomed;
16.263 +
16.264 +$\bullet$ {\it fathomed node} is a node, which has been processed and
16.265 +fathomed.
16.266 +
16.267 +In the data structure representing the search tree GLPK keeps only
16.268 +current, active, and non-active nodes. Once a node has been fathomed,
16.269 +it is removed from the tree data structure.
16.270 +
16.271 +Being created each node of the search tree is assigned a distinct
16.272 +positive integer called the {\it subproblem reference number}, which
16.273 +may be used by the application program to specify a particular node of
16.274 +the tree. The root node corresponding to the original problem to be
16.275 +solved is always assigned the reference number 1.
16.276 +
16.277 +\subsection{Current subproblem}
16.278 +
16.279 +The current subproblem is a MIP problem corresponding to the current
16.280 +node of the search tree. It is represented as the GLPK problem object
16.281 +(\verb|glp_prob|) that allows the application program using API routines
16.282 +to access its content in the standard way. If the MIP presolver is not
16.283 +used, it is the original problem object passed to the routine
16.284 +\verb|glp_intopt|; otherwise, it is an internal problem object built by
16.285 +the MIP presolver.
16.286 +
16.287 +Note that the problem object is used by the MIP solver itself during
16.288 +the solution process for various purposes (to solve LP relaxations, to
16.289 +perfom branching, etc.), and even if the MIP presolver is not used, the
16.290 +current content of the problem object may differ from its original
16.291 +content. For example, it may have additional rows, bounds of some rows
16.292 +and columns may be changed, etc. In particular, LP segment of the
16.293 +problem object corresponds to LP relaxation of the current subproblem.
16.294 +However, on exit from the MIP solver the content of the problem object
16.295 +is restored to its original state.
16.296 +
16.297 +To obtain information from the problem object the application program
16.298 +may use any API routines, which do not change the object. Using API
16.299 +routines, which change the problem object, is restricted to stipulated
16.300 +cases.
16.301 +
16.302 +\subsection{The cut pool}
16.303 +
16.304 +The {\it cut pool} is a set of cutting plane constraints maintained by
16.305 +the MIP solver. It is used by the GLPK cut generation routines and may
16.306 +be used by the application program in the same way, i.e. rather than
16.307 +to add cutting plane constraints directly to the problem object the
16.308 +application program may store them to the cut pool. In the latter case
16.309 +the solver looks through the cut pool, selects efficient constraints,
16.310 +and adds them to the problem object.
16.311 +
16.312 +\subsection{Reasons for calling the callback routine}
16.313 +
16.314 +The callback routine may be called by the MIP solver for the following
16.315 +reasons.
16.316 +
16.317 +\subsubsection*{Request for subproblem selection}
16.318 +
16.319 +The callback routine is called with the reason code \verb|GLP_ISELECT|
16.320 +if the current subproblem has been fathomed and therefore there is no
16.321 +current subproblem.
16.322 +
16.323 +In response the callback routine may select some subproblem from the
16.324 +active list and pass its reference number to the solver using the
16.325 +routine \verb|glp_ios_select_node|, in which case the solver continues
16.326 +the search from the specified active subproblem. If no selection is made
16.327 +by the callback routine, the solver uses a backtracking technique
16.328 +specified by the control parameter \verb|bt_tech|.
16.329 +
16.330 +To explore the active list (i.e. active nodes of the branch-and-bound
16.331 +tree) the callback routine may use the routines \verb|glp_ios_next_node|
16.332 +and \verb|glp_ios_prev_node|.
16.333 +
16.334 +\subsubsection*{Request for preprocessing}
16.335 +
16.336 +The callback routine is called with the reason code \verb|GLP_IPREPRO|
16.337 +if the current subproblem has just been selected from the active list
16.338 +and its LP relaxation is not solved yet.
16.339 +
16.340 +In response the callback routine may perform some preprocessing of the
16.341 +current subproblem like tightening bounds of some variables or removing
16.342 +bounds of some redundant constraints.
16.343 +
16.344 +\subsubsection*{Request for row generation}
16.345 +
16.346 +The callback routine is called with the reason code \verb|GLP_IROWGEN|
16.347 +if LP relaxation of the current subproblem has just been solved to
16.348 +optimality and its objective value is better than the best known integer
16.349 +feasible solution.
16.350 +
16.351 +In response the callback routine may add one or more ``lazy''
16.352 +constraints (rows), which are violated by the current optimal solution
16.353 +of LP relaxation, using API routines \verb|glp_add_rows|,
16.354 +\verb|glp_set_row_name|, \verb|glp_set_row_bnds|, and
16.355 +\verb|glp_set_mat_row|, in which case the solver will perform
16.356 +re-optimization of LP relaxation. If there are no violated constraints,
16.357 +the callback routine should just return.
16.358 +
16.359 +Optimal solution components for LP relaxation can be obtained with API
16.360 +routines \verb|glp_get_obj_val|, \verb|glp_get_row_prim|,
16.361 +\verb|glp_get_row_dual|, \verb|glp_get_col_prim|, and
16.362 +\verb|glp_get_col_dual|.
16.363 +
16.364 +\subsubsection*{Request for heuristic solution}
16.365 +
16.366 +The callback routine is called with the reason code \verb|GLP_IHEUR|
16.367 +if LP relaxation of the current subproblem being solved to optimality
16.368 +is integer infeasible (i.e. values of some structural variables of
16.369 +integer kind are fractional), though its objective value is better than
16.370 +the best known integer feasible solution.
16.371 +
16.372 +In response the callback routine may try applying a primal heuristic
16.373 +to find an integer feasible solution,\footnote{Integer feasible to the
16.374 +original MIP problem, not to the current subproblem.} which is better
16.375 +than the best known one. In case of success the callback routine may
16.376 +store such better solution in the problem object using the routine
16.377 +\verb|glp_ios_heur_sol|.
16.378 +
16.379 +\subsubsection*{Request for cut generation}
16.380 +
16.381 +The callback routine is called with the reason code \verb|GLP_ICUTGEN|
16.382 +if LP relaxation of the current subproblem being solved to optimality
16.383 +is integer infeasible (i.e. values of some structural variables of
16.384 +integer kind are fractional), though its objective value is better than
16.385 +the best known integer feasible solution.
16.386 +
16.387 +In response the callback routine may reformulate the {\it current}
16.388 +subproblem (before it will be splitted up due to branching) by adding to
16.389 +the problem object one or more {\it cutting plane constraints}, which
16.390 +cut off the fractional optimal point from the MIP
16.391 +polytope.\footnote{Since these constraints are added to the current
16.392 +subproblem, they may be globally as well as locally valid.}
16.393 +
16.394 +Adding cutting plane constraints may be performed in two ways.
16.395 +One way is the same as for the reason code \verb|GLP_IROWGEN| (see
16.396 +above), in which case the callback routine adds new rows corresponding
16.397 +to cutting plane constraints directly to the current subproblem.
16.398 +
16.399 +The other way is to add cutting plane constraints to the {\it cut pool},
16.400 +a set of cutting plane constraints maintained by the solver, rather than
16.401 +directly to the current subproblem. In this case after return from the
16.402 +callback routine the solver looks through the cut pool, selects
16.403 +efficient cutting plane constraints, adds them to the current
16.404 +subproblem, drops other constraints, and then performs re-optimization.
16.405 +
16.406 +\subsubsection*{Request for branching}
16.407 +
16.408 +The callback routine is called with the reason code \verb|GLP_IBRANCH|
16.409 +if LP relaxation of the current subproblem being solved to optimality
16.410 +is integer infeasible (i.e. values of some structural variables of
16.411 +integer kind are fractional), though its objective value is better than
16.412 +the best known integer feasible solution.
16.413 +
16.414 +In response the callback routine may choose some variable suitable for
16.415 +branching (i.e. integer variable, whose value in optimal solution to
16.416 +LP relaxation of the current subproblem is fractional) and pass its
16.417 +ordinal number to the solver using the routine
16.418 +\verb|glp_ios_branch_upon|, in which case the solver splits the current
16.419 +subproblem in two new subproblems and continues the search. If no choice
16.420 +is made by the callback routine, the solver uses a branching technique
16.421 +specified by the control parameter \verb|br_tech|.
16.422 +
16.423 +\subsubsection*{Better integer solution found}
16.424 +
16.425 +The callback routine is called with the reason code \verb|GLP_IBINGO|
16.426 +if LP relaxation of the current subproblem being solved to optimality
16.427 +is integer feasible (i.e. values of all structural variables of integer
16.428 +kind are integral within the working precision) and its objective value
16.429 +is better than the best known integer feasible solution.
16.430 +
16.431 +Optimal solution components for LP relaxation can be obtained in the
16.432 +same way as for the reason code \verb|GLP_IROWGEN| (see above).
16.433 +
16.434 +Components of the new MIP solution can be obtained with API routines
16.435 +\verb|glp_mip_obj_val|, \verb|glp_mip_row_val|, and
16.436 +\verb|glp_mip_col_val|. Note, however, that due to row/cut generation
16.437 +there may be additional rows in the problem object.
16.438 +
16.439 +The difference between optimal solution to LP relaxation and
16.440 +corresponding MIP solution is that in the former case some structural
16.441 +variables of integer kind (namely, basic variables) may have values,
16.442 +which are close to nearest integers within the working precision, while
16.443 +in the latter case all such variables have exact integral values.
16.444 +
16.445 +The reason \verb|GLP_IBINGO| is intended only for informational
16.446 +purposes, so the callback routine should not modify the problem object
16.447 +in this case.
16.448 +
16.449 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16.450 +
16.451 +\newpage
16.452 +
16.453 +\section{Basic routines}
16.454 +
16.455 +\subsection{glp\_ios\_reason---determine reason for calling the
16.456 +callback routine}
16.457 +
16.458 +\subsubsection*{Synopsis}
16.459 +
16.460 +\begin{verbatim}
16.461 +int glp_ios_reason(glp_tree *tree);
16.462 +\end{verbatim}
16.463 +
16.464 +\subsubsection*{Returns}
16.465 +
16.466 +The routine \verb|glp_ios_reason| returns a code, which indicates why
16.467 +the user-defined callback routine is being called:
16.468 +
16.469 +\verb|GLP_ISELECT|---request for subproblem selection;
16.470 +
16.471 +\verb|GLP_IPREPRO|---request for preprocessing;
16.472 +
16.473 +\verb|GLP_IROWGEN|---request for row generation;
16.474 +
16.475 +\verb|GLP_IHEUR |---request for heuristic solution;
16.476 +
16.477 +\verb|GLP_ICUTGEN|---request for cut generation;
16.478 +
16.479 +\verb|GLP_IBRANCH|---request for branching;
16.480 +
16.481 +\verb|GLP_IBINGO |---better integer solution found.
16.482 +
16.483 +\subsection{glp\_ios\_get\_prob---access the problem object}
16.484 +
16.485 +\subsubsection*{Synopsis}
16.486 +
16.487 +\begin{verbatim}
16.488 +glp_prob *glp_ios_get_prob(glp_tree *tree);
16.489 +\end{verbatim}
16.490 +
16.491 +\subsubsection*{Description}
16.492 +
16.493 +The routine \verb|glp_ios_get_prob| can be called from the user-defined
16.494 +callback routine to access the problem object, which is used by the MIP
16.495 +solver. It is the original problem object passed to the routine
16.496 +\verb|glp_intopt| if the MIP presolver is not used; otherwise it is an
16.497 +internal problem object built by the presolver.
16.498 +
16.499 +\subsubsection*{Returns}
16.500 +
16.501 +The routine \verb|glp_ios_get_prob| returns a pointer to the problem
16.502 +object used by the MIP solver.
16.503 +
16.504 +\subsubsection*{Comments}
16.505 +
16.506 +To obtain various information about the problem instance the callback
16.507 +routine can access the problem object (i.e. the object of type
16.508 +\verb|glp_prob|) using the routine \verb|glp_ios_get_prob|. It is the
16.509 +original problem object passed to the routine \verb|glp_intopt| if the
16.510 +MIP presolver is not used; otherwise it is an internal problem object
16.511 +built by the presolver.
16.512 +
16.513 +\subsection{glp\_ios\_row\_attr---determine additional row attributes}
16.514 +
16.515 +\subsubsection*{Synopsis}
16.516 +
16.517 +\begin{verbatim}
16.518 +void glp_ios_row_attr(glp_tree *tree, int i, glp_attr *attr);
16.519 +\end{verbatim}
16.520 +
16.521 +\subsubsection*{Description}
16.522 +
16.523 +The routine \verb|glp_ios_row_attr| retrieves additional attributes of
16.524 +$i$-th row of the current subproblem and stores them in the structure
16.525 +\verb|glp_attr|, which the parameter \verb|attr| points to.
16.526 +
16.527 +The structure \verb|glp_attr| has the following fields:
16.528 +
16.529 +\medskip
16.530 +
16.531 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
16.532 +\multicolumn{2}{@{}l}{{\tt int level}}\\
16.533 +&Subproblem level at which the row was created. (If \verb|level| = 0,
16.534 +the row was added either to the original problem object passed to the
16.535 +routine \verb|glp_intopt| or to the root subproblem on generating
16.536 +``lazy'' or/and cutting plane constraints.)\\
16.537 +\end{tabular}
16.538 +
16.539 +\medskip
16.540 +
16.541 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
16.542 +\multicolumn{2}{@{}l}{{\tt int origin}}\\
16.543 +&The row origin flag:\\
16.544 +&\verb|GLP_RF_REG |---regular constraint;\\
16.545 +&\verb|GLP_RF_LAZY|---``lazy'' constraint;\\
16.546 +&\verb|GLP_RF_CUT |---cutting plane constraint.\\
16.547 +\end{tabular}
16.548 +
16.549 +\medskip
16.550 +
16.551 +\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
16.552 +\multicolumn{2}{@{}l}{{\tt int klass}}\\
16.553 +&The row class descriptor, which is a number passed to the routine
16.554 +\verb|glp_ios_add_row| as its third parameter. If the row is a cutting
16.555 +plane constraint generated by the solver, its class may be the
16.556 +following:\\
16.557 +&\verb|GLP_RF_GMI |---Gomory's mixed integer cut;\\
16.558 +&\verb|GLP_RF_MIR |---mixed integer rounding cut;\\
16.559 +&\verb|GLP_RF_COV |---mixed cover cut;\\
16.560 +&\verb|GLP_RF_CLQ |---clique cut.\\
16.561 +\end{tabular}
16.562 +
16.563 +\newpage
16.564 +
16.565 +\subsection{glp\_ios\_mip\_gap---compute relative MIP gap}
16.566 +
16.567 +\subsubsection*{Synopsis}
16.568 +
16.569 +\begin{verbatim}
16.570 +double glp_ios_mip_gap(glp_tree *tree);
16.571 +\end{verbatim}
16.572 +
16.573 +\subsubsection*{Description}
16.574 +
16.575 +The routine \verb|glp_ios_mip_gap| computes the relative MIP gap (also
16.576 +called {\it duality gap}) with the following formula:
16.577 +$${\tt gap} = \frac{|{\tt best\_mip} - {\tt best\_bnd}|}
16.578 +{|{\tt best\_mip}| + {\tt DBL\_EPSILON}}$$
16.579 +where \verb|best_mip| is the best integer feasible solution found so
16.580 +far, \verb|best_bnd| is the best (global) bound. If no integer feasible
16.581 +solution has been found yet, \verb|gap| is set to \verb|DBL_MAX|.
16.582 +
16.583 +\subsubsection*{Returns}
16.584 +
16.585 +The routine \verb|glp_ios_mip_gap| returns the relative MIP gap.
16.586 +
16.587 +\subsubsection*{Comments}
16.588 +
16.589 +The relative MIP gap is used to measure the quality of the best integer
16.590 +feasible solution found so far, because the optimal solution value
16.591 +$z^*$ for the original MIP problem always lies in the range
16.592 +$${\tt best\_bnd}\leq z^*\leq{\tt best\_mip}$$
16.593 +in case of minimization, or in the range
16.594 +$${\tt best\_mip}\leq z^*\leq{\tt best\_bnd}$$
16.595 +in case of maximization.
16.596 +
16.597 +To express the relative MIP gap in percents the value returned by the
16.598 +routine \verb|glp_ios_mip_gap| should be multiplied by 100\%.
16.599 +
16.600 +\newpage
16.601 +
16.602 +\subsection{glp\_ios\_node\_data---access application-specific data}
16.603 +
16.604 +\subsubsection*{Synopsis}
16.605 +
16.606 +\begin{verbatim}
16.607 +void *glp_ios_node_data(glp_tree *tree, int p);
16.608 +\end{verbatim}
16.609 +
16.610 +\subsubsection*{Description}
16.611 +
16.612 +The routine \verb|glp_ios_node_data| allows the application accessing a
16.613 +memory block allocated for the subproblem (which may be active or
16.614 +inactive), whose reference number is $p$.
16.615 +
16.616 +The size of the block is defined by the control parameter \verb|cb_size|
16.617 +passed to the routine \verb|glp_intopt|. The block is initialized by
16.618 +binary zeros on creating corresponding subproblem, and its contents is
16.619 +kept until the subproblem will be removed from the tree.
16.620 +
16.621 +The application may use these memory blocks to store specific data for
16.622 +each subproblem.
16.623 +
16.624 +\subsubsection*{Returns}
16.625 +
16.626 +The routine \verb|glp_ios_node_data| returns a pointer to the memory
16.627 +block for the specified subproblem. Note that if \verb|cb_size| = 0, the
16.628 +routine returns a null pointer.
16.629 +
16.630 +\subsection{glp\_ios\_select\_node---select subproblem to continue the
16.631 +search}
16.632 +
16.633 +\subsubsection*{Synopsis}
16.634 +
16.635 +\begin{verbatim}
16.636 +void glp_ios_select_node(glp_tree *tree, int p);
16.637 +\end{verbatim}
16.638 +
16.639 +\subsubsection*{Description}
16.640 +
16.641 +The routine \verb|glp_ios_select_node| can be called from the
16.642 +user-defined callback routine in response to the reason
16.643 +\verb|GLP_ISELECT| to select an active subproblem, whose reference
16.644 +number is $p$. The search will be continued from the subproblem
16.645 +selected.
16.646 +
16.647 +\newpage
16.648 +
16.649 +\subsection{glp\_ios\_heur\_sol---provide solution found by heuristic}
16.650 +
16.651 +\subsubsection*{Synopsis}
16.652 +
16.653 +\begin{verbatim}
16.654 +int glp_ios_heur_sol(glp_tree *tree, const double x[]);
16.655 +\end{verbatim}
16.656 +
16.657 +\subsubsection*{Description}
16.658 +
16.659 +The routine \verb|glp_ios_heur_sol| can be called from the user-defined
16.660 +callback routine in response to the reason \verb|GLP_IHEUR| to provide
16.661 +an integer feasible solution found by a primal heuristic.
16.662 +
16.663 +Primal values of {\it all} variables (columns) found by the heuristic
16.664 +should be placed in locations $x[1]$, \dots, $x[n]$, where $n$ is the
16.665 +number of columns in the original problem object. Note that the routine
16.666 +\verb|glp_ios_heur_sol| does {\it not} check primal feasibility of the
16.667 +solution provided.
16.668 +
16.669 +Using the solution passed in the array $x$ the routine computes value
16.670 +of the objective function. If the objective value is better than the
16.671 +best known integer feasible solution, the routine computes values of
16.672 +auxiliary variables (rows) and stores all solution components in the
16.673 +problem object.
16.674 +
16.675 +\subsubsection*{Returns}
16.676 +
16.677 +If the provided solution is accepted, the routine
16.678 +\verb|glp_ios_heur_sol| returns zero. Otherwise, if the provided
16.679 +solution is rejected, the routine returns non-zero.
16.680 +
16.681 +\subsection{glp\_ios\_can\_branch---check if can branch upon specified
16.682 +variable}
16.683 +
16.684 +\subsubsection*{Synopsis}
16.685 +
16.686 +\begin{verbatim}
16.687 +int glp_ios_can_branch(glp_tree *tree, int j);
16.688 +\end{verbatim}
16.689 +
16.690 +\subsubsection*{Returns}
16.691 +
16.692 +If $j$-th variable (column) can be used to branch upon, the routine
16.693 +returns non-zero, otherwise zero.
16.694 +
16.695 +\newpage
16.696 +
16.697 +\subsection{glp\_ios\_branch\_upon---choose variable to branch upon}
16.698 +
16.699 +\subsubsection*{Synopsis}
16.700 +
16.701 +\begin{verbatim}
16.702 +void glp_ios_branch_upon(glp_tree *tree, int j, int sel);
16.703 +\end{verbatim}
16.704 +
16.705 +\subsubsection*{Description}
16.706 +
16.707 +The routine \verb|glp_ios_branch_upon| can be called from the
16.708 +user-defined callback routine in response to the reason
16.709 +\verb|GLP_IBRANCH| to choose a branching variable, whose ordinal number
16.710 +is $j$. Should note that only variables, for which the routine
16.711 +\verb|glp_ios_can_branch| returns non-zero, can be used to branch upon.
16.712 +
16.713 +The parameter \verb|sel| is a flag that indicates which branch
16.714 +(subproblem) should be selected next to continue the search:
16.715 +
16.716 +\verb|GLP_DN_BRNCH|---select down-branch;
16.717 +
16.718 +\verb|GLP_UP_BRNCH|---select up-branch;
16.719 +
16.720 +\verb|GLP_NO_BRNCH|---use general selection technique.
16.721 +
16.722 +\subsubsection*{Comments}
16.723 +
16.724 +On branching the solver removes the current active subproblem from the
16.725 +active list and creates two new subproblems ({\it down-} and {\it
16.726 +up-branches}), which are added to the end of the active list. Note that
16.727 +the down-branch is created before the up-branch, so the last active
16.728 +subproblem will be the up-branch.
16.729 +
16.730 +The down- and up-branches are identical to the current subproblem with
16.731 +exception that in the down-branch the upper bound of $x_j$, the variable
16.732 +chosen to branch upon, is replaced by $\lfloor x_j^*\rfloor$, while in
16.733 +the up-branch the lower bound of $x_j$ is replaced by
16.734 +$\lceil x_j^*\rceil$, where $x_j^*$ is the value of $x_j$ in optimal
16.735 +solution to LP relaxation of the current subproblem. For example, if
16.736 +$x_j^*=3.14$, the new upper bound of $x_j$ in the down-branch is
16.737 +$\lfloor 3.14\rfloor=3$, and the new lower bound in the up-branch is
16.738 +$\lceil 3.14\rceil=4$.)
16.739 +
16.740 +Additionally the callback routine may select either down- or up-branch,
16.741 +from which the solver will continue the search. If none of the branches
16.742 +is selected, a general selection technique will be used.
16.743 +
16.744 +\newpage
16.745 +
16.746 +\subsection{glp\_ios\_terminate---terminate the solution process}
16.747 +
16.748 +\subsubsection*{Synopsis}
16.749 +
16.750 +\begin{verbatim}
16.751 +void glp_ios_terminate(glp_tree *tree);
16.752 +\end{verbatim}
16.753 +
16.754 +\subsubsection*{Description}
16.755 +
16.756 +The routine \verb|glp_ios_terminate| sets a flag indicating that the
16.757 +MIP solver should prematurely terminate the search.
16.758 +
16.759 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16.760 +
16.761 +\newpage
16.762 +
16.763 +\section{The search tree exploring routines}
16.764 +
16.765 +\subsection{glp\_ios\_tree\_size---determine size of the search tree}
16.766 +
16.767 +\subsubsection*{Synopsis}
16.768 +
16.769 +\begin{verbatim}
16.770 +void glp_ios_tree_size(glp_tree *tree, int *a_cnt, int *n_cnt,
16.771 + int *t_cnt);
16.772 +\end{verbatim}
16.773 +
16.774 +\subsubsection*{Description}
16.775 +
16.776 +The routine \verb|glp_ios_tree_size| stores the following three counts
16.777 +which characterize the current size of the search tree:
16.778 +
16.779 +\verb|a_cnt| is the current number of active nodes, i.e. the current
16.780 +size of the active list;
16.781 +
16.782 +\verb|n_cnt| is the current number of all (active and inactive) nodes;
16.783 +
16.784 +\verb|t_cnt| is the total number of nodes including those which have
16.785 +been already removed from the tree. This count is increased whenever
16.786 +a new node appears in the tree and never decreased.
16.787 +
16.788 +If some of the parameters \verb|a_cnt|, \verb|n_cnt|, \verb|t_cnt| is
16.789 +a null pointer, the corresponding count is not stored.
16.790 +
16.791 +\subsection{glp\_ios\_curr\_node---determine current active subprob-\\
16.792 +lem}
16.793 +
16.794 +\subsubsection*{Synopsis}
16.795 +
16.796 +\begin{verbatim}
16.797 +int glp_ios_curr_node(glp_tree *tree);
16.798 +\end{verbatim}
16.799 +
16.800 +\subsubsection*{Returns}
16.801 +
16.802 +The routine \verb|glp_ios_curr_node| returns the reference number of the
16.803 +current active subproblem. However, if the current subproblem does not
16.804 +exist, the routine returns zero.
16.805 +
16.806 +\newpage
16.807 +
16.808 +\subsection{glp\_ios\_next\_node---determine next active subproblem}
16.809 +
16.810 +\subsubsection*{Synopsis}
16.811 +
16.812 +\begin{verbatim}
16.813 +int glp_ios_next_node(glp_tree *tree, int p);
16.814 +\end{verbatim}
16.815 +
16.816 +\subsubsection*{Returns}
16.817 +
16.818 +If the parameter $p$ is zero, the routine \verb|glp_ios_next_node|
16.819 +returns the reference number of the first active subproblem. However,
16.820 +if the tree is empty, zero is returned.
16.821 +
16.822 +If the parameter $p$ is not zero, it must specify the reference number
16.823 +of some active subproblem, in which case the routine returns the
16.824 +reference number of the next active subproblem. However, if there is
16.825 +no next active subproblem in the list, zero is returned.
16.826 +
16.827 +All subproblems in the active list are ordered chronologically, i.e.
16.828 +subproblem $A$ precedes subproblem $B$ if $A$ was created before $B$.
16.829 +
16.830 +\subsection{glp\_ios\_prev\_node---determine previous active subproblem}
16.831 +
16.832 +\subsubsection*{Synopsis}
16.833 +
16.834 +\begin{verbatim}
16.835 +int glp_ios_prev_node(glp_tree *tree, int p);
16.836 +\end{verbatim}
16.837 +
16.838 +\subsubsection*{Returns}
16.839 +
16.840 +If the parameter $p$ is zero, the routine \verb|glp_ios_prev_node|
16.841 +returns the reference number of the last active subproblem. However, if
16.842 +the tree is empty, zero is returned.
16.843 +
16.844 +If the parameter $p$ is not zero, it must specify the reference number
16.845 +of some active subproblem, in which case the routine returns the
16.846 +reference number of the previous active subproblem. However, if there
16.847 +is no previous active subproblem in the list, zero is returned.
16.848 +
16.849 +All subproblems in the active list are ordered chronologically, i.e.
16.850 +subproblem $A$ precedes subproblem $B$ if $A$ was created before $B$.
16.851 +
16.852 +\newpage
16.853 +
16.854 +\subsection{glp\_ios\_up\_node---determine parent subproblem}
16.855 +
16.856 +\subsubsection*{Synopsis}
16.857 +
16.858 +\begin{verbatim}
16.859 +int glp_ios_up_node(glp_tree *tree, int p);
16.860 +\end{verbatim}
16.861 +
16.862 +\subsubsection*{Returns}
16.863 +
16.864 +The parameter $p$ must specify the reference number of some (active or
16.865 +inactive) subproblem, in which case the routine \verb|iet_get_up_node|
16.866 +returns the reference number of its parent subproblem. However, if the
16.867 +specified subproblem is the root of the tree and, therefore, has
16.868 +no parent, the routine returns zero.
16.869 +
16.870 +\subsection{glp\_ios\_node\_level---determine subproblem level}
16.871 +
16.872 +\subsubsection*{Synopsis}
16.873 +
16.874 +\begin{verbatim}
16.875 +int glp_ios_node_level(glp_tree *tree, int p);
16.876 +\end{verbatim}
16.877 +
16.878 +\subsubsection*{Returns}
16.879 +
16.880 +The routine \verb|glp_ios_node_level| returns the level of the
16.881 +subproblem,\linebreak whose reference number is $p$, in the
16.882 +branch-and-bound tree. (The root subproblem has level 0, and the level
16.883 +of any other subproblem is the level of its parent plus one.)
16.884 +
16.885 +\subsection{glp\_ios\_node\_bound---determine subproblem local\\bound}
16.886 +
16.887 +\subsubsection*{Synopsis}
16.888 +
16.889 +\begin{verbatim}
16.890 +double glp_ios_node_bound(glp_tree *tree, int p);
16.891 +\end{verbatim}
16.892 +
16.893 +\subsubsection*{Returns}
16.894 +
16.895 +The routine \verb|glp_ios_node_bound| returns the local bound for
16.896 +(active or inactive) subproblem, whose reference number is $p$.
16.897 +
16.898 +\subsubsection*{Comments}
16.899 +
16.900 +The local bound for subproblem $p$ is an lower (minimization) or upper
16.901 +(maximization) bound for integer optimal solution to {\it this}
16.902 +subproblem (not to the original problem). This bound is local in the
16.903 +sense that only subproblems in the subtree rooted at node $p$ cannot
16.904 +have better integer feasible solutions.
16.905 +
16.906 +On creating a subproblem (due to the branching step) its local bound is
16.907 +inherited from its parent and then may get only stronger (never weaker).
16.908 +For the root subproblem its local bound is initially set to
16.909 +\verb|-DBL_MAX| (minimization) or \verb|+DBL_MAX| (maximization) and
16.910 +then improved as the root LP relaxation has been solved.
16.911 +
16.912 +Note that the local bound is not necessarily the optimal objective value
16.913 +to corresponding LP relaxation.
16.914 +
16.915 +\subsection{glp\_ios\_best\_node---find active subproblem with best
16.916 +local bound}
16.917 +
16.918 +\subsubsection*{Synopsis}
16.919 +
16.920 +\begin{verbatim}
16.921 +int glp_ios_best_node(glp_tree *tree);
16.922 +\end{verbatim}
16.923 +
16.924 +\subsubsection*{Returns}
16.925 +
16.926 +The routine \verb|glp_ios_best_node| returns the reference number of
16.927 +the active subproblem, whose local bound is best (i.e. smallest in case
16.928 +of minimization or largest in case of maximization). However, if the
16.929 +tree is empty, the routine returns zero.
16.930 +
16.931 +\subsubsection*{Comments}
16.932 +
16.933 +The best local bound is an lower (minimization) or upper (maximization)
16.934 +bound for integer optimal solution to the original MIP problem.
16.935 +
16.936 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16.937 +
16.938 +\newpage
16.939 +
16.940 +\section{The cut pool routines}
16.941 +
16.942 +\subsection{glp\_ios\_pool\_size---determine current size of the cut\\
16.943 +pool}
16.944 +
16.945 +\subsubsection*{Synopsis}
16.946 +
16.947 +\begin{verbatim}
16.948 +int glp_ios_pool_size(glp_tree *tree);
16.949 +\end{verbatim}
16.950 +
16.951 +\subsubsection*{Returns}
16.952 +
16.953 +The routine \verb|glp_ios_pool_size| returns the current size of the
16.954 +cut pool, that is, the number of cutting plane constraints currently
16.955 +added to it.
16.956 +
16.957 +\subsection{glp\_ios\_add\_row---add constraint to the cut pool}
16.958 +
16.959 +\subsubsection*{Synopsis}
16.960 +
16.961 +\begin{verbatim}
16.962 +int glp_ios_add_row(glp_tree *tree, const char *name,
16.963 + int klass, int flags, int len, const int ind[],
16.964 + const double val[], int type, double rhs);
16.965 +\end{verbatim}
16.966 +
16.967 +\subsubsection*{Description}
16.968 +
16.969 +The routine \verb|glp_ios_add_row| adds specified row (cutting plane
16.970 +constraint) to the cut pool.
16.971 +
16.972 +The cutting plane constraint should have the following format:
16.973 +$$\sum_{j\in J}a_jx_j\left\{\begin{array}{@{}c@{}}\geq\\\leq\\
16.974 +\end{array}\right\}b,$$
16.975 +where $J$ is a set of indices (ordinal numbers) of structural variables,
16.976 +$a_j$ are constraint coefficients, $x_j$ are structural variables, $b$
16.977 +is the right-hand side.
16.978 +
16.979 +The parameter \verb|name| specifies a symbolic name assigned to the
16.980 +constraint (1 up to 255 characters). If it is \verb|NULL| or an empty
16.981 +string, no name is assigned.
16.982 +
16.983 +The parameter \verb|klass| specifies the constraint class, which must
16.984 +be either zero or a number in the range from 101 to 200. The application
16.985 +may use this attribute to distinguish between cutting plane constraints
16.986 +of different classes.\footnote{Constraint classes numbered from 1 to 100
16.987 +are reserved for GLPK cutting plane generators.}
16.988 +
16.989 +The parameter \verb|flags| currently is not used and must be zero.
16.990 +
16.991 +Ordinal numbers of structural variables (i.e. column indices) $j\in J$
16.992 +and numerical values of corresponding constraint coefficients $a_j$ must
16.993 +be placed in locations \verb|ind[1]|, \dots, \verb|ind[len]| and
16.994 +\verb|val[1]|, \dots, \verb|val[len]|, respectively, where
16.995 +${\tt len}=|J|$ is the number of constraint coefficients,
16.996 +$0\leq{\tt len}\leq n$, and $n$ is the number of columns in the problem
16.997 +object. Coefficients with identical column indices are not allowed.
16.998 +Zero coefficients are allowed, however, they are ignored.
16.999 +
16.1000 +The parameter \verb|type| specifies the constraint type as follows:
16.1001 +
16.1002 +\verb|GLP_LO| means inequality constraint $\Sigma a_jx_j\geq b$;
16.1003 +
16.1004 +\verb|GLP_UP| means inequality constraint $\Sigma a_jx_j\leq b$;
16.1005 +
16.1006 +The parameter \verb|rhs| specifies the right-hand side $b$.
16.1007 +
16.1008 +All cutting plane constraints in the cut pool are identified by their
16.1009 +ordinal numbers 1, 2, \dots, $size$, where $size$ is the current size
16.1010 +of the cut pool. New constraints are always added to the end of the cut
16.1011 +pool, thus, ordinal numbers of previously added constraints are not
16.1012 +changed.
16.1013 +
16.1014 +\subsubsection*{Returns}
16.1015 +
16.1016 +The routine \verb|glp_ios_add_row| returns the ordinal number of the
16.1017 +cutting plane constraint added, which is the new size of the cut pool.
16.1018 +
16.1019 +\subsubsection*{Example}
16.1020 +
16.1021 +\begin{verbatim}
16.1022 +/* generate triangle cutting plane:
16.1023 + x[i] + x[j] + x[k] <= 1 */
16.1024 +. . .
16.1025 +/* add the constraint to the cut pool */
16.1026 +ind[1] = i, val[1] = 1.0;
16.1027 +ind[2] = j, val[2] = 1.0;
16.1028 +ind[3] = k, val[3] = 1.0;
16.1029 +glp_ios_add_row(tree, NULL, TRIANGLE_CUT, 0, 3, ind, val,
16.1030 + GLP_UP, 1.0);
16.1031 +\end{verbatim}
16.1032 +
16.1033 +\subsubsection*{Comments}
16.1034 +
16.1035 +Cutting plane constraints added to the cut pool are intended to be then
16.1036 +added only to the {\it current} subproblem, so these constraints can be
16.1037 +globally as well as locally valid. However, adding a constraint to the
16.1038 +cut pool does not mean that it will be added to the current
16.1039 +subproblem---it depends on the solver's decision: if the constraint
16.1040 +seems to be efficient, it is moved from the pool to the current
16.1041 +subproblem, otherwise it is simply dropped.\footnote{Globally valid
16.1042 +constraints could be saved and then re-used for other subproblems, but
16.1043 +currently such feature is not implemented.}
16.1044 +
16.1045 +Normally, every time the callback routine is called for cut generation,
16.1046 +the cut pool is empty. On the other hand, the solver itself can generate
16.1047 +cutting plane constraints (like Gomory's or mixed integer rounding
16.1048 +cuts), in which case the cut pool may be non-empty.
16.1049 +
16.1050 +\subsection{glp\_ios\_del\_row---remove constraint from the cut pool}
16.1051 +
16.1052 +\subsubsection*{Synopsis}
16.1053 +
16.1054 +\begin{verbatim}
16.1055 +void glp_ios_del_row(glp_tree *tree, int i);
16.1056 +\end{verbatim}
16.1057 +
16.1058 +\subsubsection*{Description}
16.1059 +
16.1060 +The routine \verb|glp_ios_del_row| deletes $i$-th row (cutting plane
16.1061 +constraint) from the cut pool, where $1\leq i\leq size$ is the ordinal
16.1062 +number of the constraint in the pool, $size$ is the current size of the
16.1063 +cut pool.
16.1064 +
16.1065 +Note that deleting a constraint from the cut pool leads to changing
16.1066 +ordinal numbers of other constraints remaining in the pool. New ordinal
16.1067 +numbers of the remaining constraints are assigned under assumption that
16.1068 +the original order of constraints is not changed. Let, for example,
16.1069 +there be four constraints $a$, $b$, $c$ and $d$ in the cut pool, which
16.1070 +have ordinal numbers 1, 2, 3 and 4, respectively, and let constraint
16.1071 +$b$ have been deleted. Then after deletion the remaining constraint $a$,
16.1072 +$c$ and $d$ are assigned new ordinal numbers 1, 2 and 3, respectively.
16.1073 +
16.1074 +To find the constraint to be deleted the routine \verb|glp_ios_del_row|
16.1075 +uses ``smart'' linear search, so it is recommended to remove constraints
16.1076 +in a natural or reverse order and avoid removing them in a random order.
16.1077 +
16.1078 +\subsubsection*{Example}
16.1079 +
16.1080 +\begin{verbatim}
16.1081 +/* keep first 10 constraints in the cut pool and remove other
16.1082 + constraints */
16.1083 +while (glp_ios_pool_size(tree) > 10)
16.1084 + glp_ios_del_row(tree, glp_ios_pool_size(tree));
16.1085 +\end{verbatim}
16.1086 +
16.1087 +\newpage
16.1088 +
16.1089 +\subsection{glp\_ios\_clear\_pool---remove all constraints from the cut
16.1090 +pool}
16.1091 +
16.1092 +\subsubsection*{Synopsis}
16.1093 +
16.1094 +\begin{verbatim}
16.1095 +void glp_ios_clear_pool(glp_tree *tree);
16.1096 +\end{verbatim}
16.1097 +
16.1098 +\subsubsection*{Description}
16.1099 +
16.1100 +The routine \verb|glp_ios_clear_pool| makes the cut pool empty deleting
16.1101 +all existing rows (cutting plane constraints) from it.
16.1102 +
16.1103 +%* eof *%
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
17.2 +++ b/doc/glpk06.tex Mon Dec 06 13:09:21 2010 +0100
17.3 @@ -0,0 +1,896 @@
17.4 +%* glpk06.tex *%
17.5 +
17.6 +\chapter{Miscellaneous API Routines}
17.7 +
17.8 +\section{GLPK environment routines}
17.9 +
17.10 +\subsection{glp\_long---64-bit integer data type}
17.11 +
17.12 +Some GLPK API routines use 64-bit integer data type, which is declared
17.13 +in the header \verb|glpk.h| as follows:
17.14 +
17.15 +\begin{verbatim}
17.16 +typedef struct { int lo, hi; } glp_long;
17.17 +\end{verbatim}
17.18 +
17.19 +\noindent
17.20 +where \verb|lo| contains low 32 bits, and \verb|hi| contains high 32
17.21 +bits of 64-bit integer value.\footnote{GLPK conforms to ILP32, LLP64,
17.22 +and LP64 programming models, where the built-in type {\tt int}
17.23 +corresponds to 32-bit integers.}
17.24 +
17.25 +\subsection{glp\_init\_env---initialize GLPK environment}
17.26 +
17.27 +\subsubsection*{Synopsis}
17.28 +
17.29 +\begin{verbatim}
17.30 +int glp_init_env(void);
17.31 +\end{verbatim}
17.32 +
17.33 +\subsubsection*{Description}
17.34 +
17.35 +The routine \verb|glp_init_env| initializes the GLPK environment.
17.36 +Normally the application program does not need to call this routine,
17.37 +because it is called automatically on the first call to any API routine.
17.38 +
17.39 +\newpage
17.40 +
17.41 +\subsubsection*{Returns}
17.42 +
17.43 +The routine \verb|glp_init_env| returns one of the following codes:
17.44 +
17.45 +\noindent
17.46 +0 --- initialization successful;
17.47 +
17.48 +\noindent
17.49 +1 --- environment is already initialized;
17.50 +
17.51 +\noindent
17.52 +2 --- initialization failed (insufficient memory);
17.53 +
17.54 +\noindent
17.55 +3 --- initialization failed (unsupported programming model).
17.56 +
17.57 +\subsection{glp\_version---determine library version}
17.58 +
17.59 +\subsubsection*{Synopsis}
17.60 +
17.61 +\begin{verbatim}
17.62 +const char *glp_version(void);
17.63 +\end{verbatim}
17.64 +
17.65 +\subsubsection*{Returns}
17.66 +
17.67 +The routine \verb|glp_version| returns a pointer to a null-terminated
17.68 +character string, which specifies the version of the GLPK library in
17.69 +the form \verb|"X.Y"|, where `\verb|X|' is the major version number, and
17.70 +`\verb|Y|' is the minor version number, for example, \verb|"4.16"|.
17.71 +
17.72 +\subsubsection*{Example}
17.73 +
17.74 +\begin{footnotesize}
17.75 +\begin{verbatim}
17.76 +printf("GLPK version is %s\n", glp_version());
17.77 +\end{verbatim}
17.78 +\end{footnotesize}
17.79 +
17.80 +\subsection{glp\_free\_env---free GLPK environment}
17.81 +
17.82 +\subsubsection*{Synopsis}
17.83 +
17.84 +\begin{verbatim}
17.85 +int glp_free_env(void);
17.86 +\end{verbatim}
17.87 +
17.88 +\subsubsection*{Description}
17.89 +
17.90 +The routine \verb|glp_free_env| frees all resources used by GLPK
17.91 +routines (memory blocks, etc.) which are currently still in use.
17.92 +
17.93 +Normally the application program does not need to call this routine,
17.94 +because GLPK routines always free all unused resources. However, if
17.95 +the application program even has deleted all problem objects, there
17.96 +will be several memory blocks still allocated for the internal library
17.97 +needs. For some reasons the application program may want GLPK to free
17.98 +this memory, in which case it should call \verb|glp_free_env|.
17.99 +
17.100 +Note that a call to \verb|glp_free_env| invalidates all problem objects
17.101 +which still exist.
17.102 +
17.103 +\subsubsection*{Returns}
17.104 +
17.105 +The routine \verb|glp_free_env| returns one of the following codes:
17.106 +
17.107 +\noindent
17.108 +0 --- termination successful;
17.109 +
17.110 +\noindent
17.111 +1 --- environment is inactive (was not initialized).
17.112 +
17.113 +\subsection{glp\_printf---write formatted output to terminal}
17.114 +
17.115 +\subsubsection*{Synopsis}
17.116 +
17.117 +\begin{verbatim}
17.118 +void glp_printf(const char *fmt, ...);
17.119 +\end{verbatim}
17.120 +
17.121 +\subsubsection*{Description}
17.122 +
17.123 +The routine \verb|glp_printf| uses the format control string
17.124 +\verb|fmt| to format its parameters and writes the formatted output to
17.125 +the terminal.
17.126 +
17.127 +This routine is a replacement of the standard C function
17.128 +\verb|printf| and used by all GLPK routines to perform terminal
17.129 +output. The application program may use \verb|glp_printf| for the same
17.130 +purpose that allows controlling its terminal output with the routines
17.131 +\verb|glp_term_out| and \verb|glp_term_hook|.
17.132 +
17.133 +\subsection{glp\_vprintf---write formatted output to terminal}
17.134 +
17.135 +\subsubsection*{Synopsis}
17.136 +
17.137 +\begin{verbatim}
17.138 +void glp_vprintf(const char *fmt, va_list arg);
17.139 +\end{verbatim}
17.140 +
17.141 +\subsubsection*{Description}
17.142 +
17.143 +The routine \verb|glp_vprintf| uses the format control string
17.144 +\verb|fmt| to format its parameters specified by the list \verb|arg|
17.145 +and writes the formatted output to the terminal.
17.146 +
17.147 +This routine is a replacement of the standard C function
17.148 +\verb|vprintf| and used by all GLPK routines to perform terminal
17.149 +output. The application program may use \verb|glp_vprintf| for the same
17.150 +purpose that allows controlling its terminal output with the routines
17.151 +\verb|glp_term_out| and \verb|glp_term_hook|.
17.152 +
17.153 +\newpage
17.154 +
17.155 +\subsection{glp\_term\_out---enable/disable terminal output}
17.156 +
17.157 +\subsubsection*{Synopsis}
17.158 +
17.159 +\begin{verbatim}
17.160 +int glp_term_out(int flag);
17.161 +\end{verbatim}
17.162 +
17.163 +\subsubsection*{Description}
17.164 +
17.165 +Depending on the parameter flag the routine \verb|glp_term_out| enables
17.166 +or disables terminal output performed by glpk routines:
17.167 +
17.168 +\verb|GLP_ON | --- enable terminal output;
17.169 +
17.170 +\verb|GLP_OFF| --- disable terminal output.
17.171 +
17.172 +\subsubsection*{Returns}
17.173 +
17.174 +The routine \verb|glp_term_out| returns the previous value of the
17.175 +terminal output flag (\verb|GLP_ON| or \verb|GLP_OFF|).
17.176 +
17.177 +\subsection{glp\_term\_hook---intercept terminal output}
17.178 +
17.179 +\subsubsection*{Synopsis}
17.180 +
17.181 +\begin{verbatim}
17.182 +void glp_term_hook(int (*func)(void *info, const char *s),
17.183 + void *info);
17.184 +\end{verbatim}
17.185 +
17.186 +\subsubsection*{Description}
17.187 +
17.188 +The routine \verb|glp_term_hook| installs the user-defined hook routine
17.189 +to intercept all terminal output performed by GLPK routines.
17.190 +
17.191 +%This feature can be used to redirect the terminal output to other
17.192 +%destination, for example, to a file or a text window.
17.193 +
17.194 +The parameter {\it func} specifies the user-defined hook routine. It is
17.195 +called from an internal printing routine, which passes to it two
17.196 +parameters: {\it info} and {\it s}. The parameter {\it info} is a
17.197 +transit pointer specified in corresponding call to the routine
17.198 +\verb|glp_term_hook|; it may be used to pass some additional information
17.199 +to the hook routine. The parameter {\it s} is a pointer to the null
17.200 +terminated character string, which is intended to be written to the
17.201 +terminal. If the hook routine returns zero, the printing routine writes
17.202 +the string {\it s} to the terminal in a usual way; otherwise, if the
17.203 +hook routine returns non-zero, no terminal output is performed.
17.204 +
17.205 +To uninstall the hook routine both parameters {\it func} and {\it info}
17.206 +should be specified as \verb|NULL|.
17.207 +
17.208 +\newpage
17.209 +
17.210 +\subsubsection*{Example}
17.211 +
17.212 +\begin{footnotesize}
17.213 +\begin{verbatim}
17.214 +static int hook(void *info, const char *s)
17.215 +{ FILE *foo = info;
17.216 + fputs(s, foo);
17.217 + return 1;
17.218 +}
17.219 +
17.220 +int main(void)
17.221 +{ FILE *foo;
17.222 + . . .
17.223 + /* redirect terminal output */
17.224 + glp_term_hook(hook, foo);
17.225 + . . .
17.226 + /* resume terminal output */
17.227 + glp_term_hook(NULL, NULL);
17.228 + . . .
17.229 +}
17.230 +\end{verbatim}
17.231 +\end{footnotesize}
17.232 +
17.233 +\subsection{glp\_open\_tee---start copying terminal output}
17.234 +
17.235 +\subsubsection*{Synopsis}
17.236 +
17.237 +\begin{verbatim}
17.238 +int glp_open_tee(const char *fname);
17.239 +\end{verbatim}
17.240 +
17.241 +\subsubsection*{Description}
17.242 +
17.243 +The routine \verb|glp_open_tee| starts copying all the terminal output
17.244 +to an output text file, whose name is specified by the character string
17.245 +\verb|fname|.
17.246 +
17.247 +\subsubsection*{Returns}
17.248 +
17.249 +The routine \verb|glp_open_tee| returns one of the following codes:
17.250 +
17.251 +\noindent
17.252 +0 --- operation successful;
17.253 +
17.254 +\noindent
17.255 +1 --- copying terminal output is already active;
17.256 +
17.257 +\noindent
17.258 +2 --- unable to create output file.
17.259 +
17.260 +\newpage
17.261 +
17.262 +\subsection{glp\_close\_tee---stop copying terminal output}
17.263 +
17.264 +\subsubsection*{Synopsis}
17.265 +
17.266 +\begin{verbatim}
17.267 +int glp_close_tee(void);
17.268 +\end{verbatim}
17.269 +
17.270 +\subsubsection*{Description}
17.271 +
17.272 +The routine \verb|glp_close_tee| stops copying the terminal output to
17.273 +the output text file previously open by the routine \verb|glp_open_tee|
17.274 +closing that file.
17.275 +
17.276 +\subsubsection*{Returns}
17.277 +
17.278 +The routine \verb|glp_close_tee| returns one of the following codes:
17.279 +
17.280 +\noindent
17.281 +0 --- operation successful;
17.282 +
17.283 +\noindent
17.284 +1 --- copying terminal output was not started.
17.285 +
17.286 +\subsection{glp\_error---display error message and terminate execution}
17.287 +
17.288 +\subsubsection*{Synopsis}
17.289 +
17.290 +\begin{verbatim}
17.291 +void glp_error(const char *fmt, ...);
17.292 +\end{verbatim}
17.293 +
17.294 +\subsubsection*{Description}
17.295 +
17.296 +The routine \verb|glp_error| (implemented as a macro) formats its
17.297 +parameters using the format control string \verb|fmt|, writes the
17.298 +formatted message to the terminal, and then abnormally terminates the
17.299 +program.
17.300 +
17.301 +\subsection{glp\_assert---check logical condition}
17.302 +
17.303 +\subsubsection*{Synopsis}
17.304 +
17.305 +\begin{verbatim}
17.306 +void glp_assert(int expr);
17.307 +\end{verbatim}
17.308 +
17.309 +\subsubsection*{Description}
17.310 +
17.311 +The routine \verb|glp_assert| (implemented as a macro) checks
17.312 +a logical condition specified by the expression \verb|expr|. If the
17.313 +condition is true (non-zero), the routine does nothing; otherwise, if
17.314 +the condition is false (zero), the routine prints an error message and
17.315 +abnormally terminates the program.
17.316 +
17.317 +This routine is a replacement of the standard C function \verb|assert|
17.318 +and used by all GLPK routines to check program logic. The application
17.319 +program may use \verb|glp_assert| for the same purpose.
17.320 +
17.321 +\subsection{glp\_error\_hook---install hook to intercept abnormal
17.322 +termination}
17.323 +
17.324 +\subsubsection*{Synopsis}
17.325 +
17.326 +\begin{verbatim}
17.327 +void glp_error_hook(void (*func)(void *info), void *info);
17.328 +\end{verbatim}
17.329 +
17.330 +\subsubsection*{Description}
17.331 +
17.332 +The routine \verb|glp_error_hook| installs a user-defined hook routine
17.333 +to intercept abnormal termination.
17.334 +
17.335 +The parameter \verb|func| specifies the user-defined hook routine. It
17.336 +is called from the routine \verb|glp_error| before the latter calls the
17.337 +abort function to abnormally terminate the application program because
17.338 +of fatal error. The parameter \verb|info| is a transit pointer,
17.339 +specified in the corresponding call to the routine
17.340 +\verb|glp_error_hook|; it may be used to pass some information to the
17.341 +hook routine.
17.342 +
17.343 +To uninstall the hook routine the parameters \verb|func| and \verb|info|
17.344 +should be specified as \verb|NULL|.
17.345 +
17.346 +\subsubsection*{Usage note}
17.347 +
17.348 +If the hook routine returns, the application program is abnormally
17.349 +terminated. To prevent abnormal termnation the hook routine may perform
17.350 +a global jump using the standard function \verb|longjmp|, in which case
17.351 +the application program {\it must} call the routine \verb|glp_free_env|.
17.352 +
17.353 +\subsection{glp\_malloc---allocate memory block}
17.354 +
17.355 +\subsubsection*{Synopsis}
17.356 +
17.357 +\begin{verbatim}
17.358 +void *glp_malloc(int size);
17.359 +\end{verbatim}
17.360 +
17.361 +\subsubsection*{Description}
17.362 +
17.363 +The routine \verb|glp_malloc| dynamically allocates a memory block of
17.364 +\verb|size| bytes long. Should note that:
17.365 +
17.366 +1) the parameter \verb|size| must be positive;
17.367 +
17.368 +2) being allocated the memory block contains arbitrary data, that is,
17.369 +it is {\it not} initialized by binary zeros;
17.370 +
17.371 +3) if the block cannot be allocated due to insufficient memory, the
17.372 +routine prints an error message and abnormally terminates the program.
17.373 +
17.374 +This routine is a replacement of the standard C function \verb|malloc|
17.375 +and used by all GLPK routines for dynamic memory allocation. The
17.376 +application program may use \verb|glp_malloc| for the same purpose.
17.377 +
17.378 +\subsubsection*{Returns}
17.379 +
17.380 +The routine \verb|glp_malloc| returns a pointer to the memory block
17.381 +allocated. To free this block the routine \verb|glp_free| (not the
17.382 +standard C function \verb|free|!) must be used.
17.383 +
17.384 +\subsection{glp\_calloc---allocate memory block}
17.385 +
17.386 +\subsubsection*{Synopsis}
17.387 +
17.388 +\begin{verbatim}
17.389 +void *glp_calloc(int n, int size);
17.390 +\end{verbatim}
17.391 +
17.392 +\subsubsection*{Description}
17.393 +
17.394 +The routine \verb|glp_calloc| dynamically allocates a memory block of
17.395 +\verb|n|$\times$\verb|size| bytes long. Should note that:
17.396 +
17.397 +1) both parameters \verb|n| and \verb|size| must be positive;
17.398 +
17.399 +2) being allocated the memory block contains arbitrary data, that is,
17.400 +it is {\it not} initialized by binary zeros;
17.401 +
17.402 +3) if the block cannot be allocated due to insufficient memory, the
17.403 +routine prints an error message and abnormally terminates the program.
17.404 +
17.405 +This routine is a replacement of the standard C function \verb|calloc|
17.406 +(with exception that the block is not cleaned) and used by all GLPK
17.407 +routines for dynamic memory allocation. The application program may use
17.408 +\verb|glp_calloc| for the same purpose.
17.409 +
17.410 +\subsubsection*{Returns}
17.411 +
17.412 +The routine \verb|glp_calloc| returns a pointer to the memory block
17.413 +allocated. To free this block the routine \verb|glp_free| (not the
17.414 +standard C function \verb|free|!) must be used.
17.415 +
17.416 +\subsection{glp\_free---free memory block}
17.417 +
17.418 +\subsubsection*{Synopsis}
17.419 +
17.420 +\begin{verbatim}
17.421 +void glp_free(void *ptr);
17.422 +\end{verbatim}
17.423 +
17.424 +\subsubsection*{Description}
17.425 +
17.426 +The routine \verb|glp_free| frees (deallocates) a memory block pointed
17.427 +to by \verb|ptr|, which was previously allocated by the routine
17.428 +\verb|glp_malloc| or \verb|glp_calloc|. Note that the pointer \verb|ptr|
17.429 +must valid and must not be \verb|NULL|.
17.430 +
17.431 +This routine is a replacement of the standard C function \verb|free|
17.432 +and used by all GLPK routines for dynamic memory allocation. The
17.433 +application program may use \verb|glp_free| for the same purpose.
17.434 +
17.435 +\subsection{glp\_mem\_usage---get memory usage information}
17.436 +
17.437 +\subsubsection*{Synopsis}
17.438 +
17.439 +\begin{verbatim}
17.440 +void glp_mem_usage(int *count, int *cpeak, glp_long *total,
17.441 + glp_long *tpeak);
17.442 +\end{verbatim}
17.443 +
17.444 +\subsubsection*{Description}
17.445 +
17.446 +The routine \verb|glp_mem_usage| reports some information about
17.447 +utilization of the memory by the routines \verb|glp_malloc|,
17.448 +\verb|glp_calloc|, and \verb|glp_free|. Information is stored to
17.449 +locations specified by corresponding parameters (see below). Any
17.450 +parameter can be specified as \verb|NULL|, in which case corresponding
17.451 +information is not stored.
17.452 +
17.453 +\verb|*count| is the number of currently allocated memory blocks.
17.454 +
17.455 +\verb|*cpeak| is the peak value of \verb|*count| reached since the
17.456 +initialization of the GLPK library environment.
17.457 +
17.458 +\verb|*total| is the total amount, in bytes, of currently allocated
17.459 +memory blocks.
17.460 +
17.461 +\verb|*tpeak| is the peak value of \verb|*total| reached since the
17.462 +initialization of the GLPK library envirionment.
17.463 +
17.464 +\subsubsection*{Example}
17.465 +
17.466 +\begin{footnotesize}
17.467 +\begin{verbatim}
17.468 +glp_mem_usage(&count, NULL, NULL, NULL);
17.469 +printf("%d memory block(s) are still allocated\n", count);
17.470 +\end{verbatim}
17.471 +\end{footnotesize}
17.472 +
17.473 +\subsection{glp\_mem\_limit---set memory usage limit}
17.474 +
17.475 +\subsubsection*{Synopsis}
17.476 +
17.477 +\begin{verbatim}
17.478 +void glp_mem_limit(int limit);
17.479 +\end{verbatim}
17.480 +
17.481 +\subsubsection*{Description}
17.482 +
17.483 +The routine \verb|glp_mem_limit| limits the amount of memory available
17.484 +for dynamic allocation (with the routines \verb|glp_malloc| and
17.485 +\verb|glp_calloc|) to \verb|limit| megabytes.
17.486 +
17.487 +\subsection{glp\_time---determine current universal time}
17.488 +
17.489 +\subsubsection*{Synopsis}
17.490 +
17.491 +\begin{verbatim}
17.492 +glp_long glp_time(void);
17.493 +\end{verbatim}
17.494 +
17.495 +\subsection*{Returns}
17.496 +
17.497 +The routine \verb|glp_time| returns the current universal time (UTC),
17.498 +in milliseconds, elapsed since 00:00:00 GMT January 1, 1970.
17.499 +
17.500 +\subsection{glp\_difftime---compute difference between two time values}
17.501 +
17.502 +\subsubsection*{Synopsis}
17.503 +
17.504 +\begin{verbatim}
17.505 +double glp_difftime(glp_long t1, glp_long t0);
17.506 +\end{verbatim}
17.507 +
17.508 +\subsection*{Returns}
17.509 +
17.510 +The routine \verb|glp_difftime| returns the difference between two time
17.511 +values \verb|t1| and \verb|t0|, expressed in seconds.
17.512 +
17.513 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
17.514 +
17.515 +\newpage
17.516 +
17.517 +\section{Plain data file reading routines}
17.518 +
17.519 +\subsection{Introduction}
17.520 +
17.521 +On developing simple applications to solve optimization problems it is
17.522 +often needed to read data from plain text files. To do this the standard
17.523 +C function \verb|fscanf| may be used, however, it is not convenient; for
17.524 +example, if it scans an integer number according to the format
17.525 +specification `\verb|%d|', and that number is coded incorrectly,
17.526 +no diagnostics is provided.
17.527 +
17.528 +This section describes a set of GLPK API routines, which may be used in
17.529 +application programs to simplify reading data from plain text files.
17.530 +
17.531 +\subsubsection*{Example 1}
17.532 +
17.533 +The following main program reads ten integer numbers from plain text
17.534 +file \verb|data.txt| and prints their sum.
17.535 +
17.536 +\begin{footnotesize}
17.537 +\begin{verbatim}
17.538 +/* sdfsamp1.c */
17.539 +
17.540 +#include <stdio.h>
17.541 +#include <stdlib.h>
17.542 +#include <glpk.h>
17.543 +
17.544 +int main(void)
17.545 +{ glp_data *data;
17.546 + int j, num, sum;
17.547 + /* open plain data file */
17.548 + data = glp_sdf_open_file("data.txt");
17.549 + if (data == NULL) exit(EXIT_FAILURE);
17.550 + sum = 0;
17.551 + for (j = 1; j <= 10; j++)
17.552 + { /* read next integer number */
17.553 + num = glp_sdf_read_int(data);
17.554 + sum += num;
17.555 + }
17.556 + printf("sum = %d\n", sum);
17.557 + /* close plain data file */
17.558 + glp_sdf_close_file(data);
17.559 + return 0;
17.560 +}
17.561 +
17.562 +/* eof */
17.563 +\end{verbatim}
17.564 +\end{footnotesize}
17.565 +
17.566 +The input data are coded in free format. For example, the file
17.567 +\verb|data.txt| may look like this:
17.568 +
17.569 +\begin{footnotesize}
17.570 +\begin{verbatim}
17.571 +123 65 432 890 -12 743 895 -7 111 326
17.572 +\end{verbatim}
17.573 +\end{footnotesize}
17.574 +
17.575 +\noindent
17.576 +or like this:
17.577 +
17.578 +\begin{footnotesize}
17.579 +\begin{verbatim}
17.580 +123 65 432 890 -12
17.581 +743 895 -7 111 326
17.582 +\end{verbatim}
17.583 +\end{footnotesize}
17.584 +
17.585 +\noindent
17.586 +If the input data file contains incorrect data, the routine
17.587 +\verb|glp_sdf_read_int| prints an error message and, if no error
17.588 +handling is provided by the application program, abnormally terminates
17.589 +program execution. For example, the file \verb|data.txt| could contain
17.590 +the following data:
17.591 +
17.592 +\begin{footnotesize}
17.593 +\begin{verbatim}
17.594 +123 65 432 890 -12
17.595 +743 895 =7 111 326
17.596 +\end{verbatim}
17.597 +\end{footnotesize}
17.598 +
17.599 +\noindent
17.600 +in which case the error message would be the following:
17.601 +
17.602 +\begin{footnotesize}
17.603 +\begin{verbatim}
17.604 +data.txt:2: cannot convert `=7' to integer
17.605 +\end{verbatim}
17.606 +\end{footnotesize}
17.607 +
17.608 +\subsubsection*{Example 2}
17.609 +
17.610 +As it was said above, by default any attempt to read incorrect data
17.611 +leads to abnormal termination. However, sometimes it is desirable to
17.612 +catch such errors. This feature is illustrated by the following main
17.613 +program, which does the same job as in the previous example.
17.614 +
17.615 +\begin{footnotesize}
17.616 +\begin{verbatim}
17.617 +/* sdfsamp2.c */
17.618 +
17.619 +#include <setjmp.h>
17.620 +#include <stdio.h>
17.621 +#include <stdlib.h>
17.622 +#include <glpk.h>
17.623 +
17.624 +int main(void)
17.625 +{ glp_data *data;
17.626 + jmp_buf jump;
17.627 + int j, num, sum, ret;
17.628 + /* open plain data file */
17.629 + data = glp_sdf_open_file("data.txt");
17.630 + if (data == NULL)
17.631 + { ret = EXIT_FAILURE;
17.632 + goto done;
17.633 + }
17.634 + /* set up error handling */
17.635 + if (setjmp(jump))
17.636 + { ret = EXIT_FAILURE;
17.637 + goto done;
17.638 + }
17.639 + glp_sdf_set_jump(data, jump);
17.640 + /* read and process data */
17.641 + sum = 0;
17.642 + for (j = 1; j <= 10; j++)
17.643 + { /* read next integer number */
17.644 + num = glp_sdf_read_int(data);
17.645 + if (abs(num) > 1000)
17.646 + glp_sdf_error(data, "integer %d too big\n", num);
17.647 + if (num < 0)
17.648 + glp_sdf_warning(data, "integer %d is negative\n", num);
17.649 + sum += num;
17.650 + }
17.651 + printf("sum = %d\n", sum);
17.652 + ret = EXIT_SUCCESS;
17.653 +done: /* close plain data file */
17.654 + if (data != NULL) glp_sdf_close_file(data);
17.655 + return ret;
17.656 +}
17.657 +
17.658 +/* eof */
17.659 +\end{verbatim}
17.660 +\end{footnotesize}
17.661 +
17.662 +\subsection{glp\_sdf\_open\_file---open plain data file}
17.663 +
17.664 +\subsubsection*{Synopsis}
17.665 +
17.666 +\begin{verbatim}
17.667 +glp_data *glp_sdf_open_file(const char *fname);
17.668 +\end{verbatim}
17.669 +
17.670 +\subsubsection*{Description}
17.671 +
17.672 +The routine \verb|glp_sdf_open_file| opens a plain data file, whose
17.673 +name is specified by the character string \verb|fname|.
17.674 +
17.675 +\subsubsection*{Returns}
17.676 +
17.677 +If the operation was successful, the routine \verb|glp_sdf_open_file|
17.678 +returns a pointer to the opaque program object of the type
17.679 +\verb|glp_data|\footnote{This data structure is declared in the header
17.680 +file {\tt glpk.h}.} associated with the plain data file. Otherwise, if
17.681 +the operation failed, the routine prints an error message and returns
17.682 +\verb|NULL|.
17.683 +
17.684 +\subsubsection*{Note}
17.685 +
17.686 +The application program should use the pointer returned by the routine
17.687 +\verb|glp_sdf_open_file| to perform all subsequent operations on the
17.688 +data file.
17.689 +
17.690 +\newpage
17.691 +
17.692 +\subsection{glp\_sdf\_set\_jump---set up error handling}
17.693 +
17.694 +\subsubsection*{Synopsis}
17.695 +
17.696 +\begin{verbatim}
17.697 +void glp_sdf_set_jump(glp_data *data, jmp_buf jump);
17.698 +\end{verbatim}
17.699 +
17.700 +\subsubsection*{Description}
17.701 +
17.702 +The routine \verb|glp_sdf_set_jump| sets up error handling for the
17.703 +plain data file specified by the parameter \verb|data|.
17.704 +
17.705 +The parameter \verb|jump| specifies the environment buffer, which must
17.706 +be initialized with the standard C function \verb|setjmp| prior to call
17.707 +to the routine \verb|glp_sdf_set_jump|. Detecting any incorrect data in
17.708 +the corresponding plain data file will cause non-local ``go to'' by
17.709 +a call to the standard C function \verb|longjmp|.
17.710 +
17.711 +The parameter \verb|jump| can be specified as \verb|NULL|, in which
17.712 +case the routine \verb|glp_sdf_set_jump| restores the default behavior,
17.713 +in which case detecting incorrect data leads to abnormal termination.
17.714 +
17.715 +\subsection{glp\_sdf\_error---print error message}
17.716 +
17.717 +\subsubsection*{Synopsis}
17.718 +
17.719 +\begin{verbatim}
17.720 +void glp_sdf_error(glp_data *data, const char *fmt, ...);
17.721 +\end{verbatim}
17.722 +
17.723 +\subsubsection*{Description}
17.724 +
17.725 +The routine \verb|glp_sdf_error| prints an error message related to the
17.726 +plain data file specified by the parameter \verb|data|. If error handing
17.727 +was not previously provided, the routine then abnormally terminates
17.728 +execution of the application program. Otherwise, it signals about the
17.729 +error by a call to the standard C function \verb|longjmp|.
17.730 +
17.731 +The character string \verb|fmt| and optional parameters following it
17.732 +have the same meaning as for the standard C function \verb|printf|.
17.733 +
17.734 +The message produced by the routine \verb|glp_sdf_error| looks like
17.735 +follows:
17.736 +
17.737 +\medskip
17.738 +
17.739 +{\it file}{\tt :}{\it line}{\tt :} {\it message text}
17.740 +
17.741 +\medskip
17.742 +
17.743 +\noindent
17.744 +where {\it file} is the filename passed to the routine
17.745 +\verb|glp_sdf_open| and {\it line} is the current line number.
17.746 +
17.747 +\newpage
17.748 +
17.749 +\subsection{glp\_sdf\_warning---print warning message}
17.750 +
17.751 +\subsubsection*{Synopsis}
17.752 +
17.753 +\begin{verbatim}
17.754 +void glp_sdf_warning(glp_data *data, const char *fmt, ...);
17.755 +\end{verbatim}
17.756 +
17.757 +\subsubsection*{Description}
17.758 +
17.759 +The routine \verb|glp_sdf_warning| prints a warning message related to
17.760 +the plain data file specified by the parameter \verb|data|.
17.761 +
17.762 +The character string \verb|fmt| and optional parameters following it
17.763 +have the same meaning as for the standard C function \verb|printf|.
17.764 +
17.765 +The message produced by the routine \verb|glp_sdf_warning| looks like
17.766 +follows:
17.767 +
17.768 +\medskip
17.769 +
17.770 +{\it file}{\tt :}{\it line}\verb|: warning:| {\it message text}
17.771 +
17.772 +\medskip
17.773 +
17.774 +\noindent
17.775 +where {\it file} is the filename passed to the routine
17.776 +\verb|glp_sdf_open| and {\it line} is the current line number.
17.777 +
17.778 +\subsection{glp\_sdf\_read\_int---read integer number}
17.779 +
17.780 +\subsubsection*{Synopsis}
17.781 +
17.782 +\begin{verbatim}
17.783 +int glp_sdf_read_int(glp_data *data);
17.784 +\end{verbatim}
17.785 +
17.786 +\subsubsection*{Description}
17.787 +
17.788 +The routine \verb|glp_sdf_read_int| skips optional white-space
17.789 +characters and then reads an integer number from the plain data file
17.790 +specified by the parameter \verb|data|. If the operation failed, the
17.791 +routine \verb|glp_sdf_read_int| calls the routine \verb|glp_sdf_error|
17.792 +(see above).
17.793 +
17.794 +\subsubsection*{Returns}
17.795 +
17.796 +The routine \verb|glp_sdf_read_int| returns the integer number read.
17.797 +
17.798 +\newpage
17.799 +
17.800 +\subsection{glp\_sdf\_read\_num---read floating-point number}
17.801 +
17.802 +\subsubsection*{Synopsis}
17.803 +
17.804 +\begin{verbatim}
17.805 +double glp_sdf_read_num(glp_data *data);
17.806 +\end{verbatim}
17.807 +
17.808 +\subsubsection*{Description}
17.809 +
17.810 +The routine \verb|glp_sdf_read_num| skips optional white-space
17.811 +characters and then reads a floating-point number from the plain data
17.812 +file specified by the parameter \verb|data|. If the operation failed,
17.813 +the routine \verb|glp_sdf_num| calls the routine \verb|glp_sdf_error|
17.814 +(see above).
17.815 +
17.816 +\subsubsection*{Returns}
17.817 +
17.818 +The routine \verb|glp_sdf_read_num| returns the floating-point number
17.819 +read.
17.820 +
17.821 +\subsection{glp\_sdf\_read\_item---read data item}
17.822 +
17.823 +\subsubsection*{Synopsis}
17.824 +
17.825 +\begin{verbatim}
17.826 +const char *glp_sdf_read_item(glp_data *data);
17.827 +\end{verbatim}
17.828 +
17.829 +\subsubsection*{Description}
17.830 +
17.831 +The routine \verb|glp_sdf_read_item| skips optional white-space
17.832 +characters and then reads a data item from the plain data file specified
17.833 +by the parameter \verb|data|. If the operation failed, the routine
17.834 +\verb|glp_sdf_read_item| calls the routine \verb|glp_sdf_error| (see
17.835 +above).
17.836 +
17.837 +{\it Data item} is a sequence of 1 to 255 arbitrary graphic characters
17.838 +delimited by white-space characters. Data items may be used to represent
17.839 +symbolic names, identifiers, etc.
17.840 +
17.841 +\subsubsection*{Returns}
17.842 +
17.843 +The routine \verb|glp_sdf_read_item| returns a pointer to the internal
17.844 +buffer, which contains the data item read in the form of a
17.845 +null-terminated character string.
17.846 +
17.847 +\newpage
17.848 +
17.849 +\subsection{glp\_sdf\_read\_text---read text until end of line}
17.850 +
17.851 +\subsubsection*{Synopsis}
17.852 +
17.853 +\begin{verbatim}
17.854 +const char *glp_sdf_read_text(glp_data *data);
17.855 +\end{verbatim}
17.856 +
17.857 +\subsubsection*{Description}
17.858 +
17.859 +The routine \verb|glp_sdf_read_text| reads a text from the plain data
17.860 +file specified by the parameter \verb|data|.
17.861 +
17.862 +Reading starts from the current position and extends until end of the
17.863 +current line. Initial and trailing white-space characters as well as
17.864 +the newline character are not included in the text.
17.865 +
17.866 +\subsubsection*{Returns}
17.867 +
17.868 +The routine \verb|glp_sdf_read_text| returns a pointer to the internal
17.869 +buffer, which contains the text read in the form of a null-terminated
17.870 +character string.
17.871 +
17.872 +\subsection{glp\_sdf\_line---determine current line number}
17.873 +
17.874 +\subsubsection*{Synopsis}
17.875 +
17.876 +\begin{verbatim}
17.877 +int glp_sdf_line(glp_data *data);
17.878 +\end{verbatim}
17.879 +
17.880 +\subsubsection*{Returns}
17.881 +
17.882 +The routine \verb|glp_sdf_line| returns the current line number for the
17.883 +plain data file specified by the parameter \verb|data|.
17.884 +
17.885 +\subsection{glp\_sdf\_close\_file---close plain data file}
17.886 +
17.887 +\subsubsection*{Synopsis}
17.888 +
17.889 +\begin{verbatim}
17.890 +void glp_sdf_close_file(glp_data *data);
17.891 +\end{verbatim}
17.892 +
17.893 +\subsubsection*{Description}
17.894 +
17.895 +The routine \verb|glp_sdf_close_file| closes the plain data file
17.896 +specified by the parameter \verb|data| and frees all the resources
17.897 +allocated to this program object.
17.898 +
17.899 +%* eof *%
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
18.2 +++ b/doc/glpk07.tex Mon Dec 06 13:09:21 2010 +0100
18.3 @@ -0,0 +1,336 @@
18.4 +%* glpk07.tex *%
18.5 +
18.6 +\chapter{Installing GLPK on Your Computer}
18.7 +\label{install}
18.8 +
18.9 +\section{Downloading the distribution tarball}
18.10 +
18.11 +The distribution tarball of the most recent version of the GLPK
18.12 +package can be found on \url{http://ftp.gnu.org/gnu/glpk/} [via http]
18.13 +and \url{ftp://ftp.gnu.org/gnu/glpk/} [via FTP]. It can also be found
18.14 +on one of the FTP mirrors; see \url{http://www.gnu.org/prep/ftp.html}.
18.15 +Please use a mirror if possible.
18.16 +
18.17 +To make sure that the GLPK distribution tarball you have downloaded is
18.18 +intact you need to download the corresponding `\verb|.sig|' file and
18.19 +run a command like this:
18.20 +
18.21 +\begin{verbatim}
18.22 + gpg --verify glpk-4.38.tar.gz.sig
18.23 +\end{verbatim}
18.24 +
18.25 +\noindent
18.26 +If that command fails because you do not have the required public key,
18.27 +run the following command to import it:
18.28 +
18.29 +\begin{verbatim}
18.30 + gpg --keyserver keys.gnupg.net --recv-keys 5981E818
18.31 +\end{verbatim}
18.32 +
18.33 +\noindent
18.34 +and then re-run the previous command.
18.35 +
18.36 +\section{Unpacking the distribution tarball}
18.37 +
18.38 +The GLPK package (like all other GNU software) is distributed in the
18.39 +form of packed archive. This is one file named \verb|glpk-X.Y.tar.gz|,
18.40 +where {\it X} is the major version number and {\it Y} is the minor
18.41 +version number.
18.42 +
18.43 +In order to prepare the distribution for installation you should:
18.44 +
18.45 +\medskip
18.46 +
18.47 +1. Copy the GLPK distribution file to a working subdirectory.
18.48 +
18.49 +\medskip
18.50 +
18.51 +2. Unpack the distribution file with the following command:
18.52 +
18.53 +\begin{verbatim}
18.54 + gzip -d glpk-X.Y.tar.gz
18.55 +\end{verbatim}
18.56 +
18.57 +\noindent
18.58 +that renames the distribution file to \verb|glpk-X.Y.tar|.
18.59 +
18.60 +\medskip
18.61 +
18.62 +3. Unarchive the distribution file with the following command:
18.63 +
18.64 +\begin{verbatim}
18.65 + tar -x < glpk-X.Y.tar
18.66 +\end{verbatim}
18.67 +
18.68 +\noindent
18.69 +that automatically creates the subdirectory \verb|glpk-X.Y| containing
18.70 +the GLPK distribution.
18.71 +
18.72 +
18.73 +\section{Configuring the package}
18.74 +
18.75 +After unpacking and unarchiving the GLPK distribution you should
18.76 +configure the package, i.e. automatically tune it for your platform.
18.77 +
18.78 +Normally, you should just \verb|cd| to the subdirectory
18.79 +\verb|glpk-X.Y| and run the configure script, e.g.
18.80 +
18.81 +\begin{verbatim}
18.82 + ./configure
18.83 +\end{verbatim}
18.84 +
18.85 +The `\verb|configure|' shell script attempts to guess correct values
18.86 +for various system-dependent variables used during compilation. It uses
18.87 +those values to create a `\verb|Makefile|' in each directory of the
18.88 +package. It also creates file `\verb|config.h|' containing
18.89 +platform-dependent definitions. Finally, it creates a shell script
18.90 +`\verb|config.status|' that you can run in the future to recreate the
18.91 +current configuration, a file `\verb|config.cache|' that saves the
18.92 +results of its tests to speed up reconfiguring, and a file
18.93 +`\verb|config.log|' containing compiler output (useful mainly for
18.94 +debugging `\verb|configure|').
18.95 +
18.96 +Running `\verb|configure|' takes about a few minutes. While it is
18.97 +running, it displays some informational messages that tell you what it
18.98 +is doing. If you don't want to see these messages, run
18.99 +`\verb|configure|' with its standard output redirected to
18.100 +`\verb|dev/null|'; for example, `\verb|./configure > /dev/null|'.
18.101 +
18.102 +By default both static and shared versions of the GLPK library will be
18.103 +compiled. Compilation of the shared librariy can be turned off by
18.104 +specifying the `\verb|--disable-shared|' option to `\verb|configure|',
18.105 +e.g.
18.106 +
18.107 +\begin{verbatim}
18.108 + ./configure --disable-shared
18.109 +\end{verbatim}
18.110 +
18.111 +\noindent
18.112 +If you encounter problems building the library try using the above
18.113 +option, because some platforms do not support shared libraries.
18.114 +
18.115 +\newpage
18.116 +
18.117 +The GLPK package has some optional features listed below. By default
18.118 +all these features are disabled. To enable a feature the corresponding
18.119 +option should be passed to the configure script.
18.120 +
18.121 +\bigskip
18.122 +
18.123 +\noindent
18.124 +\verb|--with-gmp | Enable using the GNU MP bignum library
18.125 +
18.126 +\medskip
18.127 +
18.128 +This feature allows the exact simplex solver to use the GNU MP bignum
18.129 +library. If it is disabled, the exact simplex solver uses the GLPK
18.130 +bignum module, which provides the same functionality as GNU MP, however,
18.131 +it is much less efficient.
18.132 +
18.133 +For details about the GNU MP bignum library see its web page at
18.134 +\url{http://gmplib.org/}.
18.135 +
18.136 +\bigskip
18.137 +
18.138 +\noindent
18.139 +\verb|--with-zlib |
18.140 +Enable using the zlib data compression library
18.141 +
18.142 +\medskip
18.143 +
18.144 +This feature allows GLPK API routines and the stand-alone solver to
18.145 +read and write compressed data files performing compression and
18.146 +decompression ``on the fly'' (compressed data files are recognized by
18.147 +suffix `\verb|.gz|' in the file name). It may be useful in case of
18.148 +large MPS files to save the disk space.
18.149 +
18.150 +For details about the zlib compression library see its web page at
18.151 +\url{http://www.zlib.net/}.
18.152 +
18.153 +\bigskip
18.154 +
18.155 +\noindent
18.156 +\verb|--enable-dl | The same as `\verb|--enable-dl=ltdl|'
18.157 +
18.158 +\noindent
18.159 +\verb|--enable-dl=ltdl | Enable shared library support (GNU)
18.160 +
18.161 +\noindent
18.162 +\verb|--enable-dl=dlfcn | Enable shared library support (POSIX)
18.163 +
18.164 +\medskip
18.165 +
18.166 +Currently this feature is only needed to provide dynamic linking to
18.167 +ODBC and MySQL shared libraries (see below).
18.168 +
18.169 +For details about the GNU shared library support see the manual at
18.170 +\url{http://www.gnu.org/software/libtool/manual/}.
18.171 +
18.172 +\bigskip
18.173 +
18.174 +\noindent
18.175 +\verb|--enable-odbc |
18.176 +Enable using ODBC table driver (\verb|libiodbc|)
18.177 +
18.178 +\noindent
18.179 +\verb|--enable-odbc=unix |
18.180 +Enable using ODBC table driver (\verb|libodbc|)
18.181 +
18.182 +\medskip
18.183 +
18.184 +This feature allows transmitting data between MathProg model objects
18.185 +and relational databases accessed through ODBC.
18.186 +
18.187 +For more details about this feature see the supplement ``Using Data
18.188 +Tables in the GNU MathProg Modeling Language'' (\verb|doc/tables.pdf|).
18.189 +
18.190 +\bigskip
18.191 +
18.192 +\noindent
18.193 +\verb|--enable-mysql |
18.194 +Enable using MySQL table driver (\verb|libmysql|)
18.195 +
18.196 +\medskip
18.197 +
18.198 +This feature allows transmitting data between MathProg model objects
18.199 +and MySQL relational databases.
18.200 +
18.201 +For more details about this feature see the supplement ``Using Data
18.202 +Tables in the GNU MathProg Modeling Language'' (\verb|doc/tables.pdf|).
18.203 +
18.204 +\section{Compiling the package}
18.205 +
18.206 +Normally, you can compile (build) the package by typing the command:
18.207 +
18.208 +\begin{verbatim}
18.209 + make
18.210 +\end{verbatim}
18.211 +
18.212 +\noindent
18.213 +It reads `\verb|Makefile|' generated by `\verb|configure|' and performs
18.214 +all necessary jobs.
18.215 +
18.216 +If you want, you can override the `\verb|make|' variables \verb|CFLAGS|
18.217 +and \verb|LDFLAGS| like this:
18.218 +
18.219 +\begin{verbatim}
18.220 + make CFLAGS=-O2 LDFLAGS=-s
18.221 +\end{verbatim}
18.222 +
18.223 +To compile the package in a different directory from the one containing
18.224 +the source code, you must use a version of `\verb|make|' that supports
18.225 +`\verb|VPATH|' variable, such as GNU `\verb|make|'. `\verb|cd|' to the
18.226 +directory where you want the object files and executables to go and run
18.227 +the `\verb|configure|' script. `\verb|configure|' automatically checks
18.228 +for the source code in the directory that `\verb|configure|' is in and
18.229 +in `\verb|..|'. If for some reason `\verb|configure|' is not in the
18.230 +source code directory that you are configuring, then it will report that
18.231 +it can't find the source code. In that case, run `\verb|configure|' with
18.232 +the option `\verb|--srcdir=DIR|', where \verb|DIR| is the directory that
18.233 +contains the source code.
18.234 +
18.235 +Some systems require unusual options for compilation or linking that
18.236 +the `\verb|configure|' script does not know about. You can give
18.237 +`\verb|configure|' initial values for variables by setting them in the
18.238 +environment. Using a Bourne-compatible shell, you can do that on the
18.239 +command line like this:
18.240 +
18.241 +\begin{verbatim}
18.242 + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
18.243 +\end{verbatim}
18.244 +
18.245 +\noindent
18.246 +Or on systems that have the `\verb|env|' program, you can do it like
18.247 +this:
18.248 +
18.249 +\begin{verbatim}
18.250 + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
18.251 +\end{verbatim}
18.252 +
18.253 +Here are the `\verb|make|' variables that you might want to override
18.254 +with environment variables when running `\verb|configure|'.
18.255 +
18.256 +For these variables, any value given in the environment overrides the
18.257 +value that `\verb|configure|' would choose:
18.258 +
18.259 +\medskip
18.260 +
18.261 +\noindent
18.262 +\verb|CC | C compiler program. The default is `\verb|cc|'.
18.263 +
18.264 +\medskip
18.265 +
18.266 +\noindent
18.267 +\verb|INSTALL | Program used to install files. The default value is
18.268 +`\verb|install|' if
18.269 +
18.270 +\noindent
18.271 +\verb| | you have it, otherwise `\verb|cp|'.
18.272 +
18.273 +\medskip
18.274 +
18.275 +For these variables, any value given in the environment is added to the
18.276 +value that `\verb|configure|' chooses:
18.277 +
18.278 +\medskip
18.279 +
18.280 +\noindent
18.281 +\verb|DEFS | Configuration options, in the form
18.282 +`\verb|-Dfoo -Dbar| \dots'.
18.283 +
18.284 +\medskip
18.285 +
18.286 +\noindent
18.287 +\verb|LIBS | Libraries to link with, in the form
18.288 +`\verb|-lfoo -lbar| \dots'.
18.289 +
18.290 +\section{Checking the package}
18.291 +
18.292 +To check the package, i.e. to run some tests included in the package,
18.293 +you can use the following command:
18.294 +
18.295 +\begin{verbatim}
18.296 + make check
18.297 +\end{verbatim}
18.298 +
18.299 +\section{Installing the package}
18.300 +
18.301 +Normally, to install the GLPK package you should type the following
18.302 +command:
18.303 +
18.304 +\begin{verbatim}
18.305 + make install
18.306 +\end{verbatim}
18.307 +
18.308 +\noindent
18.309 +By default, `\verb|make install|' will install the package's files in
18.310 +`\verb|usr/local/bin|', `\verb|usr/local/lib|', etc. You can specify an
18.311 +installation prefix other than `\verb|/usr/local|' by giving
18.312 +`\verb|configure|' the option `\verb|--prefix=PATH|'. Alternately, you
18.313 +can do so by consistently giving a value for the `\verb|prefix|'
18.314 +variable when you run `\verb|make|', e.g.
18.315 +
18.316 +\begin{verbatim}
18.317 + make prefix=/usr/gnu
18.318 + make prefix=/usr/gnu install
18.319 +\end{verbatim}
18.320 +
18.321 +After installing you can remove the program binaries and object files
18.322 +from the source directory by typing `\verb|make clean|'. To remove all
18.323 +files that `\verb|configure|' created (`\verb|Makefile|',
18.324 +`\verb|config.status|', etc.), just type `\verb|make distclean|'.
18.325 +
18.326 +The file `\verb|configure.ac|' is used to create `\verb|configure|' by
18.327 +a program called `\verb|autoconf|'. You only need it if you want to
18.328 +remake `\verb|configure|' using a newer version of `\verb|autoconf|'.
18.329 +
18.330 +\section{Uninstalling the package}
18.331 +
18.332 +To uninstall the GLPK package, i.e. to remove all the package's files
18.333 +from the system places, you can use the following command:
18.334 +
18.335 +\begin{verbatim}
18.336 + make uninstall
18.337 +\end{verbatim}
18.338 +
18.339 +%* eof *%
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
19.2 +++ b/doc/glpk08.tex Mon Dec 06 13:09:21 2010 +0100
19.3 @@ -0,0 +1,696 @@
19.4 +%* glpk08.tex *%
19.5 +
19.6 +\chapter{MPS Format}
19.7 +\label{champs}
19.8 +
19.9 +\section{Fixed MPS Format}
19.10 +\label{secmps}
19.11 +
19.12 +The MPS format\footnote{The MPS format was developed in 1960's by IBM
19.13 +as input format for their mathematical programming system MPS/360.
19.14 +Today the MPS format is a most widely used format understood by most
19.15 +mathematical programming packages. This appendix describes only the
19.16 +features of the MPS format, which are implemented in the GLPK package.}
19.17 +is intended for coding LP/MIP problem data. This format assumes the
19.18 +formulation of LP/MIP problem (1.1)---(1.3) (see Section \ref{seclp},
19.19 +page \pageref{seclp}).
19.20 +
19.21 +{\it MPS file} is a text file, which contains two types of
19.22 +cards\footnote{In 1960's MPS file was a deck of 80-column punched cards,
19.23 +so the author decided to keep the word ``card'', which may be understood
19.24 +as ``line of text file''.}: indicator cards and data cards.
19.25 +
19.26 +Indicator cards determine a kind of succeeding data. Each indicator card
19.27 +has one word in uppercase letters beginning in column 1.
19.28 +
19.29 +Data cards contain problem data. Each data card is divided into six
19.30 +fixed fields:
19.31 +
19.32 +\begin{center}
19.33 +\begin{tabular}{lcccccc}
19.34 +& Field 1 & Field 2 & Field 3 & Field 4 & Field 5 & Feld 6 \\
19.35 +\hline
19.36 +Columns & 2---3 & 5---12 & 15---22 & 25---36 & 40---47 & 50---61 \\
19.37 +Contents & Code & Name & Name & Number & Name & Number \\
19.38 +\end{tabular}
19.39 +\end{center}
19.40 +
19.41 +On a particular data card some fields may be optional.
19.42 +
19.43 +Names are used to identify rows, columns, and some vectors (see below).
19.44 +
19.45 +Aligning the indicator code in the field 1 to the left margin is
19.46 +optional.
19.47 +
19.48 +All names specified in the fields 2, 3, and 5 should contain from 1 up
19.49 +to 8 arbitrary characters (except control characters). If a name is
19.50 +placed in the field 3 or 5, its first character should not be the dollar
19.51 +sign `\verb|$|'. If a name contains spaces, the spaces are ignored.
19.52 +
19.53 +All numerical values in the fields 4 and 6 should be coded in the form
19.54 +$sxx$\verb|E|$syy$, where $s$ is the plus `\verb|+|' or the minus
19.55 +`\verb|-|' sign, $xx$ is a real number with optional decimal point,
19.56 +$yy$ is an integer decimal exponent. Any number should contain up to 12
19.57 +characters. If the sign $s$ is omitted, the plus sign is assumed. The
19.58 +exponent part is optional. If a number contains spaces, the spaces are
19.59 +ignored.
19.60 +
19.61 +If a card has the asterisk `\verb|*|' in the column 1, this card is
19.62 +considered as a comment and ignored. Besides, if the first character in
19.63 +the field 3 or 5 is the dollar sign `\verb|$|', all characters from the
19.64 +dollar sign to the end of card are considered as a comment and ignored.
19.65 +
19.66 +MPS file should contain cards in the following order:
19.67 +
19.68 +$\bullet$ NAME indicator card;
19.69 +
19.70 +$\bullet$ ROWS indicator card;
19.71 +
19.72 +$\bullet$ data cards specifying rows (constraints);
19.73 +
19.74 +$\bullet$ COLUMNS indicator card;
19.75 +
19.76 +$\bullet$ data cards specifying columns (structural variables) and
19.77 +constraint coefficients;
19.78 +
19.79 +$\bullet$ RHS indicator card;
19.80 +
19.81 +$\bullet$ data cards specifying right-hand sides of constraints;
19.82 +
19.83 +$\bullet$ RANGES indicator card;
19.84 +
19.85 +$\bullet$ data cards specifying ranges for double-bounded constraints;
19.86 +
19.87 +$\bullet$ BOUNDS indicator card;
19.88 +
19.89 +$\bullet$ data cards specifying types and bounds of structural
19.90 +variables;
19.91 +
19.92 +$\bullet$ ENDATA indicator card.
19.93 +
19.94 +{\it Section} is a group of cards consisting of an indicator card and
19.95 +data cards succeeding this indicator card. For example, the ROWS section
19.96 +consists of the ROWS indicator card and data cards specifying rows.
19.97 +
19.98 +The sections RHS, RANGES, and BOUNDS are optional and may be omitted.
19.99 +
19.100 +\section{Free MPS Format}
19.101 +
19.102 +{\it Free MPS format} is an improved version of the standard (fixed)
19.103 +MPS format described above.\footnote{This format was developed in the
19.104 +beginning of 1990's by IBM as an alternative to the standard fixed MPS
19.105 +format for Optimization Subroutine Library (OSL).} Note that all
19.106 +changes in free MPS format concern only the coding of data while the
19.107 +structure of data is the same for both fixed and free versions of the
19.108 +MPS format.
19.109 +
19.110 +In free MPS format indicator and data records\footnote{{\it Record} in
19.111 +free MPS format has the same meaning as {\it card} in fixed MPS format.}
19.112 +may have arbitrary length not limited to 80 characters. Fields of data
19.113 +records have no predefined positions, i.e. the fields may begin in any
19.114 +position, except position 1, which must be blank, and must be separated
19.115 +from each other by one or more blanks. However, the fields must appear
19.116 +in the same order as in fixed MPS format.
19.117 +
19.118 +Symbolic names in fields 2, 3, and 5 may be longer than 8
19.119 +characters\footnote{GLPK allows symbolic names having up to 255
19.120 +characters.}
19.121 +and must not contain embedded blanks.
19.122 +
19.123 +Numeric values in fields 4 and 6 are limited to 12 characters and must
19.124 +not contain embedded blanks.
19.125 +
19.126 +Only six fields on each data record are used. Any other fields are
19.127 +ignored.
19.128 +
19.129 +If the first character of any field (not necessarily fields 3 and 5)
19.130 +is the dollar sign (\$), all characters from the dollar sign to the end
19.131 +of record are considered as a comment and ignored.
19.132 +
19.133 +\section{NAME indicator card}
19.134 +
19.135 +The NAME indicator card should be the first card in the MPS file (except
19.136 +optional comment cards, which may precede the NAME card). This card
19.137 +should contain the word \verb|NAME| in the columns 1---4 and the problem
19.138 +name in the field 3. The problem name is optional and may be omitted.
19.139 +
19.140 +\section{ROWS section}
19.141 +\label{secrows}
19.142 +
19.143 +The ROWS section should start with the indicator card, which contains
19.144 +the word \verb|ROWS| in the columns 1---4.
19.145 +
19.146 +Each data card in the ROWS section specifies one row (constraint) of the
19.147 +problem. All these data cards have the following format.
19.148 +
19.149 +`\verb|N|' in the field 1 means that the row is free (unbounded):
19.150 +$$-\infty < x_i = a_{i1}x_{m+1} + a_{i2}x_{m+2} + \dots + a_{in}x_{m+n}
19.151 +< +\infty;$$
19.152 +
19.153 +`\verb|L|' in the field 1 means that the row is of ``less than or equal
19.154 +to'' type:
19.155 +$$-\infty < x_i = a_{i1}x_{m+1} + a_{i2}x_{m+2} + \dots + a_{in}x_{m+n}
19.156 +\leq b_i;$$
19.157 +
19.158 +`\verb|G|' in the field 1 means that the row is of ``greater than or
19.159 +equal to'' type:
19.160 +$$b_i \leq x_i = a_{i1}x_{m+1} + a_{i2}x_{m+2} + \dots + a_{in}x_{m+n}
19.161 +< +\infty;$$
19.162 +
19.163 +`\verb|E|' in the field 1 means that the row is of ``equal to'' type:
19.164 +$$x_i = a_{i1}x_{m+1} + a_{i2}x_{m+2} + \dots + a_{in}x_{m+n} \leq
19.165 +b_i,$$
19.166 +where $b_i$ is a right-hand side. Note that each constraint has a
19.167 +corresponding implictly defined auxiliary variable ($x_i$ above), whose
19.168 +value is a value of the corresponding linear form, therefore row bounds
19.169 +can be considered as bounds of such auxiliary variable.
19.170 +
19.171 +The filed 2 specifies a row name (which is considered as the name of
19.172 +the corresponding auxiliary variable).
19.173 +
19.174 +The fields 3, 4, 5, and 6 are not used and should be empty.
19.175 +
19.176 +Numerical values of all non-zero right-hand sides $b_i$ should be
19.177 +specified in the RHS section (see below). All double-bounded (ranged)
19.178 +constraints should be specified in the RANGES section (see below).
19.179 +
19.180 +\section{COLUMNS section}
19.181 +
19.182 +The COLUMNS section should start with the indicator card, which contains
19.183 +the word \verb|COLUMNS| in the columns 1---7.
19.184 +
19.185 +Each data card in the COLUMNS section specifies one or two constraint
19.186 +coefficients $a_{ij}$ and also introduces names of columns, i.e. names
19.187 +of structural variables. All these data cards have the following format.
19.188 +
19.189 +The field 1 is not used and should be empty.
19.190 +
19.191 +The field 2 specifies a column name. If this field is empty, the column
19.192 +name from the immediately preceeding data card is assumed.
19.193 +
19.194 +The field 3 specifies a row name defined in the ROWS section.
19.195 +
19.196 +The field 4 specifies a numerical value of the constraint coefficient
19.197 +$a_{ij}$, which is placed in the corresponding row and column.
19.198 +
19.199 +The fields 5 and 6 are optional. If they are used, they should contain
19.200 +a second pair ``row name---constraint coefficient'' for the same column.
19.201 +
19.202 +Elements of the constraint matrix (i.e. constraint coefficients) should
19.203 +be enumerated in the column wise manner: all elements for the current
19.204 +column should be specified before elements for the next column. However,
19.205 +the order of rows in the COLUMNS section may differ from the order of
19.206 +rows in the ROWS section.
19.207 +
19.208 +Constraint coefficients not specified in the COLUMNS section are
19.209 +considered as zeros. Therefore zero coefficients may be omitted,
19.210 +although it is allowed to explicitly specify them.
19.211 +
19.212 +\section{RHS section}
19.213 +
19.214 +The RHS section should start with the indicator card, which contains the
19.215 +word \verb|RHS| in the columns 1---3.
19.216 +
19.217 +Each data card in the RHS section specifies one or two right-hand sides
19.218 +$b_i$ (see Section \ref{secrows}, page \pageref{secrows}). All these
19.219 +data cards have the following format.
19.220 +
19.221 +The field 1 is not used and should be empty.
19.222 +
19.223 +The field 2 specifies a name of the right-hand side (RHS)
19.224 +vector\footnote{This feature allows the user to specify several RHS
19.225 +vectors in the same MPS file. However, before solving the problem a
19.226 +particular RHS vector should be chosen.}. If this field is empty, the
19.227 +RHS vector name from the immediately preceeding data card is assumed.
19.228 +
19.229 +The field 3 specifies a row name defined in the ROWS section.
19.230 +
19.231 +The field 4 specifies a right-hand side $b_i$ for the row, whose name is
19.232 +specified in the field 3. Depending on the row type $b_i$ is a lower
19.233 +bound (for the row of \verb|G| type), an upper bound (for the row of
19.234 +\verb|L| type), or a fixed value (for the row of \verb|E|
19.235 +type).\footnote{If the row is of {\tt N} type, $b_i$ is considered as
19.236 +a constant term of the corresponding linear form. Should note, however,
19.237 +this convention is non-standard.}
19.238 +
19.239 +The fields 5 and 6 are optional. If they are used, they should contain
19.240 +a second pair ``row name---right-hand side'' for the same RHS vector.
19.241 +
19.242 +All right-hand sides for the current RHS vector should be specified
19.243 +before right-hand sides for the next RHS vector. However, the order of
19.244 +rows in the RHS section may differ from the order of rows in the ROWS
19.245 +section.
19.246 +
19.247 +Right-hand sides not specified in the RHS section are considered as
19.248 +zeros. Therefore zero right-hand sides may be omitted, although it is
19.249 +allowed to explicitly specify them.
19.250 +
19.251 +\section{RANGES section}
19.252 +
19.253 +The RANGES section should start with the indicator card, which contains
19.254 +the word \verb|RANGES| in the columns 1---6.
19.255 +
19.256 +Each data card in the RANGES section specifies one or two ranges for
19.257 +double-side constraints, i.e. for constraints that are of the types
19.258 +\verb|L| and \verb|G| at the same time:
19.259 +$$l_i \leq x_i = a_{i1}x_{m+1} + a_{i2}x_{m+2} + \dots + a_{in}x_{m+n}
19.260 +\leq u_i,$$
19.261 +where $l_i$ is a lower bound, $u_i$ is an upper bound. All these data
19.262 +cards have the following format.
19.263 +
19.264 +The field 1 is not used and should be empty.
19.265 +
19.266 +The field 2 specifies a name of the range vector\footnote{This feature
19.267 +allows the user to specify several range vectors in the same MPS file.
19.268 +However, before solving the problem a particular range vector should be
19.269 +chosen.}. If this field is empty, the range vector name from the
19.270 +immediately preceeding data card is assumed.
19.271 +
19.272 +The field 3 specifies a row name defined in the ROWS section.
19.273 +
19.274 +The field 4 specifies a range value $r_i$ (see the table below) for the
19.275 +row, whose name is specified in the field 3.
19.276 +
19.277 +The fields 5 and 6 are optional. If they are used, they should contain
19.278 +a second pair ``row name---range value'' for the same range vector.
19.279 +
19.280 +All range values for the current range vector should be specified before
19.281 +range values for the next range vector. However, the order of rows in
19.282 +the RANGES section may differ from the order of rows in the ROWS
19.283 +section.
19.284 +
19.285 +For each double-side constraint specified in the RANGES section its
19.286 +lower and upper bounds are determined as follows:
19.287 +
19.288 +\begin{center}
19.289 +\begin{tabular}{cccc}
19.290 +Row type & Sign of $r_i$ & Lower bound & Upper bound \\
19.291 +\hline
19.292 +{\tt G} & $+$ or $-$ & $b_i$ & $b_i + |r_i|$ \\
19.293 +{\tt L} & $+$ or $-$ & $b_i - |r_i|$ & $b_i$ \\
19.294 +{\tt E} & $+$ & $b_i$ & $b_i + |r_i|$ \\
19.295 +{\tt E} & $-$ & $b_i - |r_i|$ & $b_i$ \\
19.296 +\end{tabular}
19.297 +\end{center}
19.298 +
19.299 +\noindent
19.300 +where $b_i$ is a right-hand side specified in the RHS section (if $b_i$
19.301 +is not specified, it is considered as zero), $r_i$ is a range value
19.302 +specified in the RANGES section.
19.303 +
19.304 +\section{BOUNDS section}
19.305 +\label{secbounds}
19.306 +
19.307 +The BOUNDS section should start with the indicator card, which contains
19.308 +the word \verb|BOUNDS| in the columns 1---6.
19.309 +
19.310 +Each data card in the BOUNDS section specifies one (lower or upper)
19.311 +bound for one structural variable (column). All these data cards have
19.312 +the following format.
19.313 +
19.314 +The indicator in the field 1 specifies the bound type:
19.315 +
19.316 +\begin{tabular}{@{}ll}
19.317 +\verb|LO| & lower bound; \\
19.318 +\verb|UP| & upper bound; \\
19.319 +\verb|FX| & fixed variable (lower and upper bounds are equal); \\
19.320 +\verb|FR| & free variable (no bounds); \\
19.321 +\verb|MI| & no lower bound (lower bound is ``minus infinity''); \\
19.322 +\verb|PL| & no upper bound (upper bound is ``plus infinity''); \\
19.323 +\end{tabular}
19.324 +
19.325 +The field 2 specifies a name of the bound vector\footnote{This feature
19.326 +allows the user to specify several bound vectors in the same MPS file.
19.327 +However, before solving the problem a particular bound vector should be
19.328 +chosen.}. If this field is empty, the bound vector name from the
19.329 +immediately preceeding data card is assumed.
19.330 +
19.331 +The field 3 specifies a column name defined in the COLUMNS section.
19.332 +
19.333 +The field 4 specifies a bound value. If the bound type in the field 1
19.334 +differs from \verb|LO|, \verb|UP|, and \verb|FX|, the value in the field
19.335 +4 is ignored and may be omitted.
19.336 +
19.337 +The fields 5 and 6 are not used and should be empty.
19.338 +
19.339 +All bound values for the current bound vector should be specified before
19.340 +bound values for the next bound vector. However, the order of columns in
19.341 +the BOUNDS section may differ from the order of columns in the COLUMNS
19.342 +section. Specification of a lower bound should precede specification of
19.343 +an upper bound for the same column (if both the lower and upper bounds
19.344 +are explicitly specified).
19.345 +
19.346 +By default, all columns (structural variables) are non-negative, i.e.
19.347 +have zero lower bound and no upper bound. Lower ($l_j$) and upper
19.348 +($u_j$) bounds of some column (structural variable $x_j$) are set in the
19.349 +following way, where $s_j$ is a corresponding bound value explicitly
19.350 +specified in the BOUNDS section:
19.351 +
19.352 +\begin{tabular}{@{}ll}
19.353 +\verb|LO| & sets $l_j$ to $s_j$; \\
19.354 +\verb|UP| & sets $u_j$ to $s_j$; \\
19.355 +\verb|FX| & sets both $l_j$ and $u_j$ to $s_j$; \\
19.356 +\verb|FR| & sets $l_j$ to $-\infty$ and $u_j$ to $+\infty$; \\
19.357 +\verb|MI| & sets $l_j$ to $-\infty$; \\
19.358 +\verb|PL| & sets $u_j$ to $+\infty$. \\
19.359 +\end{tabular}
19.360 +
19.361 +\section{ENDATA indicator card}
19.362 +
19.363 +The ENDATA indicator card should be the last card of MPS file (except
19.364 +optional comment cards, which may follow the ENDATA card). This card
19.365 +should contain the word \verb|ENDATA| in the columns 1---6.
19.366 +
19.367 +\section{Specifying objective function}
19.368 +
19.369 +It is impossible to explicitly specify the objective function and
19.370 +optimization direction in the MPS file. However, the following implicit
19.371 +rule is used by default: the first row of \verb|N| type is considered
19.372 +as a row of the objective function (i.e. the objective function is the
19.373 +corresponding auxiliary variable), which should be {\it minimized}.
19.374 +
19.375 +GLPK also allows specifying a constant term of the objective function
19.376 +as a right-hand side of the corresponding row in the RHS section.
19.377 +
19.378 +\section{Example of MPS file}
19.379 +\label{secmpsex}
19.380 +
19.381 +In order to illustrate what the MPS format is, consider the following
19.382 +example of LP problem:
19.383 +
19.384 +\medskip
19.385 +\noindent minimize
19.386 +$$
19.387 +value = .03\ bin_1 + .08\ bin_2 + .17\ bin_3 + .12\ bin_4 + .15\ bin_5
19.388 ++ .21\ al + .38\ si
19.389 +$$
19.390 +
19.391 +\noindent subject to linear constraints
19.392 +$$
19.393 +\begin{array}{@{}l@{\:}l@{}}
19.394 +yield &= \ \ \ \ \;bin_1 + \ \ \ \ \;bin_2 + \ \ \ \ \;bin_3 +
19.395 + \ \ \ \ \;bin_4 + \ \ \ \ \;bin_5 + \ \ \ \ \;al +
19.396 + \ \ \ \ \;si \\
19.397 +FE &= .15\ bin_1 + .04\ bin_2 + .02\ bin_3 + .04\ bin_4 + .02\ bin_5
19.398 + + .01\ al + .03\ si \\
19.399 +CU &= .03\ bin_1 + .05\ bin_2 + .08\ bin_3 + .02\ bin_4 + .06\ bin_5
19.400 + + .01\ al \\
19.401 +MN &= .02\ bin_1 + .04\ bin_2 + .01\ bin_3 + .02\ bin_4 + .02\ bin_5
19.402 + \\
19.403 +MG &= .02\ bin_1 + .03\ bin_2
19.404 +\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ + .01\ bin_5 \\
19.405 +AL &= .70\ bin_1 + .75\ bin_2 + .80\ bin_3 + .75\ bin_4 + .80\ bin_5
19.406 + + .97\ al \\
19.407 +SI &= .02\ bin_1 + .06\ bin_2 + .08\ bin_3 + .12\ bin_4 + .02\ bin_5
19.408 + + .01\ al + .97\ si \\
19.409 +\end{array}
19.410 +$$
19.411 +and bounds of (auxiliary and structural) variables
19.412 +$$
19.413 +\begin{array}{r@{\ }l@{\ }l@{\ }l@{\ }rcr@{\ }l@{\ }l@{\ }l@{\ }r}
19.414 +&&yield&=&2000&&0&\leq&bin_1&\leq&200\\
19.415 +-\infty&<&FE&\leq&60&&0&\leq&bin_2&\leq&2500\\
19.416 +-\infty&<&CU&\leq&100&&400&\leq&bin_3&\leq&800\\
19.417 +-\infty&<&MN&\leq&40&&100&\leq&bin_4&\leq&700\\
19.418 +-\infty&<&MG&\leq&30&&0&\leq&bin_5&\leq&1500\\
19.419 +1500&\leq&AL&<&+\infty&&0&\leq&al&<&+\infty\\
19.420 +250&\leq&SI&\leq&300&&0&\leq&si&<&+\infty\\
19.421 +\end{array}
19.422 +$$
19.423 +
19.424 +A complete MPS file which specifies data for this example is shown
19.425 +below (the first two comment lines show card positions).
19.426 +
19.427 +\begin{verbatim}
19.428 +*000000001111111111222222222233333333334444444444555555555566
19.429 +*234567890123456789012345678901234567890123456789012345678901
19.430 +NAME PLAN
19.431 +ROWS
19.432 + N VALUE
19.433 + E YIELD
19.434 + L FE
19.435 + L CU
19.436 + L MN
19.437 + L MG
19.438 + G AL
19.439 + L SI
19.440 +COLUMNS
19.441 + BIN1 VALUE .03000 YIELD 1.00000
19.442 + FE .15000 CU .03000
19.443 + MN .02000 MG .02000
19.444 + AL .70000 SI .02000
19.445 + BIN2 VALUE .08000 YIELD 1.00000
19.446 + FE .04000 CU .05000
19.447 + MN .04000 MG .03000
19.448 + AL .75000 SI .06000
19.449 + BIN3 VALUE .17000 YIELD 1.00000
19.450 + FE .02000 CU .08000
19.451 + MN .01000 AL .80000
19.452 + SI .08000
19.453 + BIN4 VALUE .12000 YIELD 1.00000
19.454 + FE .04000 CU .02000
19.455 + MN .02000 AL .75000
19.456 + SI .12000
19.457 + BIN5 VALUE .15000 YIELD 1.00000
19.458 + FE .02000 CU .06000
19.459 + MN .02000 MG .01000
19.460 + AL .80000 SI .02000
19.461 + ALUM VALUE .21000 YIELD 1.00000
19.462 + FE .01000 CU .01000
19.463 + AL .97000 SI .01000
19.464 + SILICON VALUE .38000 YIELD 1.00000
19.465 + FE .03000 SI .97000
19.466 +RHS
19.467 + RHS1 YIELD 2000.00000 FE 60.00000
19.468 + CU 100.00000 MN 40.00000
19.469 + SI 300.00000
19.470 + MG 30.00000 AL 1500.00000
19.471 +RANGES
19.472 + RNG1 SI 50.00000
19.473 +BOUNDS
19.474 + UP BND1 BIN1 200.00000
19.475 + UP BIN2 2500.00000
19.476 + LO BIN3 400.00000
19.477 + UP BIN3 800.00000
19.478 + LO BIN4 100.00000
19.479 + UP BIN4 700.00000
19.480 + UP BIN5 1500.00000
19.481 +ENDATA
19.482 +\end{verbatim}
19.483 +
19.484 +\section{MIP features}
19.485 +
19.486 +The MPS format provides two ways for introducing integer variables into
19.487 +the problem.
19.488 +
19.489 +The first way is most general and based on using special marker cards
19.490 +INTORG and INTEND. These marker cards are placed in the COLUMNS section.
19.491 +The INTORG card indicates the start of a group of integer variables
19.492 +(columns), and the card INTEND indicates the end of the group. The MPS
19.493 +file may contain arbitrary number of the marker cards.
19.494 +
19.495 +The marker cards have the same format as the data cards (see Section
19.496 +\ref{secmps}, page \pageref{secmps}).
19.497 +
19.498 +The fields 1, 2, and 6 are not used and should be empty.
19.499 +
19.500 +The field 2 should contain a marker name. This name may be arbitrary.
19.501 +
19.502 +The field 3 should contain the word \verb|'MARKER'| (including
19.503 +apostrophes).
19.504 +
19.505 +The field 5 should contain either the word \verb|'INTORG'| (including
19.506 +apostrophes) for the marker card, which begins a group of integer
19.507 +columns, or the word \verb|'INTEND'| (including apostrophes) for the
19.508 +marker card, which ends the group.
19.509 +
19.510 +The second way is less general but more convenient in some cases. It
19.511 +allows the user declaring integer columns using three additional types
19.512 +of bounds, which are specified in the field 1 of data cards in the
19.513 +BOUNDS section (see Section \ref{secbounds}, page \pageref{secbounds}):
19.514 +
19.515 +\begin{tabular}{@{}lp{112.3mm}@{}}
19.516 +\verb|LI| & lower integer. This bound type specifies that the
19.517 +corresponding column (structural variable), whose name is specified in
19.518 +field 3, is of integer kind. In this case an lower bound of the
19.519 +column should be specified in field 4 (like in the case of \verb|LO|
19.520 +bound type). \\
19.521 +\verb|UI| & upper integer. This bound type specifies that the
19.522 +corresponding column (structural variable), whose name is specified in
19.523 +field 3, is of integer kind. In this case an upper bound of the
19.524 +column should be specified in field 4 (like in the case of \verb|UP|
19.525 +bound type). \\
19.526 +\end{tabular}
19.527 +
19.528 +\pagebreak
19.529 +
19.530 +\begin{tabular}{@{}lp{112.3mm}@{}}
19.531 +\verb|BV| & binary variable. This bound type specifies that the
19.532 +corresponding column (structural variable), whose name is specified in
19.533 +the field 3, is of integer kind, its lower bound is zero, and its upper
19.534 +bound is one (thus, such variable being of integer kind can have only
19.535 +two values zero and one). In this case a numeric value specified in the
19.536 +field 4 is ignored and may be omitted.\\
19.537 +\end{tabular}
19.538 +
19.539 +Consider the following example of MIP problem:
19.540 +
19.541 +\medskip
19.542 +
19.543 +\noindent
19.544 +\hspace{1in} minimize
19.545 +$$Z = 3 x_1 + 7 x_2 - x_3 + x4$$
19.546 +\hspace{1in} subject to linear constraints
19.547 +$$
19.548 +\begin{array}{c}
19.549 +\nonumber r_1 = 2 x_1 - \ \ x_2 + \ \ x_3 - \ \;x_4 \\
19.550 +\nonumber r_2 = \ \;x_1 - \ \;x_2 - 6 x_3 + 4 x_4 \\
19.551 +\nonumber r_3 = 5 x_1 + 3 x_2 \ \ \ \ \ \ \ \ \ + \ \ x_4 \\
19.552 +\end{array}
19.553 +$$
19.554 +\hspace{1in} and bound of variables
19.555 +$$
19.556 +\begin{array}{cccl}
19.557 +\nonumber 1 \leq r_1 < +\infty && 0 \leq x_1 \leq 4 &{\rm(continuous)}\\
19.558 +\nonumber 8 \leq r_2 < +\infty && 2 \leq x_2 \leq 5 &{\rm(integer)} \\
19.559 +\nonumber 5 \leq r_3 < +\infty && 0 \leq x_3 \leq 1 &{\rm(integer)} \\
19.560 +\nonumber && 3 \leq x_4 \leq 8 &{\rm(continuous)}\\
19.561 +\end{array}
19.562 +$$
19.563 +
19.564 +The corresponding MPS file may look like the following:
19.565 +
19.566 +\begin{verbatim}
19.567 +NAME SAMP1
19.568 +ROWS
19.569 + N Z
19.570 + G R1
19.571 + G R2
19.572 + G R3
19.573 +COLUMNS
19.574 + X1 R1 2.0 R2 1.0
19.575 + X1 R3 5.0 Z 3.0
19.576 + MARK0001 'MARKER' 'INTORG'
19.577 + X2 R1 -1.0 R2 -1.0
19.578 + X2 R3 3.0 Z 7.0
19.579 + X3 R1 1.0 R2 -6.0
19.580 + X3 Z -1.0
19.581 + MARK0002 'MARKER' 'INTEND'
19.582 + X4 R1 -1.0 R2 4.0
19.583 + X4 R3 1.0 Z 1.0
19.584 +RHS
19.585 + RHS1 R1 1.0
19.586 + RHS1 R2 8.0
19.587 + RHS1 R3 5.0
19.588 +BOUNDS
19.589 + UP BND1 X1 4.0
19.590 + LO BND1 X2 2.0
19.591 + UP BND1 X2 5.0
19.592 + UP BND1 X3 1.0
19.593 + LO BND1 X4 3.0
19.594 + UP BND1 X4 8.0
19.595 +ENDATA
19.596 +\end{verbatim}
19.597 +
19.598 +The same example may be coded without INTORG/INTEND markers using the
19.599 +bound type UI for the variable $x_2$ and the bound type BV for the
19.600 +variable $x_3$:
19.601 +
19.602 +\begin{verbatim}
19.603 +NAME SAMP2
19.604 +ROWS
19.605 + N Z
19.606 + G R1
19.607 + G R2
19.608 + G R3
19.609 +COLUMNS
19.610 + X1 R1 2.0 R2 1.0
19.611 + X1 R3 5.0 Z 3.0
19.612 + X2 R1 -1.0 R2 -1.0
19.613 + X2 R3 3.0 Z 7.0
19.614 + X3 R1 1.0 R2 -6.0
19.615 + X3 Z -1.0
19.616 + X4 R1 -1.0 R2 4.0
19.617 + X4 R3 1.0 Z 1.0
19.618 +RHS
19.619 + RHS1 R1 1.0
19.620 + RHS1 R2 8.0
19.621 + RHS1 R3 5.0
19.622 +BOUNDS
19.623 + UP BND1 X1 4.0
19.624 + LO BND1 X2 2.0
19.625 + UI BND1 X2 5.0
19.626 + BV BND1 X3
19.627 + LO BND1 X4 3.0
19.628 + UP BND1 X4 8.0
19.629 +ENDATA
19.630 +\end{verbatim}
19.631 +
19.632 +%\section{Specifying predefined basis}
19.633 +%\label{secbas}
19.634 +%
19.635 +%The MPS format can also be used to specify some predefined basis for an
19.636 +%LP problem, i.e. to specify which rows and columns are basic and which
19.637 +%are non-basic.
19.638 +%
19.639 +%The order of a basis file in the MPS format is:
19.640 +%
19.641 +%$\bullet$ NAME indicator card;
19.642 +%
19.643 +%$\bullet$ data cards (can appear in arbitrary order);
19.644 +%
19.645 +%$\bullet$ ENDATA indicator card.
19.646 +%
19.647 +%Each data card specifies either a pair "basic column---non-basic row"
19.648 +%or a non-basic column. All the data cards have the following format.
19.649 +%
19.650 +%`\verb|XL|' in the field 1 means that a column, whose name is given in
19.651 +%the field 2, is basic, and a row, whose name is given in the field 3,
19.652 +%is non-basic and placed on its lower bound.
19.653 +%
19.654 +%`\verb|XU|' in the field 1 means that a column, whose name is given in
19.655 +%the field 2, is basic, and a row, whose name is given in the field 3,
19.656 +%is non-basic and placed on its upper bound.
19.657 +%
19.658 +%`\verb|LL|' in the field 1 means that a column, whose name is given in
19.659 +%the field 3, is non-basic and placed on its lower bound.
19.660 +%
19.661 +%`\verb|UL|' in the field 1 means that a column, whose name is given in
19.662 +%the field 3, is non-basic and placed on its upper bound.
19.663 +%
19.664 +%The field 2 contains a column name.
19.665 +%
19.666 +%If the indicator given in the field 1 is `\verb|XL|' or `\verb|XU|',
19.667 +%the field 3 contains a row name. Otherwise, if the indicator is
19.668 +%`\verb|LL|' or `\verb|UL|', the field 3 is not used and should be
19.669 +%empty.
19.670 +%
19.671 +%The field 4, 5, and 6 are not used and should be empty.
19.672 +%
19.673 +%A basis file in the MPS format acts like a patch: it doesn't specify
19.674 +%a basis completely, instead that it is just shows in what a given basis
19.675 +%differs from the "standard" basis, where all rows (auxiliary variables)
19.676 +%are assumed to be basic and all columns (structural variables) are
19.677 +%assumed to be non-basic.
19.678 +%
19.679 +%As an example here is a basis file that specifies an optimal basis
19.680 +%for the example LP problem given in Section \ref{secmpsex},
19.681 +%Page \pageref{secmpsex}:
19.682 +%
19.683 +%\pagebreak
19.684 +%
19.685 +%\begin{verbatim}
19.686 +%*000000001111111111222222222233333333334444444444555555555566
19.687 +%*234567890123456789012345678901234567890123456789012345678901
19.688 +%NAME PLAN
19.689 +% XL BIN2 YIELD
19.690 +% XL BIN3 FE
19.691 +% XL BIN4 MN
19.692 +% XL ALUM AL
19.693 +% XL SILICON SI
19.694 +% LL BIN1
19.695 +% LL BIN5
19.696 +%ENDATA
19.697 +%\end{verbatim}
19.698 +
19.699 +%* eof *%
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
20.2 +++ b/doc/glpk09.tex Mon Dec 06 13:09:21 2010 +0100
20.3 @@ -0,0 +1,413 @@
20.4 +%* glpk09.tex *%
20.5 +
20.6 +\chapter{CPLEX LP Format}
20.7 +\label{chacplex}
20.8 +
20.9 +\section{Prelude}
20.10 +
20.11 +The CPLEX LP format\footnote{The CPLEX LP format was developed in
20.12 +the end of 1980's by CPLEX Optimization, Inc. as an input format for
20.13 +the CPLEX linear programming system. Although the CPLEX LP format is
20.14 +not as widely used as the MPS format, being row-oriented it is more
20.15 +convenient for coding mathematical programming models by human. This
20.16 +appendix describes only the features of the CPLEX LP format which are
20.17 +implemented in the GLPK package.} is intended for coding LP/MIP problem
20.18 +data. It is a row-oriented format that assumes the formulation of LP/MIP
20.19 +problem (1.1)---(1.3) (see Section \ref{seclp}, page \pageref{seclp}).
20.20 +
20.21 +CPLEX LP file is a plain text file written in CPLEX LP format. Each text
20.22 +line of this file may contain up to 255 characters\footnote{GLPK allows
20.23 +text lines of arbitrary length.}. Blank lines are ignored. If a line
20.24 +contains the backslash character ($\backslash$), this character and
20.25 +everything that follows it until the end of line are considered as a
20.26 +comment and also ignored.
20.27 +
20.28 +An LP file is coded by the user using the following elements:
20.29 +
20.30 +$\bullet$ keywords;
20.31 +
20.32 +$\bullet$ symbolic names;
20.33 +
20.34 +$\bullet$ numeric constants;
20.35 +
20.36 +$\bullet$ delimiters;
20.37 +
20.38 +$\bullet$ blanks.
20.39 +
20.40 +\newpage
20.41 +
20.42 +{\it Keywords} which may be used in the LP file are the following:
20.43 +
20.44 +\begin{verbatim}
20.45 + minimize minimum min
20.46 + maximize maximum max
20.47 + subject to such that s.t. st. st
20.48 + bounds bound
20.49 + general generals gen
20.50 + integer integers int
20.51 + binary binaries bin
20.52 + infinity inf
20.53 + free
20.54 + end
20.55 +\end{verbatim}
20.56 +
20.57 +\noindent
20.58 +All the keywords are case insensitive. Keywords given above on the same
20.59 +line are equivalent. Any keyword (except \verb|infinity|, \verb|inf|,
20.60 +and \verb|free|) being used in the LP file must start at the beginning
20.61 +of a text line.
20.62 +
20.63 +{\it Symbolic names} are used to identify the objective function,
20.64 +constraints (rows), and variables (columns). All symbolic names are case
20.65 +sensitive and may contain up to 16 alphanumeric characters\footnote{GLPK
20.66 +allows symbolic names having up to 255 characters.} (\verb|a|, \dots,
20.67 +\verb|z|, \verb|A|, \dots, \verb|Z|, \verb|0|, \dots, \verb|9|) as well
20.68 +as the following characters:
20.69 +
20.70 +\begin{verbatim}
20.71 +! " # $ % & ( ) / , . ; ? @ _ ` ' { } | ~
20.72 +\end{verbatim}
20.73 +
20.74 +\noindent
20.75 +with exception that no symbolic name can begin with a digit or a period.
20.76 +
20.77 +{\it Numeric constants} are used to denote constraint and objective
20.78 +coefficients, right-hand sides of constraints, and bounds of variables.
20.79 +They are coded in the standard form $xx$\verb|E|$syy$, where $xx$ is
20.80 +a real number with optional decimal point, $s$ is a sign (\verb|+| or
20.81 +\verb|-|), $yy$ is an integer decimal exponent. Numeric constants may
20.82 +contain arbitrary number of characters. The exponent part is optional.
20.83 +The letter `\verb|E|' can be coded as `\verb|e|'. If the sign $s$ is
20.84 +omitted, plus is assumed.
20.85 +
20.86 +{\it Delimiters} that may be used in the LP file are the following:
20.87 +
20.88 +\begin{verbatim}
20.89 + :
20.90 + +
20.91 + -
20.92 + < <= =<
20.93 + > >= =>
20.94 + =
20.95 +\end{verbatim}
20.96 +
20.97 +\noindent
20.98 +Delimiters given above on the same line are equivalent. The meaning of
20.99 +the delimiters will be explained below.
20.100 +
20.101 +{\it Blanks} are non-significant characters. They may be used freely to
20.102 +improve readability of the LP file. Besides, blanks should be used to
20.103 +separate elements from each other if there is no other way to do that
20.104 +(for example, to separate a keyword from a following symbolic name).
20.105 +
20.106 +The order of an LP file is:
20.107 +
20.108 +$\bullet$ objective function definition;
20.109 +
20.110 +$\bullet$ constraints section;
20.111 +
20.112 +$\bullet$ bounds section;
20.113 +
20.114 +$\bullet$ general, integer, and binary sections (can appear in arbitrary
20.115 +order);
20.116 +
20.117 +$\bullet$ end keyword.
20.118 +
20.119 +These components are discussed in following sections.
20.120 +
20.121 +\section{Objective function definition}
20.122 +
20.123 +The objective function definition must appear first in the LP file. It
20.124 +defines the objective function and specifies the optimization direction.
20.125 +
20.126 +The objective function definition has the following form:
20.127 +$$
20.128 +\left\{
20.129 +\begin{array}{@{}c@{}}
20.130 +{\tt minimize} \\ {\tt maximize}
20.131 +\end{array}
20.132 +\right\}\ f\ {\tt :}\ s\ c\ x\ s\ c\ x\ \dots\ s\ c\ x
20.133 +$$
20.134 +where $f$ is a symbolic name of the objective function, $s$ is a sign
20.135 +\verb|+| or \verb|-|, $c$ is a numeric constant that denotes an
20.136 +objective coefficient, $x$ is a symbolic name of a variable.
20.137 +
20.138 +If necessary, the objective function definition can be continued on as
20.139 +many text lines as desired.
20.140 +
20.141 +The name of the objective function is optional and may be omitted
20.142 +(together with the semicolon that follows it). In this case the default
20.143 +name `\verb|obj|' is assigned to the objective function.
20.144 +
20.145 +If the very first sign $s$ is omitted, the sign plus is assumed. Other
20.146 +signs cannot be omitted.
20.147 +
20.148 +If some objective coefficient $c$ is omitted, 1 is assumed.
20.149 +
20.150 +Symbolic names $x$ used to denote variables are recognized by context
20.151 +and therefore needn't to be declared somewhere else.
20.152 +
20.153 +Here is an example of the objective function definition:
20.154 +
20.155 +\begin{verbatim}
20.156 + Minimize Z : - x1 + 2 x2 - 3.5 x3 + 4.997e3x(4) + x5 + x6 +
20.157 + x7 - .01x8
20.158 +\end{verbatim}
20.159 +
20.160 +\section{Constraints section}
20.161 +
20.162 +The constraints section must follow the objective function definition.
20.163 +It defines a system of equality and/or inequality constraints.
20.164 +
20.165 +The constraint section has the following form:
20.166 +
20.167 +\begin{center}
20.168 +\begin{tabular}{l}
20.169 +\verb|subject to| \\
20.170 +{\it constraint}$_1$ \\
20.171 +{\it constraint}$_2$ \\
20.172 +\hspace{20pt}\dots \\
20.173 +{\it constraint}$_m$ \\
20.174 +\end{tabular}
20.175 +\end{center}
20.176 +
20.177 +\noindent where {\it constraint}$_i, i=1,\dots,m,$ is a particular
20.178 +constraint definition.
20.179 +
20.180 +Each constraint definition can be continued on as many text lines as
20.181 +desired. However, each constraint definition must begin on a new line
20.182 +except the very first constraint definition which can begin on the same
20.183 +line as the keyword `\verb|subject to|'.
20.184 +
20.185 +Constraint definitions have the following form:
20.186 +$$
20.187 +r\ {\tt:}\ s\ c\ x\ s\ c\ x\ \dots\ s\ c\ x
20.188 +\ \left\{
20.189 +\begin{array}{@{}c@{}}
20.190 +\mbox{\tt<=} \\ \mbox{\tt>=} \\ \mbox{\tt=}
20.191 +\end{array}
20.192 +\right\}\ b
20.193 +$$
20.194 +where $r$ is a symbolic name of a constraint, $s$ is a sign \verb|+| or
20.195 +\verb|-|, $c$ is a numeric constant that denotes a constraint
20.196 +coefficient, $x$ is a symbolic name of a variable, $b$ is a right-hand
20.197 +side.
20.198 +
20.199 +The name $r$ of a constraint (which is the name of the corresponding
20.200 +auxiliary variable) is optional and may be omitted (together with the
20.201 +semicolon that follows it). In this case the default names like
20.202 +`\verb|r.nnn|' are assigned to unnamed constraints.
20.203 +
20.204 +The linear form $s\ c\ x\ s\ c\ x\ \dots\ s\ c\ x$ in the left-hand
20.205 +side of a constraint definition has exactly the same meaning as in the
20.206 +case of the objective function definition (see above).
20.207 +
20.208 +After the linear form one of the following delimiters that indicate
20.209 +the constraint sense must be specified:
20.210 +
20.211 +\verb|<=| \ means `less than or equal to'
20.212 +
20.213 +\verb|>=| \ means `greater than or equal to'
20.214 +
20.215 +\verb|= | \ means `equal to'
20.216 +
20.217 +The right hand side $b$ is a numeric constant with an optional sign.
20.218 +
20.219 +Here is an example of the constraints section:
20.220 +
20.221 +\begin{verbatim}
20.222 + Subject To
20.223 + one: y1 + 3 a1 - a2 - b >= 1.5
20.224 + y2 + 2 a3 + 2
20.225 + a4 - b >= -1.5
20.226 + two : y4 + 3 a1 + 4 a5 - b <= +1
20.227 + .20y5 + 5 a2 - b = 0
20.228 + 1.7 y6 - a6 + 5 a777 - b >= 1
20.229 +\end{verbatim}
20.230 +
20.231 +(Should note that it is impossible to express ranged constraints in the
20.232 +CPLEX LP format. Each a ranged constraint can be coded as two
20.233 +constraints with identical linear forms in the left-hand side, one of
20.234 +which specifies a lower bound and other does an upper one of the
20.235 +original ranged constraint.)
20.236 +
20.237 +\section{Bounds section}
20.238 +
20.239 +The bounds section is intended to define bounds of variables. This
20.240 +section is optional; if it is specified, it must follow the constraints
20.241 +section. If the bound section is omitted, all variables are assumed to
20.242 +be non-negative (i.e. that they have zero lower bound and no upper
20.243 +bound).
20.244 +
20.245 +The bounds section has the following form:
20.246 +
20.247 +\begin{center}
20.248 +\begin{tabular}{l}
20.249 +\verb|bounds| \\
20.250 +{\it definition}$_1$ \\
20.251 +{\it definition}$_2$ \\
20.252 +\hspace{20pt}\dots \\
20.253 +{\it definition}$_p$ \\
20.254 +\end{tabular}
20.255 +\end{center}
20.256 +
20.257 +\noindent
20.258 +where {\it definition}$_k, k=1,\dots,p,$ is a particular bound
20.259 +definition.
20.260 +
20.261 +Each bound definition must begin on a new line\footnote{The GLPK
20.262 +implementation allows several bound definitions to be placed on the same
20.263 +line.} except the very first bound definition which can begin on the
20.264 +same line as the keyword `\verb|bounds|'.
20.265 +
20.266 +Syntactically constraint definitions can have one of the following six
20.267 +forms:
20.268 +
20.269 +\begin{center}
20.270 +\begin{tabular}{ll}
20.271 +$x$ \verb|>=| $l$ & specifies a lower bound \\
20.272 +$l$ \verb|<=| $x$ & specifies a lower bound \\
20.273 +$x$ \verb|<=| $u$ & specifies an upper bound \\
20.274 +$l$ \verb|<=| $x$ \verb|<=| $u$ &specifies both lower and upper bounds\\
20.275 +$x$ \verb|=| $t$ &specifies a fixed value \\
20.276 +$x$ \verb|free| &specifies free variable
20.277 +\end{tabular}
20.278 +\end{center}
20.279 +
20.280 +\noindent
20.281 +where $x$ is a symbolic name of a variable, $l$ is a numeric constant
20.282 +with an optional sign that defines a lower bound of the variable or
20.283 +\verb|-inf| that means that the variable has no lower bound, $u$ is a
20.284 +numeric constant with an optional sign that defines an upper bound of
20.285 +the variable or \verb|+inf| that means that the variable has no upper
20.286 +bound, $t$ is a numeric constant with an optional sign that defines a
20.287 +fixed value of the variable.
20.288 +
20.289 +By default all variables are non-negative, i.e. have zero lower bound
20.290 +and no upper bound. Therefore definitions of these default bounds can be
20.291 +omitted in the bounds section.
20.292 +
20.293 +Here is an example of the bounds section:
20.294 +
20.295 +\begin{verbatim}
20.296 + Bounds
20.297 + -inf <= a1 <= 100
20.298 + -100 <= a2
20.299 + b <= 100
20.300 + x2 = +123.456
20.301 + x3 free
20.302 +\end{verbatim}
20.303 +
20.304 +\section{General, integer, and binary sections}
20.305 +
20.306 +The general, integer, and binary sections are intended to define
20.307 +some variables as integer or binary. All these sections are optional
20.308 +and needed only in case of MIP problems. If they are specified, they
20.309 +must follow the bounds section or, if the latter is omitted, the
20.310 +constraints section.
20.311 +
20.312 +All the general, integer, and binary sections have the same form as
20.313 +follows:
20.314 +
20.315 +\begin{center}
20.316 +\begin{tabular}{l}
20.317 +$
20.318 +\left\{
20.319 +\begin{array}{@{}l@{}}
20.320 +\verb|general| \\
20.321 +\verb|integer| \\
20.322 +\verb|binary | \\
20.323 +\end{array}
20.324 +\right\}
20.325 +$ \\
20.326 +\hspace{10pt}$x_1$ \\
20.327 +\hspace{10pt}$x_2$ \\
20.328 +\hspace{10pt}\dots \\
20.329 +\hspace{10pt}$x_q$ \\
20.330 +\end{tabular}
20.331 +\end{center}
20.332 +
20.333 +\noindent
20.334 +where $x_k$ is a symbolic name of variable, $k=1,\dots,q$.
20.335 +
20.336 +Each symbolic name must begin on a new line\footnote{The GLPK
20.337 +implementation allows several symbolic names to be placed on the same
20.338 +line.} except the very first symbolic name which can begin on the same
20.339 +line as the keyword `\verb|general|', `\verb|integer|', or
20.340 +`\verb|binary|'.
20.341 +
20.342 +If a variable appears in the general or the integer section, it is
20.343 +assumed to be general integer variable. If a variable appears in the
20.344 +binary section, it is assumed to be binary variable, i.e. an integer
20.345 +variable whose lower bound is zero and upper bound is one. (Note that
20.346 +if bounds of a variable are specified in the bounds section and then
20.347 +the variable appears in the binary section, its previously specified
20.348 +bounds are ignored.)
20.349 +
20.350 +Here is an example of the integer section:
20.351 +
20.352 +\begin{verbatim}
20.353 + Integer
20.354 + z12
20.355 + z22
20.356 + z35
20.357 +\end{verbatim}
20.358 +
20.359 +\section{End keyword}
20.360 +
20.361 +The keyword `\verb|end|' is intended to end the LP file. It must begin
20.362 +on a separate line and no other elements (except comments and blank
20.363 +lines) must follow it. Although this keyword is optional, it is strongly
20.364 +recommended to include it in the LP file.
20.365 +
20.366 +\section{Example of CPLEX LP file}
20.367 +
20.368 +Here is a complete example of CPLEX LP file that corresponds to the
20.369 +example given in Section \ref{secmpsex}, page \pageref{secmpsex}.
20.370 +
20.371 +{\footnotesize
20.372 +\begin{verbatim}
20.373 +\* plan.lp *\
20.374 +
20.375 +Minimize
20.376 + value: .03 bin1 + .08 bin2 + .17 bin3 + .12 bin4 + .15 bin5 +
20.377 + .21 alum + .38 silicon
20.378 +
20.379 +Subject To
20.380 + yield: bin1 + bin2 + bin3 + bin4 + bin5 +
20.381 + alum + silicon = 2000
20.382 +
20.383 + fe: .15 bin1 + .04 bin2 + .02 bin3 + .04 bin4 + .02 bin5 +
20.384 + .01 alum + .03 silicon <= 60
20.385 +
20.386 + cu: .03 bin1 + .05 bin2 + .08 bin3 + .02 bin4 + .06 bin5 +
20.387 + .01 alum <= 100
20.388 +
20.389 + mn: .02 bin1 + .04 bin2 + .01 bin3 + .02 bin4 + .02 bin5 <= 40
20.390 +
20.391 + mg: .02 bin1 + .03 bin2 + .01 bin5 <= 30
20.392 +
20.393 + al: .70 bin1 + .75 bin2 + .80 bin3 + .75 bin4 + .80 bin5 +
20.394 + .97 alum >= 1500
20.395 +
20.396 + si1: .02 bin1 + .06 bin2 + .08 bin3 + .12 bin4 + .02 bin5 +
20.397 + .01 alum + .97 silicon >= 250
20.398 +
20.399 + si2: .02 bin1 + .06 bin2 + .08 bin3 + .12 bin4 + .02 bin5 +
20.400 + .01 alum + .97 silicon <= 300
20.401 +
20.402 +Bounds
20.403 + bin1 <= 200
20.404 + bin2 <= 2500
20.405 + 400 <= bin3 <= 800
20.406 + 100 <= bin4 <= 700
20.407 + bin5 <= 1500
20.408 +
20.409 +End
20.410 +
20.411 +\* eof *\
20.412 +\end{verbatim}
20.413 +
20.414 +}
20.415 +
20.416 +%* eof *%
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
21.2 +++ b/doc/glpk10.tex Mon Dec 06 13:09:21 2010 +0100
21.3 @@ -0,0 +1,210 @@
21.4 +%* glpk10.tex *%
21.5 +
21.6 +\chapter{Stand-alone LP/MIP Solver}
21.7 +\label{chaglpsol}
21.8 +
21.9 +The GLPK package includes the program \verb|glpsol|, which is a
21.10 +stand-alone LP/MIP solver. This program can be invoked from the command
21.11 +line of from the shell to read LP/MIP problem data in any format
21.12 +supported by GLPK, solve the problem, and write the problem solution
21.13 +obtained to an output text file.
21.14 +
21.15 +\subsubsection*{Usage}
21.16 +
21.17 +\noindent
21.18 +\verb|glpsol| [{\it options\dots}] [{\it filename}]
21.19 +
21.20 +\subsubsection*{General options}
21.21 +
21.22 +\noindent
21.23 +\begin{tabular}{@{}p{30mm}p{92.3mm}@{}}
21.24 +\verb|--mps| & read LP/MIP problem in fixed MPS format \\
21.25 +\verb|--freemps| & read LP/MIP problem in free MPS format (default)\\
21.26 +\verb|--lp| & read LP/MIP problem in CPLEX LP format \\
21.27 +\verb|--glp| & read LP/MIP problem in GLPK format \\
21.28 +\verb|--math| & read LP/MIP model written in GNU MathProg modeling
21.29 + language \\
21.30 +\multicolumn{2}{@{}l}{{\tt -m} {\it filename}, {\tt --model}
21.31 +{\it filename}} \\
21.32 + & read model section and optional data section from
21.33 + {\it filename} (the same as \verb|--math|) \\
21.34 +\multicolumn{2}{@{}l}{{\tt -d} {\it filename}, {\tt --data}
21.35 +{\it filename}} \\
21.36 + & read data section from {\it filename}
21.37 + (for \verb|--math| only); if model file also has
21.38 + data section, that section is ignored \\
21.39 +\multicolumn{2}{@{}l}{{\tt -y} {\it filename}, {\tt --display}
21.40 +{\it filename}} \\
21.41 + & send display output to {\it filename}
21.42 + (for \verb|--math| only); by default the output is
21.43 + sent to \verb|stdout| \\
21.44 +\end{tabular}
21.45 +
21.46 +\noindent
21.47 +\begin{tabular}{@{}p{30mm}p{92.3mm}@{}}
21.48 +\verb|--seed| {\it value}
21.49 + & initialize pseudo-random number generator used in
21.50 + MathProg model with specified seed (any integer);
21.51 + if the seed value is specified as \verb|?|
21.52 + (question mark), some random seed will be used\\
21.53 +\verb|--mincost| & read min-cost flow problem in DIMACS format\\
21.54 +\verb|--maxflow| & read maximum flow problem in DIMACS format\\
21.55 +\verb|--simplex| & use simplex method (default) \\
21.56 +\verb|--interior| & use interior point method (for pure LP only) \\
21.57 +\multicolumn{2}{@{}l}{{\tt -r} {\it filename}, {\tt --read}
21.58 +{\it filename}} \\
21.59 + & read solution from {\it filename} rather to find
21.60 + it with the solver \\
21.61 +\verb|--min| & minimization \\
21.62 +\verb|--max| & maximization \\
21.63 +\verb|--scale| & scale problem (default) \\
21.64 +\verb|--noscale| & do not scale problem \\
21.65 +\multicolumn{2}{@{}l}{{\tt -o} {\it filename}, {\tt --output}
21.66 +{\it filename}} \\
21.67 + & write solution to {\it filename} in printable
21.68 + format \\
21.69 +\multicolumn{2}{@{}l}{{\tt -w} {\it filename}, {\tt --write}
21.70 +{\it filename}} \\
21.71 + & write solution to {\it filename} in plain text
21.72 + format \\
21.73 +\multicolumn{2}{@{}l}{{\tt --ranges} {\it filename}} \\
21.74 + & write sensitivity analysis report to {\it filename}
21.75 + in printable format (simplex only) \\
21.76 +\verb|--tmlim| {\it nnn}
21.77 + & limit solution time to {\it nnn} seconds
21.78 + (\verb|--tmlim 0| allows obtaining solution at
21.79 + initial point) \\
21.80 +\verb|--memlim| {\it nnn}
21.81 + & limit available memory to {\it nnn} megabytes \\
21.82 +\verb|--check| & do not solve problem, check input data only \\
21.83 +\verb|--name| {\it probname}
21.84 + & change problem name to {\it probname} \\
21.85 +\verb|--wmps| {\it filename}
21.86 + & write problem to {\it filename} in fixed MPS
21.87 + format \\
21.88 +\multicolumn{2}{@{}l}{{\tt --wfreemps} {\it filename}} \\
21.89 + & write problem to {\it filename} in free MPS
21.90 + format \\
21.91 +\verb|--wlp| {\it filename}
21.92 + & write problem to {\it filename} in CPLEX LP
21.93 + format \\
21.94 +\verb|--wglp| {\it filename}
21.95 + & write problem to {\it filename} in GLPK format \\
21.96 +\verb|--log| {\it filename}
21.97 + & write copy of terminal output to {\it filename} \\
21.98 +\verb|-h|, \verb|--help|
21.99 + & display this help information and exit \\
21.100 +\verb|-v|, \verb|--version|
21.101 + & display program version and exit \\
21.102 +\end{tabular}
21.103 +
21.104 +\subsection*{LP basis factorization options}
21.105 +
21.106 +\noindent
21.107 +\begin{tabular}{@{}p{30mm}p{92.3mm}@{}}
21.108 +\verb|--luf| & LU + Forrest--Tomlin update \\
21.109 + & (faster, less stable; default) \\
21.110 +\verb|--cbg| & LU + Schur complement + Bartels--Golub update \\
21.111 + & (slower, more stable) \\
21.112 +\verb|--cgr| & LU + Schur complement + Givens rotation update \\
21.113 + & (slower, more stable) \\
21.114 +\end{tabular}
21.115 +
21.116 +\subsubsection*{Options specific to the simplex solver}
21.117 +
21.118 +\noindent
21.119 +\begin{tabular}{@{}p{30mm}p{92.3mm}@{}}
21.120 +\verb|--primal| & use primal simplex (default) \\
21.121 +\verb|--dual| & use dual simplex \\
21.122 +\verb|--std| & use standard initial basis of all slacks \\
21.123 +\verb|--adv| & use advanced initial basis (default) \\
21.124 +\verb|--bib| & use Bixby's initial basis\\
21.125 +\verb|--ini| {\it filename}
21.126 + & use as initial basis previously saved with
21.127 + \verb|-w| \\
21.128 + & (disables LP presolver) \\
21.129 +\verb|--steep| & use steepest edge technique (default) \\
21.130 +\verb|--nosteep| & use standard ``textbook'' pricing \\
21.131 +\verb|--relax| & use Harris' two-pass ratio test (default) \\
21.132 +\verb|--norelax| & use standard ``textbook'' ratio test \\
21.133 +\verb|--presol| & use LP presolver (default; assumes \verb|--scale|
21.134 + and \verb|--adv|) \\
21.135 +\verb|--nopresol| & do not use LP presolver \\
21.136 +\verb|--exact| & use simplex method based on exact arithmetic \\
21.137 +\verb|--xcheck| & check final basis using exact arithmetic \\
21.138 +\end{tabular}
21.139 +
21.140 +\subsubsection*{Options specific to the interior-point solver}
21.141 +
21.142 +\noindent
21.143 +\begin{tabular}{@{}p{30mm}p{92.3mm}@{}}
21.144 +\verb|--nord| & use natural (original) ordering \\
21.145 +\verb|--qmd| & use quotient minimum degree ordering \\
21.146 +\verb|--amd| & use approximate minimum degree ordering (default)\\
21.147 +\verb|--symamd| & use approximate minimum degree ordering \\
21.148 +\end{tabular}
21.149 +
21.150 +\subsubsection*{Options specific to the MIP solver}
21.151 +
21.152 +\noindent
21.153 +\begin{tabular}{@{}p{30mm}p{92.3mm}@{}}
21.154 +\verb|--nomip| & consider all integer variables as continuous
21.155 + (allows solving MIP as pure LP) \\
21.156 +\verb|--first| & branch on first integer variable \\
21.157 +\verb|--last| & branch on last integer variable \\
21.158 +\verb|--mostf| & branch on most fractional variable \\
21.159 +\end{tabular}
21.160 +
21.161 +\noindent
21.162 +\begin{tabular}{@{}p{30mm}p{92.3mm}@{}}
21.163 +\verb|--drtom| & branch using heuristic by Driebeck and Tomlin
21.164 + (default) \\
21.165 +\verb|--pcost| & branch using hybrid pseudocost heuristic (may be
21.166 + useful for hard instances) \\
21.167 +\verb|--dfs| & backtrack using depth first search \\
21.168 +\verb|--bfs| & backtrack using breadth first search \\
21.169 +\verb|--bestp| & backtrack using the best projection heuristic
21.170 + (default) \\
21.171 +\verb|--bestb| & backtrack using node with best local bound \\
21.172 +\verb|--intopt| & use MIP presolver (default)\\
21.173 +\verb|--nointopt| & do not use MIP presolver\\
21.174 +\verb|--binarize| & replace general integer variables by binary ones
21.175 + (assumes \verb|--intopt|)\\
21.176 +\verb|--fpump| & apply feasibility pump heuristic\\
21.177 +\verb|--gomory| & generate Gomory's mixed integer cuts\\
21.178 +\verb|--mir| & generate MIR (mixed integer rounding) cuts\\
21.179 +\verb|--cover| & generate mixed cover cuts\\
21.180 +\verb|--clique| & generate clique cuts\\
21.181 +\verb|--cuts| & generate cuts of all classes above (assumes
21.182 + \verb|--intopt|)\\
21.183 +\verb|--mipgap| {\it tol}
21.184 + & set relative mip gap tolerance to {\it tol}\\
21.185 +\end{tabular}
21.186 +
21.187 +\bigskip
21.188 +
21.189 +\noindent
21.190 +For description of the MPS format see Appendix \ref{champs},
21.191 +page \pageref{champs}.
21.192 +
21.193 +\bigskip
21.194 +
21.195 +\noindent
21.196 +For description of the CPLEX LP format see Appendix \ref{chacplex},
21.197 +page \pageref{chacplex}.
21.198 +
21.199 +\bigskip
21.200 +
21.201 +\noindent
21.202 +For description of the modeling language see the document ``Modeling
21.203 +Language GNU MathProg: Language Reference'' included in the GLPK
21.204 +distribution.
21.205 +
21.206 +\bigskip
21.207 +
21.208 +\noindent
21.209 +For description of the DIMACS min-cost flow problem format and DIMACS
21.210 +maximum flow problem format see the document ``GLPK: Graph and Network
21.211 +Routines'' included in the GLPK distribution.
21.212 +
21.213 +%* eof *%
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
22.2 +++ b/doc/glpk11.tex Mon Dec 06 13:09:21 2010 +0100
22.3 @@ -0,0 +1,124 @@
22.4 +%* glpk11.tex *%
22.5 +
22.6 +\begin{footnotesize}
22.7 +
22.8 +\chapter{External Software Modules Used In GLPK}
22.9 +
22.10 +In the GLPK package there are used some external software modules
22.11 +listed in this Appendix. Note that these modules are {\it not} part of
22.12 +GLPK, but are used with GLPK and included in the distribution.
22.13 +
22.14 +\section{AMD}
22.15 +
22.16 +AMD Version 2.2, Copyright {\copyright} 2007 by Timothy A. Davis,
22.17 +Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved.
22.18 +
22.19 +\subsection*{Description}
22.20 +
22.21 +AMD is a set of routines for pre-ordering sparse matrices prior to
22.22 +Cholesky or LU factorization, using the approximate minimum degree
22.23 +ordering algorithm.
22.24 +
22.25 +\subsection*{License}
22.26 +
22.27 +This library is free software; you can redistribute it and/or
22.28 +modify it under the terms of the GNU Lesser General Public License
22.29 +as published by the Free Software Foundation; either version 2.1 of
22.30 +the License, or (at your option) any later version.
22.31 +
22.32 +This library is distributed in the hope that it will be useful,
22.33 +but WITHOUT ANY WARRANTY; without even the implied warranty of
22.34 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22.35 +Lesser General Public License for more details.
22.36 +
22.37 +You should have received a copy of the GNU Lesser General Public
22.38 +License along with this library; if not, write to the Free Software
22.39 +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22.40 +USA.
22.41 +
22.42 +Permission is hereby granted to use or copy this program under the
22.43 +terms of the GNU LGPL, provided that the Copyright, this License,
22.44 +and the Availability of the original version is retained on all
22.45 +copies. User documentation of any code that uses this code or any
22.46 +modified version of this code must cite the Copyright, this License,
22.47 +the Availability note, and ``Used by permission.'' Permission to
22.48 +modify the code and to distribute modified code is granted, provided
22.49 +the Copyright, this License, and the Availability note are retained,
22.50 +and a notice that the code was modified is included.
22.51 +
22.52 +AMD is available under alternate licences; contact T. Davis for
22.53 +details.
22.54 +
22.55 +\subsection*{Availability}
22.56 +
22.57 +\verb|http://www.cise.ufl.edu/research/sparse/amd|
22.58 +
22.59 +\bigskip
22.60 +
22.61 +\noindent
22.62 +Used by permission.
22.63 +
22.64 +\section{COLAMD/SYMAMD}
22.65 +
22.66 +COLAMD/SYMAMD Version 2.7, Copyright {\copyright} 1998-2007, Timothy A.
22.67 +Davis, All Rights Reserved.
22.68 +
22.69 +\subsection*{Description}
22.70 +
22.71 +\paragraph{colamd:} an approximate minimum degree column ordering
22.72 +algorithm, for LU factorization of symmetric or unsymmetric matrices,
22.73 +QR factorization, least squares, interior point methods for linear
22.74 +programming problems, and other related problems.
22.75 +
22.76 +\paragraph{symamd:} an approximate minimum degree ordering algorithm
22.77 +for Cholesky factorization of symmetric matrices.
22.78 +
22.79 +\subsection*{Authors}
22.80 +
22.81 +The authors of the code itself are Stefan I. Larimore and Timothy A.
22.82 +Davis (davis at cise.ufl.edu), University of Florida. The algorithm
22.83 +was developed in collaboration with John Gilbert, Xerox PARC, and
22.84 +Esmond Ng, Oak Ridge National Laboratory.
22.85 +
22.86 +\subsection*{License}
22.87 +
22.88 +This library is free software; you can redistribute it and/or
22.89 +modify it under the terms of the GNU Lesser General Public License
22.90 +as published by the Free Software Foundation; either version 2.1 of
22.91 +the License, or (at your option) any later version.
22.92 +
22.93 +This library is distributed in the hope that it will be useful,
22.94 +but WITHOUT ANY WARRANTY; without even the implied warranty of
22.95 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22.96 +Lesser General Public License for more details.
22.97 +
22.98 +You should have received a copy of the GNU Lesser General Public
22.99 +License along with this library; if not, write to the Free Software
22.100 +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22.101 +USA.
22.102 +
22.103 +Permission is hereby granted to use or copy this program under the
22.104 +terms of the GNU LGPL, provided that the Copyright, this License,
22.105 +and the Availability of the original version is retained on all
22.106 +copies. User documentation of any code that uses this code or any
22.107 +modified version of this code must cite the Copyright, this License,
22.108 +the Availability note, and ``Used by permission.'' Permission to
22.109 +modify the code and to distribute modified code is granted, provided
22.110 +the Copyright, this License, and the Availability note are retained,
22.111 +and a notice that the code was modified is included.
22.112 +
22.113 +COLAMD is also available under alternate licenses, contact T. Davis for
22.114 +details.
22.115 +
22.116 +\subsection*{Availability}
22.117 +
22.118 +\verb|http://www.cise.ufl.edu/research/sparse/colamd|
22.119 +
22.120 +\bigskip
22.121 +
22.122 +\noindent
22.123 +Used by permission.
22.124 +
22.125 +\end{footnotesize}
22.126 +
22.127 +%* eof *%
23.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
23.2 +++ b/doc/glpk12.tex Mon Dec 06 13:09:21 2010 +0100
23.3 @@ -0,0 +1,726 @@
23.4 +%* glpk12.tex *%
23.5 +
23.6 +\begin{footnotesize}
23.7 +
23.8 +\chapter*{\sf\bfseries GNU General Public License}
23.9 +\addcontentsline{toc}{chapter}{GNU General Public License}
23.10 +
23.11 +\begin{center}
23.12 +{\bf Version 3, 29 June 2007}
23.13 +\end{center}
23.14 +
23.15 +\begin{quotation}
23.16 +\noindent
23.17 +Copyright {\copyright} 2007 Free Software Foundation, Inc.
23.18 +\verb|<http://fsf.org/>|
23.19 +\end{quotation}
23.20 +
23.21 +\begin{quotation}
23.22 +\noindent
23.23 +Everyone is permitted to copy and distribute verbatim copies
23.24 +of this license document, but changing it is not allowed.
23.25 +\end{quotation}
23.26 +
23.27 +\section*{Preamble}
23.28 +
23.29 +\noindent\indent
23.30 + The GNU General Public License is a free, copyleft license for
23.31 +software and other kinds of works.
23.32 +
23.33 + The licenses for most software and other practical works are designed
23.34 +to take away your freedom to share and change the works. By contrast,
23.35 +the GNU General Public License is intended to guarantee your freedom to
23.36 +share and change all versions of a program--to make sure it remains free
23.37 +software for all its users. We, the Free Software Foundation, use the
23.38 +GNU General Public License for most of our software; it applies also to
23.39 +any other work released this way by its authors. You can apply it to
23.40 +your programs, too.
23.41 +
23.42 + When we speak of free software, we are referring to freedom, not
23.43 +price. Our General Public Licenses are designed to make sure that you
23.44 +have the freedom to distribute copies of free software (and charge for
23.45 +them if you wish), that you receive source code or can get it if you
23.46 +want it, that you can change the software or use pieces of it in new
23.47 +free programs, and that you know you can do these things.
23.48 +
23.49 + To protect your rights, we need to prevent others from denying you
23.50 +these rights or asking you to surrender the rights. Therefore, you have
23.51 +certain responsibilities if you distribute copies of the software, or if
23.52 +you modify it: responsibilities to respect the freedom of others.
23.53 +
23.54 + For example, if you distribute copies of such a program, whether
23.55 +gratis or for a fee, you must pass on to the recipients the same
23.56 +freedoms that you received. You must make sure that they, too, receive
23.57 +or can get the source code. And you must show them these terms so they
23.58 +know their rights.
23.59 +
23.60 + Developers that use the GNU GPL protect your rights with two steps:
23.61 +(1) assert copyright on the software, and (2) offer you this License
23.62 +giving you legal permission to copy, distribute and/or modify it.
23.63 +
23.64 + For the developers' and authors' protection, the GPL clearly explains
23.65 +that there is no warranty for this free software. For both users' and
23.66 +authors' sake, the GPL requires that modified versions be marked as
23.67 +changed, so that their problems will not be attributed erroneously to
23.68 +authors of previous versions.
23.69 +
23.70 + Some devices are designed to deny users access to install or run
23.71 +modified versions of the software inside them, although the manufacturer
23.72 +can do so. This is fundamentally incompatible with the aim of
23.73 +protecting users' freedom to change the software. The systematic
23.74 +pattern of such abuse occurs in the area of products for individuals to
23.75 +use, which is precisely where it is most unacceptable. Therefore, we
23.76 +have designed this version of the GPL to prohibit the practice for those
23.77 +products. If such problems arise substantially in other domains, we
23.78 +stand ready to extend this provision to those domains in future versions
23.79 +of the GPL, as needed to protect the freedom of users.
23.80 +
23.81 + Finally, every program is threatened constantly by software patents.
23.82 +States should not allow patents to restrict development and use of
23.83 +software on general-purpose computers, but in those that do, we wish to
23.84 +avoid the special danger that patents applied to a free program could
23.85 +make it effectively proprietary. To prevent this, the GPL assures that
23.86 +patents cannot be used to render the program non-free.
23.87 +
23.88 + The precise terms and conditions for copying, distribution and
23.89 +modification follow.
23.90 +
23.91 +\section*{TERMS AND CONDITIONS}
23.92 +
23.93 +\subsubsection*{0. Definitions.}
23.94 +
23.95 +\noindent\indent
23.96 + ``This License'' refers to version 3 of the GNU General Public
23.97 +License.
23.98 +
23.99 + ``Copyright'' also means copyright-like laws that apply to other kinds
23.100 +of works, such as semiconductor masks.
23.101 +
23.102 + ``The Program'' refers to any copyrightable work licensed under this
23.103 +License. Each licensee is addressed as ``you''. ``Licensees'' and
23.104 +``recipients'' may be individuals or organizations.
23.105 +
23.106 + To ``modify'' a work means to copy from or adapt all or part of the
23.107 +work in a fashion requiring copyright permission, other than the making
23.108 +of an exact copy. The resulting work is called a ``modified version''
23.109 +of the earlier work or a work ``based on'' the earlier work.
23.110 +
23.111 + A ``covered work'' means either the unmodified Program or a work based
23.112 +on the Program.
23.113 +
23.114 + To ``propagate'' a work means to do anything with it that, without
23.115 +permission, would make you directly or secondarily liable for
23.116 +infringement under applicable copyright law, except executing it on a
23.117 +computer or modifying a private copy. Propagation includes copying,
23.118 +distribution (with or without modification), making available to the
23.119 +public, and in some countries other activities as well.
23.120 +
23.121 + To ``convey'' a work means any kind of propagation that enables other
23.122 +parties to make or receive copies. Mere interaction with a user through
23.123 +a computer network, with no transfer of a copy, is not conveying.
23.124 +
23.125 + An interactive user interface displays ``Appropriate Legal Notices''
23.126 +to the extent that it includes a convenient and prominently visible
23.127 +feature that (1) displays an appropriate copyright notice, and (2)
23.128 +tells the user that there is no warranty for the work (except to the
23.129 +extent that warranties are provided), that licensees may convey the
23.130 +work under this License, and how to view a copy of this License. If
23.131 +the interface presents a list of user commands or options, such as a
23.132 +menu, a prominent item in the list meets this criterion.
23.133 +
23.134 +\subsubsection*{1. Source Code.}
23.135 +
23.136 +\noindent\indent
23.137 + The ``source code'' for a work means the preferred form of the work
23.138 +for making modifications to it. ``Object code'' means any non-source
23.139 +form of a work.
23.140 +
23.141 + A ``Standard Interface'' means an interface that either is an official
23.142 +standard defined by a recognized standards body, or, in the case of
23.143 +interfaces specified for a particular programming language, one that
23.144 +is widely used among developers working in that language.
23.145 +
23.146 + The ``System Libraries'' of an executable work include anything, other
23.147 +than the work as a whole, that (a) is included in the normal form of
23.148 +packaging a Major Component, but which is not part of that Major
23.149 +Component, and (b) serves only to enable use of the work with that
23.150 +Major Component, or to implement a Standard Interface for which an
23.151 +implementation is available to the public in source code form. A
23.152 +``Major Component'', in this context, means a major essential component
23.153 +(kernel, window system, and so on) of the specific operating system
23.154 +(if any) on which the executable work runs, or a compiler used to
23.155 +produce the work, or an object code interpreter used to run it.
23.156 +
23.157 + The ``Corresponding Source'' for a work in object code form means all
23.158 +the source code needed to generate, install, and (for an executable
23.159 +work) run the object code and to modify the work, including scripts to
23.160 +control those activities. However, it does not include the work's
23.161 +System Libraries, or general-purpose tools or generally available free
23.162 +programs which are used unmodified in performing those activities but
23.163 +which are not part of the work. For example, Corresponding Source
23.164 +includes interface definition files associated with source files for
23.165 +the work, and the source code for shared libraries and dynamically
23.166 +linked subprograms that the work is specifically designed to require,
23.167 +such as by intimate data communication or control flow between those
23.168 +subprograms and other parts of the work.
23.169 +
23.170 + The Corresponding Source need not include anything that users
23.171 +can regenerate automatically from other parts of the Corresponding
23.172 +Source.
23.173 +
23.174 + The Corresponding Source for a work in source code form is that
23.175 +same work.
23.176 +
23.177 +\subsubsection*{2. Basic Permissions.}
23.178 +
23.179 +\noindent\indent
23.180 + All rights granted under this License are granted for the term of
23.181 +copyright on the Program, and are irrevocable provided the stated
23.182 +conditions are met. This License explicitly affirms your unlimited
23.183 +permission to run the unmodified Program. The output from running a
23.184 +covered work is covered by this License only if the output, given its
23.185 +content, constitutes a covered work. This License acknowledges your
23.186 +rights of fair use or other equivalent, as provided by copyright law.
23.187 +
23.188 + You may make, run and propagate covered works that you do not
23.189 +convey, without conditions so long as your license otherwise remains
23.190 +in force. You may convey covered works to others for the sole purpose
23.191 +of having them make modifications exclusively for you, or provide you
23.192 +with facilities for running those works, provided that you comply with
23.193 +the terms of this License in conveying all material for which you do
23.194 +not control copyright. Those thus making or running the covered works
23.195 +for you must do so exclusively on your behalf, under your direction
23.196 +and control, on terms that prohibit them from making any copies of
23.197 +your copyrighted material outside their relationship with you.
23.198 +
23.199 + Conveying under any other circumstances is permitted solely under
23.200 +the conditions stated below. Sublicensing is not allowed; section 10
23.201 +makes it unnecessary.
23.202 +
23.203 +\subsubsection*{3. Protecting Users' Legal Rights From
23.204 +Anti-Circumvention Law.}
23.205 +
23.206 +\noindent\indent
23.207 + No covered work shall be deemed part of an effective technological
23.208 +measure under any applicable law fulfilling obligations under article
23.209 +11 of the WIPO copyright treaty adopted on 20 December 1996, or
23.210 +similar laws prohibiting or restricting circumvention of such
23.211 +measures.
23.212 +
23.213 + When you convey a covered work, you waive any legal power to forbid
23.214 +circumvention of technological measures to the extent such circumvention
23.215 +is effected by exercising rights under this License with respect to
23.216 +the covered work, and you disclaim any intention to limit operation or
23.217 +modification of the work as a means of enforcing, against the work's
23.218 +users, your or third parties' legal rights to forbid circumvention of
23.219 +technological measures.
23.220 +
23.221 +\subsubsection*{4. Conveying Verbatim Copies.}
23.222 +
23.223 +\noindent\indent
23.224 + You may convey verbatim copies of the Program's source code as you
23.225 +receive it, in any medium, provided that you conspicuously and
23.226 +appropriately publish on each copy an appropriate copyright notice;
23.227 +keep intact all notices stating that this License and any
23.228 +non-permissive terms added in accord with section 7 apply to the code;
23.229 +keep intact all notices of the absence of any warranty; and give all
23.230 +recipients a copy of this License along with the Program.
23.231 +
23.232 + You may charge any price or no price for each copy that you convey,
23.233 +and you may offer support or warranty protection for a fee.
23.234 +
23.235 +\subsubsection*{5. Conveying Modified Source Versions.}
23.236 +
23.237 + You may convey a work based on the Program, or the modifications to
23.238 +produce it from the Program, in the form of source code under the
23.239 +terms of section 4, provided that you also meet all of these conditions:
23.240 +
23.241 + a) The work must carry prominent notices stating that you modified
23.242 + it, and giving a relevant date.
23.243 +
23.244 + b) The work must carry prominent notices stating that it is
23.245 + released under this License and any conditions added under section
23.246 + 7. This requirement modifies the requirement in section 4 to
23.247 + ``keep intact all notices''.
23.248 +
23.249 + c) You must license the entire work, as a whole, under this
23.250 + License to anyone who comes into possession of a copy. This
23.251 + License will therefore apply, along with any applicable section 7
23.252 + additional terms, to the whole of the work, and all its parts,
23.253 + regardless of how they are packaged. This License gives no
23.254 + permission to license the work in any other way, but it does not
23.255 + invalidate such permission if you have separately received it.
23.256 +
23.257 + d) If the work has interactive user interfaces, each must display
23.258 + Appropriate Legal Notices; however, if the Program has interactive
23.259 + interfaces that do not display Appropriate Legal Notices, your
23.260 + work need not make them do so.
23.261 +
23.262 + A compilation of a covered work with other separate and independent
23.263 +works, which are not by their nature extensions of the covered work,
23.264 +and which are not combined with it such as to form a larger program,
23.265 +in or on a volume of a storage or distribution medium, is called an
23.266 +``aggregate'' if the compilation and its resulting copyright are not
23.267 +used to limit the access or legal rights of the compilation's users
23.268 +beyond what the individual works permit. Inclusion of a covered work
23.269 +in an aggregate does not cause this License to apply to the other
23.270 +parts of the aggregate.
23.271 +
23.272 +\subsubsection*{6. Conveying Non-Source Forms.}
23.273 +
23.274 + You may convey a covered work in object code form under the terms
23.275 +of sections 4 and 5, provided that you also convey the
23.276 +machine-readable Corresponding Source under the terms of this License,
23.277 +in one of these ways:
23.278 +
23.279 + a) Convey the object code in, or embodied in, a physical product
23.280 + (including a physical distribution medium), accompanied by the
23.281 + Corresponding Source fixed on a durable physical medium
23.282 + customarily used for software interchange.
23.283 +
23.284 + b) Convey the object code in, or embodied in, a physical product
23.285 + (including a physical distribution medium), accompanied by a
23.286 + written offer, valid for at least three years and valid for as
23.287 + long as you offer spare parts or customer support for that product
23.288 + model, to give anyone who possesses the object code either (1) a
23.289 + copy of the Corresponding Source for all the software in the
23.290 + product that is covered by this License, on a durable physical
23.291 + medium customarily used for software interchange, for a price no
23.292 + more than your reasonable cost of physically performing this
23.293 + conveying of source, or (2) access to copy the
23.294 + Corresponding Source from a network server at no charge.
23.295 +
23.296 + c) Convey individual copies of the object code with a copy of the
23.297 + written offer to provide the Corresponding Source. This
23.298 + alternative is allowed only occasionally and noncommercially, and
23.299 + only if you received the object code with such an offer, in accord
23.300 + with subsection 6b.
23.301 +
23.302 + d) Convey the object code by offering access from a designated
23.303 + place (gratis or for a charge), and offer equivalent access to the
23.304 + Corresponding Source in the same way through the same place at no
23.305 + further charge. You need not require recipients to copy the
23.306 + Corresponding Source along with the object code. If the place to
23.307 + copy the object code is a network server, the Corresponding Source
23.308 + may be on a different server (operated by you or a third party)
23.309 + that supports equivalent copying facilities, provided you maintain
23.310 + clear directions next to the object code saying where to find the
23.311 + Corresponding Source. Regardless of what server hosts the
23.312 + Corresponding Source, you remain obligated to ensure that it is
23.313 + available for as long as needed to satisfy these requirements.
23.314 +
23.315 + e) Convey the object code using peer-to-peer transmission, provided
23.316 + you inform other peers where the object code and Corresponding
23.317 + Source of the work are being offered to the general public at no
23.318 + charge under subsection 6d.
23.319 +
23.320 + A separable portion of the object code, whose source code is excluded
23.321 +from the Corresponding Source as a System Library, need not be
23.322 +included in conveying the object code work.
23.323 +
23.324 + A ``User Product'' is either (1) a ``consumer product'', which means
23.325 +any tangible personal property which is normally used for personal,
23.326 +family, or household purposes, or (2) anything designed or sold for
23.327 +incorporation into a dwelling. In determining whether a product is a
23.328 +consumer product, doubtful cases shall be resolved in favor of coverage.
23.329 +For a particular product received by a particular user, ``normally
23.330 +used'' refers to a typical or common use of that class of product,
23.331 +regardless of the status of the particular user or of the way in which
23.332 +the particular user actually uses, or expects or is expected to use, the
23.333 +product. A product is a consumer product regardless of whether the
23.334 +product has substantial commercial, industrial or non-consumer uses,
23.335 +unless such uses represent the only significant mode of use of the
23.336 +product.
23.337 +
23.338 + ``Installation Information'' for a User Product means any methods,
23.339 +procedures, authorization keys, or other information required to install
23.340 +and execute modified versions of a covered work in that User Product
23.341 +from a modified version of its Corresponding Source. The information
23.342 +must suffice to ensure that the continued functioning of the modified
23.343 +object code is in no case prevented or interfered with solely because
23.344 +modification has been made.
23.345 +
23.346 + If you convey an object code work under this section in, or with, or
23.347 +specifically for use in, a User Product, and the conveying occurs as
23.348 +part of a transaction in which the right of possession and use of the
23.349 +User Product is transferred to the recipient in perpetuity or for a
23.350 +fixed term (regardless of how the transaction is characterized), the
23.351 +Corresponding Source conveyed under this section must be accompanied
23.352 +by the Installation Information. But this requirement does not apply
23.353 +if neither you nor any third party retains the ability to install
23.354 +modified object code on the User Product (for example, the work has
23.355 +been installed in ROM).
23.356 +
23.357 + The requirement to provide Installation Information does not include a
23.358 +requirement to continue to provide support service, warranty, or updates
23.359 +for a work that has been modified or installed by the recipient, or for
23.360 +the User Product in which it has been modified or installed. Access to
23.361 +a network may be denied when the modification itself materially and
23.362 +adversely affects the operation of the network or violates the rules and
23.363 +protocols for communication across the network.
23.364 +
23.365 + Corresponding Source conveyed, and Installation Information provided,
23.366 +in accord with this section must be in a format that is publicly
23.367 +documented (and with an implementation available to the public in
23.368 +source code form), and must require no special password or key for
23.369 +unpacking, reading or copying.
23.370 +
23.371 +\subsubsection*{7. Additional Terms.}
23.372 +
23.373 +\noindent\indent
23.374 + ``Additional permissions'' are terms that supplement the terms of this
23.375 +License by making exceptions from one or more of its conditions.
23.376 +Additional permissions that are applicable to the entire Program shall
23.377 +be treated as though they were included in this License, to the extent
23.378 +that they are valid under applicable law. If additional permissions
23.379 +apply only to part of the Program, that part may be used separately
23.380 +under those permissions, but the entire Program remains governed by
23.381 +this License without regard to the additional permissions.
23.382 +
23.383 + When you convey a copy of a covered work, you may at your option
23.384 +remove any additional permissions from that copy, or from any part of
23.385 +it. (Additional permissions may be written to require their own
23.386 +removal in certain cases when you modify the work.) You may place
23.387 +additional permissions on material, added by you to a covered work,
23.388 +for which you have or can give appropriate copyright permission.
23.389 +
23.390 + Notwithstanding any other provision of this License, for material you
23.391 +add to a covered work, you may (if authorized by the copyright holders
23.392 +of that material) supplement the terms of this License with terms:
23.393 +
23.394 + a) Disclaiming warranty or limiting liability differently from the
23.395 + terms of sections 15 and 16 of this License; or
23.396 +
23.397 + b) Requiring preservation of specified reasonable legal notices or
23.398 + author attributions in that material or in the Appropriate Legal
23.399 + Notices displayed by works containing it; or
23.400 +
23.401 + c) Prohibiting misrepresentation of the origin of that material, or
23.402 + requiring that modified versions of such material be marked in
23.403 + reasonable ways as different from the original version; or
23.404 +
23.405 + d) Limiting the use for publicity purposes of names of licensors or
23.406 + authors of the material; or
23.407 +
23.408 + e) Declining to grant rights under trademark law for use of some
23.409 + trade names, trademarks, or service marks; or
23.410 +
23.411 + f) Requiring indemnification of licensors and authors of that
23.412 + material by anyone who conveys the material (or modified versions of
23.413 + it) with contractual assumptions of liability to the recipient, for
23.414 + any liability that these contractual assumptions directly impose on
23.415 + those licensors and authors.
23.416 +
23.417 + All other non-permissive additional terms are considered ``further
23.418 +restrictions'' within the meaning of section 10. If the Program as you
23.419 +received it, or any part of it, contains a notice stating that it is
23.420 +governed by this License along with a term that is a further
23.421 +restriction, you may remove that term. If a license document contains
23.422 +a further restriction but permits relicensing or conveying under this
23.423 +License, you may add to a covered work material governed by the terms
23.424 +of that license document, provided that the further restriction does
23.425 +not survive such relicensing or conveying.
23.426 +
23.427 + If you add terms to a covered work in accord with this section, you
23.428 +must place, in the relevant source files, a statement of the
23.429 +additional terms that apply to those files, or a notice indicating
23.430 +where to find the applicable terms.
23.431 +
23.432 + Additional terms, permissive or non-permissive, may be stated in the
23.433 +form of a separately written license, or stated as exceptions;
23.434 +the above requirements apply either way.
23.435 +
23.436 +\subsubsection*{8. Termination.}
23.437 +
23.438 +\noindent\indent
23.439 + You may not propagate or modify a covered work except as expressly
23.440 +provided under this License. Any attempt otherwise to propagate or
23.441 +modify it is void, and will automatically terminate your rights under
23.442 +this License (including any patent licenses granted under the third
23.443 +paragraph of section 11).
23.444 +
23.445 + However, if you cease all violation of this License, then your
23.446 +license from a particular copyright holder is reinstated (a)
23.447 +provisionally, unless and until the copyright holder explicitly and
23.448 +finally terminates your license, and (b) permanently, if the copyright
23.449 +holder fails to notify you of the violation by some reasonable means
23.450 +prior to 60 days after the cessation.
23.451 +
23.452 + Moreover, your license from a particular copyright holder is
23.453 +reinstated permanently if the copyright holder notifies you of the
23.454 +violation by some reasonable means, this is the first time you have
23.455 +received notice of violation of this License (for any work) from that
23.456 +copyright holder, and you cure the violation prior to 30 days after
23.457 +your receipt of the notice.
23.458 +
23.459 + Termination of your rights under this section does not terminate the
23.460 +licenses of parties who have received copies or rights from you under
23.461 +this License. If your rights have been terminated and not permanently
23.462 +reinstated, you do not qualify to receive new licenses for the same
23.463 +material under section 10.
23.464 +
23.465 +\subsubsection*{9. Acceptance Not Required for Having Copies.}
23.466 +
23.467 +\noindent\indent
23.468 + You are not required to accept this License in order to receive or
23.469 +run a copy of the Program. Ancillary propagation of a covered work
23.470 +occurring solely as a consequence of using peer-to-peer transmission
23.471 +to receive a copy likewise does not require acceptance. However,
23.472 +nothing other than this License grants you permission to propagate or
23.473 +modify any covered work. These actions infringe copyright if you do
23.474 +not accept this License. Therefore, by modifying or propagating a
23.475 +covered work, you indicate your acceptance of this License to do so.
23.476 +
23.477 +\subsubsection*{10. Automatic Licensing of Downstream Recipients.}
23.478 +
23.479 +\noindent\indent
23.480 + Each time you convey a covered work, the recipient automatically
23.481 +receives a license from the original licensors, to run, modify and
23.482 +propagate that work, subject to this License. You are not responsible
23.483 +for enforcing compliance by third parties with this License.
23.484 +
23.485 + An ``entity transaction'' is a transaction transferring control of an
23.486 +organization, or substantially all assets of one, or subdividing an
23.487 +organization, or merging organizations. If propagation of a covered
23.488 +work results from an entity transaction, each party to that
23.489 +transaction who receives a copy of the work also receives whatever
23.490 +licenses to the work the party's predecessor in interest had or could
23.491 +give under the previous paragraph, plus a right to possession of the
23.492 +Corresponding Source of the work from the predecessor in interest, if
23.493 +the predecessor has it or can get it with reasonable efforts.
23.494 +
23.495 + You may not impose any further restrictions on the exercise of the
23.496 +rights granted or affirmed under this License. For example, you may
23.497 +not impose a license fee, royalty, or other charge for exercise of
23.498 +rights granted under this License, and you may not initiate litigation
23.499 +(including a cross-claim or counterclaim in a lawsuit) alleging that
23.500 +any patent claim is infringed by making, using, selling, offering for
23.501 +sale, or importing the Program or any portion of it.
23.502 +
23.503 +\subsubsection*{11. Patents.}
23.504 +
23.505 +\noindent\indent
23.506 + A ``contributor'' is a copyright holder who authorizes use under this
23.507 +License of the Program or a work on which the Program is based. The
23.508 +work thus licensed is called the contributor's ``contributor version''.
23.509 +
23.510 + A contributor's ``essential patent claims'' are all patent claims
23.511 +owned or controlled by the contributor, whether already acquired or
23.512 +hereafter acquired, that would be infringed by some manner, permitted
23.513 +by this License, of making, using, or selling its contributor version,
23.514 +but do not include claims that would be infringed only as a
23.515 +consequence of further modification of the contributor version. For
23.516 +purposes of this definition, ``control'' includes the right to grant
23.517 +patent sublicenses in a manner consistent with the requirements of
23.518 +this License.
23.519 +
23.520 + Each contributor grants you a non-exclusive, worldwide, royalty-free
23.521 +patent license under the contributor's essential patent claims, to
23.522 +make, use, sell, offer for sale, import and otherwise run, modify and
23.523 +propagate the contents of its contributor version.
23.524 +
23.525 + In the following three paragraphs, a ``patent license'' is any express
23.526 +agreement or commitment, however denominated, not to enforce a patent
23.527 +(such as an express permission to practice a patent or covenant not to
23.528 +sue for patent infringement). To ``grant'' such a patent license to a
23.529 +party means to make such an agreement or commitment not to enforce a
23.530 +patent against the party.
23.531 +
23.532 + If you convey a covered work, knowingly relying on a patent license,
23.533 +and the Corresponding Source of the work is not available for anyone
23.534 +to copy, free of charge and under the terms of this License, through a
23.535 +publicly available network server or other readily accessible means,
23.536 +then you must either (1) cause the Corresponding Source to be so
23.537 +available, or (2) arrange to deprive yourself of the benefit of the
23.538 +patent license for this particular work, or (3) arrange, in a manner
23.539 +consistent with the requirements of this License, to extend the patent
23.540 +license to downstream recipients. ``Knowingly relying'' means you have
23.541 +actual knowledge that, but for the patent license, your conveying the
23.542 +covered work in a country, or your recipient's use of the covered work
23.543 +in a country, would infringe one or more identifiable patents in that
23.544 +country that you have reason to believe are valid.
23.545 +
23.546 + If, pursuant to or in connection with a single transaction or
23.547 +arrangement, you convey, or propagate by procuring conveyance of, a
23.548 +covered work, and grant a patent license to some of the parties
23.549 +receiving the covered work authorizing them to use, propagate, modify
23.550 +or convey a specific copy of the covered work, then the patent license
23.551 +you grant is automatically extended to all recipients of the covered
23.552 +work and works based on it.
23.553 +
23.554 + A patent license is ``discriminatory'' if it does not include within
23.555 +the scope of its coverage, prohibits the exercise of, or is
23.556 +conditioned on the non-exercise of one or more of the rights that are
23.557 +specifically granted under this License. You may not convey a covered
23.558 +work if you are a party to an arrangement with a third party that is
23.559 +in the business of distributing software, under which you make payment
23.560 +to the third party based on the extent of your activity of conveying
23.561 +the work, and under which the third party grants, to any of the
23.562 +parties who would receive the covered work from you, a discriminatory
23.563 +patent license (a) in connection with copies of the covered work
23.564 +conveyed by you (or copies made from those copies), or (b) primarily
23.565 +for and in connection with specific products or compilations that
23.566 +contain the covered work, unless you entered into that arrangement,
23.567 +or that patent license was granted, prior to 28 March 2007.
23.568 +
23.569 + Nothing in this License shall be construed as excluding or limiting
23.570 +any implied license or other defenses to infringement that may
23.571 +otherwise be available to you under applicable patent law.
23.572 +
23.573 +\subsubsection*{12. No Surrender of Others' Freedom.}
23.574 +
23.575 +\noindent\indent
23.576 + If conditions are imposed on you (whether by court order, agreement or
23.577 +otherwise) that contradict the conditions of this License, they do not
23.578 +excuse you from the conditions of this License. If you cannot convey a
23.579 +covered work so as to satisfy simultaneously your obligations under this
23.580 +License and any other pertinent obligations, then as a consequence you
23.581 +may not convey it at all. For example, if you agree to terms that
23.582 +obligate you to collect a royalty for further conveying from those to
23.583 +whom you convey the Program, the only way you could satisfy both those
23.584 +terms and this License would be to refrain entirely from conveying the
23.585 +Program.
23.586 +
23.587 +\subsubsection*{13. Use with the GNU Affero General Public License.}
23.588 +
23.589 +\noindent\indent
23.590 + Notwithstanding any other provision of this License, you have
23.591 +permission to link or combine any covered work with a work licensed
23.592 +under version 3 of the GNU Affero General Public License into a single
23.593 +combined work, and to convey the resulting work. The terms of this
23.594 +License will continue to apply to the part which is the covered work,
23.595 +but the special requirements of the GNU Affero General Public License,
23.596 +section 13, concerning interaction through a network will apply to the
23.597 +combination as such.
23.598 +
23.599 +\subsubsection*{14. Revised Versions of this License.}
23.600 +
23.601 +\noindent\indent
23.602 + The Free Software Foundation may publish revised and/or new versions
23.603 +of the GNU General Public License from time to time. Such new versions
23.604 +will be similar in spirit to the present version, but may differ in
23.605 +detail to address new problems or concerns.
23.606 +
23.607 + Each version is given a distinguishing version number. If the
23.608 +Program specifies that a certain numbered version of the GNU General
23.609 +Public License ``or any later version'' applies to it, you have the
23.610 +option of following the terms and conditions either of that numbered
23.611 +version or of any later version published by the Free Software
23.612 +Foundation. If the Program does not specify a version number of the
23.613 +GNU General Public License, you may choose any version ever published
23.614 +by the Free Software Foundation.
23.615 +
23.616 + If the Program specifies that a proxy can decide which future
23.617 +versions of the GNU General Public License can be used, that proxy's
23.618 +public statement of acceptance of a version permanently authorizes you
23.619 +to choose that version for the Program.
23.620 +
23.621 + Later license versions may give you additional or different
23.622 +permissions. However, no additional obligations are imposed on any
23.623 +author or copyright holder as a result of your choosing to follow a
23.624 +later version.
23.625 +
23.626 +\subsubsection*{15. Disclaimer of Warranty.}
23.627 +
23.628 +\noindent\indent
23.629 + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
23.630 +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
23.631 +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM ``AS IS'' WITHOUT
23.632 +WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
23.633 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23.634 +PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
23.635 +OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU
23.636 +ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
23.637 +
23.638 +\subsubsection*{16. Limitation of Liability.}
23.639 +
23.640 +\noindent\indent
23.641 + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
23.642 +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR
23.643 +CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
23.644 +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
23.645 +ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT
23.646 +NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES
23.647 +SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE
23.648 +WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN
23.649 +ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
23.650 +
23.651 +\subsubsection*{17. Interpretation of Sections 15 and 16.}
23.652 +
23.653 +\noindent\indent
23.654 + If the disclaimer of warranty and limitation of liability provided
23.655 +above cannot be given local legal effect according to their terms,
23.656 +reviewing courts shall apply local law that most closely approximates
23.657 +an absolute waiver of all civil liability in connection with the
23.658 +Program, unless a warranty or assumption of liability accompanies a
23.659 +copy of the Program in return for a fee.
23.660 +
23.661 +\section*{END OF TERMS AND CONDITIONS}
23.662 +
23.663 +\newpage
23.664 +
23.665 +\section*{How to Apply These Terms to Your New Programs}
23.666 +
23.667 +\noindent\indent
23.668 + If you develop a new program, and you want it to be of the greatest
23.669 +possible use to the public, the best way to achieve this is to make it
23.670 +free software which everyone can redistribute and change under these
23.671 +terms.
23.672 +
23.673 + To do so, attach the following notices to the program. It is safest
23.674 +to attach them to the start of each source file to most effectively
23.675 +state the exclusion of warranty; and each file should have at least
23.676 +the ``copyright'' line and a pointer to where the full notice is found.
23.677 +
23.678 +\begin{verbatim}
23.679 +<one line to give the program's name and a brief idea of what it does.>
23.680 +Copyright (C) <year> <name of author>
23.681 +
23.682 +This program is free software: you can redistribute it and/or modify
23.683 +it under the terms of the GNU General Public License as published by
23.684 +the Free Software Foundation, either version 3 of the License, or
23.685 +(at your option) any later version.
23.686 +
23.687 +This program is distributed in the hope that it will be useful,
23.688 +but WITHOUT ANY WARRANTY; without even the implied warranty of
23.689 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23.690 +GNU General Public License for more details.
23.691 +
23.692 +You should have received a copy of the GNU General Public License
23.693 +along with this program. If not, see <http://www.gnu.org/licenses/>.
23.694 +\end{verbatim}
23.695 +
23.696 +\noindent
23.697 +Also add information on how to contact you by electronic and paper mail.
23.698 +
23.699 + If the program does terminal interaction, make it output a short
23.700 +notice like this when it starts in an interactive mode:
23.701 +
23.702 +\begin{verbatim}
23.703 +<program> Copyright (C) <year> <name of author>
23.704 +This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
23.705 +This is free software, and you are welcome to redistribute it
23.706 +under certain conditions; type `show c' for details.
23.707 +\end{verbatim}
23.708 +
23.709 +\noindent
23.710 +The hypothetical commands `show w' and `show c' should show the
23.711 +appropriate parts of the General Public License. Of course, your
23.712 +program's commands might be different; for a GUI interface, you would
23.713 +use an ``about box''.
23.714 +
23.715 + You should also get your employer (if you work as a programmer) or
23.716 +school, if any, to sign a ``copyright disclaimer'' for the program, if
23.717 +necessary. For more information on this, and how to apply and follow the
23.718 +GNU GPL, see \verb|<http://www.gnu.org/licenses/>|.
23.719 +
23.720 + The GNU General Public License does not permit incorporating your
23.721 +program into proprietary programs. If your program is a subroutine
23.722 +library, you may consider it more useful to permit linking proprietary
23.723 +applications with the library. If this is what you want to do, use the
23.724 +GNU Lesser General Public License instead of this License. But first,
23.725 +please read \verb|<http://www.gnu.org/philosophy/why-not-lgpl.html>|.
23.726 +
23.727 +\end{footnotesize}
23.728 +
23.729 +%* eof *%
24.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
24.2 +++ b/doc/glpk_faq.txt Mon Dec 06 13:09:21 2010 +0100
24.3 @@ -0,0 +1,435 @@
24.4 +
24.5 +GNU Linear Programming Kit FAQ
24.6 +
24.7 + Summary: Frequently Asked Questions about the GNU Linear Programming Kit
24.8 +
24.9 + Author: Dr. Harley Mackenzie <hjm@hardsoftware.com>
24.10 +
24.11 + Posting-Frequency: Monthly
24.12 +
24.13 + Language: English
24.14 +
24.15 + $Date: 2004/01/09 05:57:57 $
24.16 +
24.17 + $Revision: 1.6 $
24.18 +
24.19 +
24.20 +
24.21 +Introduction
24.22 +
24.23 + Q. What is GPLK?
24.24 +
24.25 + A. GLPK stands for the GNU Linear Programming Kit. The GLPK package is
24.26 + a set of routines written in ANSI C and organized in the form of a
24.27 + callable library. This package is intended for solving large-scale
24.28 + linear programming (LP), mixed integer linear programming (MIP), and
24.29 + other related problems.
24.30 +
24.31 + The GLPK package includes the following main components:
24.32 +
24.33 + * implementation of the simplex method,
24.34 +
24.35 + * implementation of the primal-dual interior point method,
24.36 +
24.37 + * implementation of the branch-and-bound method,
24.38 +
24.39 + * application program interface (API),
24.40 +
24.41 + * GNU MathProg modeling language (a subset of AMPL),
24.42 +
24.43 + * GLPSOL, a stand-alone LP/MIP solver.
24.44 +
24.45 +
24.46 + Q. Who develops and maintains GLPK?
24.47 +
24.48 + A. GLPK is currently developed and maintained by Andrew Makhorin,
24.49 + Department for Applied Informatics, Moscow Aviation Institute, Moscow,
24.50 + Russia. Andrew's email address is <mao@mai2.rcnet.ru> and his postal
24.51 + address is 125871, Russia, Moscow, Volokolamskoye sh., 4, Moscow
24.52 + Aviation Institute, Andrew O. Makhorin
24.53 +
24.54 +
24.55 + Q. How is GLPK licensed?
24.56 +
24.57 + A. GLPK is currently licensed under the GNU General Public License
24.58 + (GPL). GLPK is free software; you can redistribute it and/or modify it
24.59 + under the terms of the GNU General Public License as published by the
24.60 + Free Software Foundation; either version 2, or (at your option) any
24.61 + later version.
24.62 +
24.63 + GLPK is not licensed under the Lesser General Public License (LGPL) as
24.64 + distinct from other free LP codes such as lp_solve. The most
24.65 + significant implication is that code that is linked to the GLPK library
24.66 + must be released under the GPL, whereas with the LGPL, code linked to
24.67 + the library does not have to be released under the same license.
24.68 +
24.69 +
24.70 + Q. Where is the GLPK home page?
24.71 +
24.72 + The GLPK home page is part of the GNU web site and can found at
24.73 + <http://www.gnu.org/software/glpk/glpk.html>.
24.74 +
24.75 +
24.76 + Q. How do I download and install GLPK?
24.77 +
24.78 + A. The GLPK source distribution can be found in the subdirectory
24.79 + /gnu/glpk/ on your favorite GNU mirror
24.80 + <http://www.gnu.org/prep/ftp.html> and can be compiled directly from
24.81 + the source.
24.82 +
24.83 + The GLPK package (like all other GNU software) is distributed in the
24.84 + form of packed archive. This is one file named 'glpk-x.y.tar.gz', where
24.85 + x is the major version number and y is the minor version number.
24.86 +
24.87 + In order to prepare the distribution for installation you should:
24.88 +
24.89 + 1. Copy the GLPK distribution file to some subdirectory.
24.90 +
24.91 + 2. Enter the command 'gzip -d glpk-x.y.tar.gz' in order to unpack the
24.92 + distribution file. After unpacking the name of the distribution file
24.93 + will be automatically changed to 'glpk-x.y.tar'.
24.94 +
24.95 + 3. Enter the command 'tar -x < glpk-x.y.tar' in order to unarchive the
24.96 + distribution. After this operation the subdirectory 'glpk-x.y' which is
24.97 + the GLPK distribution will have been automatically created.
24.98 +
24.99 + After you have unpacked and unarchived GLPK distribution you should
24.100 + configure the package, and compiled the application. The result of
24.101 + compilation is:
24.102 +
24.103 + * the file 'libglpk.a', which is a library archive containing object code
24.104 + for all GLPK routines; and
24.105 +
24.106 + * the program 'glpsol', which is a stand-alone LP/MIP solver.
24.107 +
24.108 + Complete compilation and installation instructions are included in the
24.109 + INSTALL file included with the distribution.
24.110 +
24.111 + The distribution includes make files for the Microsoft Visual C/C++
24.112 + version 6 and Borland C/C++ version 5 and by default compiles and links
24.113 + a glpk*.lib library file, a glpk*.dll DLL file and an glpsol.exe
24.114 + application file. A GNU Windows 4.1 binary, source and documentation
24.115 + compiled using the mingw32 C/C++ compiler is also available from
24.116 + <http://gnuwin32.sourceforge.net/packages/glpk.htm>.
24.117 +
24.118 +
24.119 + Q. Is there a GLPK mailing list or newsgroup?
24.120 +
24.121 + A. GLPK has two mailing lists: <help-glpk@gnu.org> and
24.122 + <bug-glpk@gnu.org>.
24.123 +
24.124 + The main discussion list is <help-glpk@gnu.org>, and is used to discuss
24.125 + all aspects of GLPK, including its development and porting. There is
24.126 + also a special list used for reporting bugs at <bug-glpk@gnu.org>.
24.127 +
24.128 + To subscribe to any GLPK mailing list, send an empty mail with a
24.129 + Subject: header line of just "subscribe" to the relevant -request list.
24.130 + For example, to subscribe yourself to the main list, you would send
24.131 + mail to <help-glpk-request@gnu.org> with no body and a Subject: header
24.132 + line of just "subscribe".
24.133 +
24.134 + Another way to subscribe to the GLP mailing lists is to visit the web
24.135 + pages <http://mail.gnu.org/mailman/listinfo/help-glpk> and
24.136 + <http://mail.gnu.org/mailman/listinfo/bug-glpk>.
24.137 +
24.138 + Currently there are no newsgroups dedicated to GLPK.
24.139 +
24.140 +
24.141 + Q. Who maintains this FAQ and how do I contribute to this FAQ?
24.142 +
24.143 + A. The present maintainer of this FAQ is Dr. Harley Mackenzie, HARD
24.144 + software, although the content of the FAQ is derived from many sources
24.145 + such as GLPK documentation, GLPK email archives and original content.
24.146 +
24.147 + Harley's email address is <hjm@hardsoftware.com> and his postal address
24.148 + is c/o HARD software, PO Box 8004, Newtown, Victoria 3220, Australia.
24.149 +
24.150 + All contributions to this FAQ, such as questions and (preferably)
24.151 + answers should be sent to the <hjm@hardsoftware.com> email address.
24.152 + This FAQ is copyright Harley Mackenzie 2003 and is released under the
24.153 + same license, terms and conditions as GLPK, that is, GPL version 2 or
24.154 + later.
24.155 +
24.156 + Contributions are not directly referenced in the body of the FAQ as
24.157 + this would become unmanageable and messy, but rather as a list of
24.158 + contributors to this FAQ. If you are the author of any information
24.159 + included in this FAQ and you do not want your content to be included,
24.160 + please contact the FAQ maintainer and your material will be removed.
24.161 + Also if you have not been correctly included as a contributor to this
24.162 + FAQ, your details have changed, or you do not want your name listed in
24.163 + the list of contributors, please contact the FAQ maintainer for
24.164 + correction.
24.165 +
24.166 +
24.167 + Q. Where can I download this FAQ?
24.168 +
24.169 + The latest version of the GLPK FAQ is available to download from
24.170 + <http://www.hardsoftware.com/downloads.php#GLPK+FAQ> in the following
24.171 + formats:
24.172 +
24.173 + * DocBook
24.174 +
24.175 + * Formatted text
24.176 +
24.177 + * Adobe PDF
24.178 +
24.179 +
24.180 + Q. Who are the FAQ contributors?
24.181 +
24.182 + A. The FAQ contents were created from the following sources:
24.183 +
24.184 + * Michael Hennebry
24.185 +
24.186 + * http://www-unix.mcs.anl.gov/otc/Guide/faq/linear-programming-faq.html
24.187 +
24.188 + * Harley Mackenzie, HARD software Pty. Ltd.
24.189 +
24.190 + * Andrew Makhorin, Department for Applied Informatics, Moscow Aviation
24.191 + Institute
24.192 +
24.193 +
24.194 +GLPK functions & features
24.195 +
24.196 + Q. What is the current state of GLPK development?
24.197 +
24.198 + A. GLPK is a work in progress and is presently under continual
24.199 + development. As of the current version 4.3, GLPK is a simplex-based
24.200 + solver is able to handle problems with up to 100,000 constraints. In
24.201 + particular, it successfully solves all instances from netlib (see the
24.202 + file bench.txt included in the GLPK distribution). The interior-point
24.203 + solver is not very robust as it is unable to handle dense columns,
24.204 + sometimes terminates due to numeric instability or slow convergence.
24.205 +
24.206 + The Mixed Integer Programming (MIP) solver currently is based on
24.207 + branch-and-bound, so it is unable to solve hard or very large problems
24.208 + with a probable practical limit of 100-200 integer variables. However,
24.209 + sometimes it is able to solve larger problems of up to 1000 integer
24.210 + variables, although the size that depends on properties of particular
24.211 + problem.
24.212 +
24.213 +
24.214 + Q. How does GLPK compare with other LP codes?
24.215 +
24.216 + A. I think that on very large-scale instances CPLEX 8.0 dual simplex is
24.217 + 10-100 times faster than the GLPK simplex solver and, of course, much
24.218 + more robust. In many cases GLPK is faster and more robust than lp_solve
24.219 + 4.0 for pure LPs as well as MIP's. See the bench.txt file in the GLPK
24.220 + distribution doc directory for GLPK netlib benchmark results.
24.221 +
24.222 + You can find benchmarks for some LP and MIP solvers such as CPLEX,
24.223 + GLPK, lp_solve, and OSL on Hans Mittelmann's webpage at
24.224 + <http://plato.asu.edu/bench.html>.
24.225 +
24.226 +
24.227 + Q. What are the differences between AMPL and GNU MathProg?
24.228 +
24.229 + A. The subset of AMPL implemented in MathProg approximately corresponds
24.230 + to AMPL status in 1990, because it is mainly based on the paper Robert
24.231 + Fourer, David M Gay and Brian W Kernighan (1990), "A Modeling Language
24.232 + for Mathematical Programming", Management Science, Vol 36, pp. 519-554
24.233 + and is available at
24.234 + <http://users.iems.nwu.edu/~4er/WRITINGS/amplmod.pdf>.
24.235 +
24.236 + The GNU MathProg translator was developed as part of GLPK. However, GNU
24.237 + MathProg can be easily used in other applications as there is a set of
24.238 + MathProg interface routines designed for use in other applications.
24.239 +
24.240 +
24.241 + Q. What input file formats does GLPK support?
24.242 +
24.243 + A. GLPK presently can read input and output LP model files in three
24.244 + supported formats:
24.245 +
24.246 + * MPS format - which is a column oriented and widely supported file
24.247 + format but has poor human readability.
24.248 +
24.249 + * CPLEX format - which is an easily readable row oriented format.
24.250 +
24.251 + * GNU MathProg - which is an AMPL like mathematical modeling language.
24.252 +
24.253 +
24.254 + Q. What interfaces are available for GLPK?
24.255 +
24.256 + A. The GLPK package is in fact a C API that can be either by statically
24.257 + or dynamically linked directly with many programming systems.
24.258 +
24.259 + Presently there are three contributed external interfaces included with
24.260 + the GLPK package:
24.261 +
24.262 + * GLPK Java Native Interface (JNI)
24.263 +
24.264 + * GLPK Delphi Interface (DELI)
24.265 +
24.266 + * GLPKMEX Matlab MEX interface
24.267 +
24.268 + There is an unofficial Microsoft Visual Basic, Tcl/Tk and Java GLPK
24.269 + interface available at
24.270 + <http://gottfried.lindner.bei.t-online.de/glpk.htm>.
24.271 +
24.272 + There are other language interfaces under development, including a Perl
24.273 + interface currently being developed by the FAQ maintainer, Dr. Harley
24.274 + Mackenzie <hjm@hardsoftware.com>.
24.275 +
24.276 +
24.277 + Q. Where can I find some examples?
24.278 +
24.279 + A. The GLPK package distribution contains many examples written in GNU
24.280 + MathProg (*.mod), C API calls (*.c), CPLEX input file format (*.lpt),
24.281 + MPS format (*.mps) as well as some specific Traveling Salesman examples
24.282 + (*.tsp).
24.283 +
24.284 + All of the examples can be found in the GLPK distribution examples
24.285 + sub-directory.
24.286 +
24.287 +
24.288 + Q. What are the future plans for GLPK?
24.289 +
24.290 + A. Developments planned for GLPK include improving the existing key
24.291 + GLPK components, such as developing a more robust and more efficient
24.292 + implementation of the simplex-based and interior-point solvers. Future
24.293 + GLPK enhancements planned are implementing a branch-and-cut solver, a
24.294 + MIP pre-processor, post-optimal and sensitivity analysis and possibly
24.295 + network simplex and quadratic programming solvers.
24.296 +
24.297 +
24.298 + Q. How do I report a GLPK bug?
24.299 +
24.300 + A. If you think you have found a bug in GLPK, then you should send as
24.301 + complete a report as possible to <bug-glpk@gnu.org>.
24.302 +
24.303 +
24.304 + Q. How do I contribute to the GLPK development?
24.305 +
24.306 + A. At present new GLPK development patches should be emailed to Andrew
24.307 + Makhorin <mao@mai2.rcnet.ru >, with sufficient documentation and test
24.308 + code to explain the nature of the patch, how to install it and the
24.309 + implications of its use. Before commencing any major GLPK development
24.310 + for inclusion in the GLPK distribution, it would be a good idea to
24.311 + discuss the idea on the GLPK mailing list.
24.312 +
24.313 +
24.314 + Q. How do I compile and link a GLPK application on a UNIX platform?
24.315 +
24.316 + A. To compile a GLPK application on a UNIX platform, then compiler must
24.317 + be able to include the GLPK include files and link to the GLPK library.
24.318 + For example, on a system where the GLPK system is installed:
24.319 +
24.320 + gcc mylp.c -o mylp -lglpk
24.321 +
24.322 + or specify the include files and libglpk.a explicitly, if GLPK is not
24.323 + installed.
24.324 +
24.325 +
24.326 + Q. How do I compile and link a GLPK application on a Win32 platform?
24.327 +
24.328 + A. On a Win32 platform, GLPK is implemented either as a Win32 Dynamic
24.329 + Link Library (DLL) or can be statically linked to the glpk*.lib file.
24.330 + As with the UNIX instructions, a GLPK application must set a path to
24.331 + the GLPK include files and also reference the GLPK library if
24.332 + statically linked.
24.333 +
24.334 +
24.335 + Q. How do I limit the GLPK execution time?
24.336 +
24.337 + A. You can limit the computing time by setting the control parameter
24.338 + LPX_K_TMLIM via the API routine lpx_set_real_parm . At present there is
24.339 + no way of limiting the execution time of glpsol without changing the
24.340 + source and recompiling a specific version.
24.341 +
24.342 +
24.343 +GLPK Linear Programming
24.344 +
24.345 + Q. What is Linear Programming and how does it work?
24.346 +
24.347 + A. Linear Programming is a mathematical technique that is a generic
24.348 + method for solving certain systems of equations with linear terms. The
24.349 + real power of LP's are that they have many practical applications and
24.350 + have proven to be a powerful and robust tool.
24.351 +
24.352 + The best single source of information on LP's is the Linear Programming
24.353 + FAQ
24.354 + <http://www-unix.mcs.anl.gov/otc/Guide/faq/linear-programming-faq.html>
24.355 + that has information on LP's and MIP's, includes a comprehensive list
24.356 + of available LP software and has many LP references for further study.
24.357 +
24.358 +
24.359 + Q. How do I determine the stability of an LP solution?
24.360 +
24.361 + A. You can perform sensitivity analysis by specifying the --bounds
24.362 + option for glpsol as:
24.363 +
24.364 + glpsol ... --bounds filename
24.365 +
24.366 + in which case the solver writes results of the analysis to the
24.367 + specified filename in plain text format. The corresponding API routine
24.368 + is lpx_print_sens_bnds() .
24.369 +
24.370 +
24.371 + Q. How do I determine which constraints are causing infeasibility?
24.372 +
24.373 + A straightforward way to find such a set of constraints is to drop
24.374 + constraints one at a time. If dropping a constraint results in a
24.375 + solvable problem, pick it up and go on to the next constraint. After
24.376 + applying phase 1 to an infeasible problem, all basic satisfied
24.377 + constraints may be dropped.
24.378 +
24.379 + If the problem has a feasible dual, then running the dual simplex
24.380 + method is a more direct approach. After the last pivot, the nonbasic
24.381 + constraints and one of the violated constraints will constitute a
24.382 + minimal set. The GLPK simplex table routines will allow you to pick a
24.383 + correct constraint from the violated ones.
24.384 +
24.385 + Note that the GLPK pre-solver needs to be turned off for the preceding
24.386 + technique to work, otherwise GLPK does not keep the basis of an
24.387 + infeasible solution.
24.388 +
24.389 + Also a more detailed methodology has been posted on the mail list
24.390 + archive at
24.391 + <http://mail.gnu.org/archive/html/help-glpk/2003-09/msg00017.html>.
24.392 +
24.393 +
24.394 + Q. What is the difference between checks and constraints?
24.395 +
24.396 + A. Check statements are intended to check that all data specified by
24.397 + the user of the model are correct, mainly in the data section of a
24.398 + MathProg model. For example, if some parameter means the number of
24.399 + nodes in a network, it must be positive integer, that is just the
24.400 + condition to be checked in the check statement (although in this case
24.401 + such condition may be also checked directly in the parameter
24.402 + statement). Note that check statements are performed when the
24.403 + translator is generating the model, so they cannot include variables.
24.404 +
24.405 + Constraints are conditions that are expressed in terms of variables and
24.406 + resolved by the solver after the model has been completely generated.
24.407 + If all data specified in the model are correct a priori, check
24.408 + statements are not needed and can be omitted, while constraints are
24.409 + essential components of the model and therefore cannot be omitted.
24.410 +
24.411 +
24.412 +GLPK Integer Programming
24.413 +
24.414 + Q. What is Integer Programming and how does it work?
24.415 +
24.416 + A. Integer LP models are ones whose variables are constrained to take
24.417 + integer or whole number (as opposed to fractional) values. It may not
24.418 + be obvious that integer programming is a very much harder problem than
24.419 + ordinary linear programming, but that is nonetheless the case, in both
24.420 + theory and practice.
24.421 +
24.422 +
24.423 + Q. What is the Integer Optimization Suite (IOS)?
24.424 +
24.425 + A. IOS is a framework to implement implicit enumeration methods based
24.426 + on LP relaxation (like branch-and-bound and branch-and-cut). Currently
24.427 + IOS includes only basic features (the enumeration tree, API routines,
24.428 + and the driver) and is not completely documented.
24.429 +
24.430 +
24.431 + Q. I have just changed an LP to a MIP and now it doesn't work?
24.432 +
24.433 + A. If you have an existing LP that is working and you change to an MIP
24.434 + and receive a "lpx_integer: optimal solution of LP relaxation required"
24.435 + 204 (==LPX_E_FAULT) error, you probably have not called the LP solution
24.436 + method lpx_simplex() before lpx_integer() . The MIP routines use the LP
24.437 + solution as part of the MIP solution methodology.
24.438 +
25.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
25.2 +++ b/doc/gmpl.tex Mon Dec 06 13:09:21 2010 +0100
25.3 @@ -0,0 +1,4653 @@
25.4 +%* gmpl.tex *%
25.5 +
25.6 +%***********************************************************************
25.7 +% This code is part of GLPK (GNU Linear Programming Kit).
25.8 +%
25.9 +% Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
25.10 +% 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
25.11 +% Moscow Aviation Institute, Moscow, Russia. All rights reserved.
25.12 +% E-mail: <mao@gnu.org>.
25.13 +%
25.14 +% GLPK is free software: you can redistribute it and/or modify it
25.15 +% under the terms of the GNU General Public License as published by
25.16 +% the Free Software Foundation, either version 3 of the License, or
25.17 +% (at your option) any later version.
25.18 +%
25.19 +% GLPK is distributed in the hope that it will be useful, but WITHOUT
25.20 +% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25.21 +% or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
25.22 +% License for more details.
25.23 +%
25.24 +% You should have received a copy of the GNU General Public License
25.25 +% along with GLPK. If not, see <http://www.gnu.org/licenses/>.
25.26 +%***********************************************************************
25.27 +
25.28 +\documentclass[10pt]{article}
25.29 +\usepackage[dvipdfm,linktocpage,colorlinks,linkcolor=blue]{hyperref}
25.30 +
25.31 +\begin{document}
25.32 +
25.33 +\thispagestyle{empty}
25.34 +
25.35 +\begin{center}
25.36 +
25.37 +\vspace*{1in}
25.38 +
25.39 +\begin{huge}
25.40 +\sf\bfseries Modeling Language GNU MathProg
25.41 +\end{huge}
25.42 +
25.43 +\vspace{0.5in}
25.44 +
25.45 +\begin{LARGE}
25.46 +\sf Language Reference
25.47 +\end{LARGE}
25.48 +
25.49 +\vspace{0.5in}
25.50 +
25.51 +\begin{LARGE}
25.52 +\sf for GLPK Version 4.45
25.53 +\end{LARGE}
25.54 +
25.55 +\vspace{0.5in}
25.56 +\begin{Large}
25.57 +\sf (DRAFT, December 2010)
25.58 +\end{Large}
25.59 +
25.60 +\end{center}
25.61 +
25.62 +\newpage
25.63 +
25.64 +\vspace*{1in}
25.65 +
25.66 +\vfill
25.67 +
25.68 +\noindent
25.69 +The GLPK package is part of the GNU Project released under the aegis of
25.70 +GNU.
25.71 +
25.72 +\medskip\noindent
25.73 +Copyright \copyright{} 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
25.74 +2008, 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
25.75 +Moscow Aviation Institute, Moscow, Russia. All rights reserved.
25.76 +
25.77 +\medskip\noindent
25.78 +Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
25.79 +MA 02110-1301, USA.
25.80 +
25.81 +\medskip\noindent
25.82 +Permission is granted to make and distribute verbatim copies of this
25.83 +manual provided the copyright notice and this permission notice are
25.84 +preserved on all copies.
25.85 +
25.86 +\medskip\noindent
25.87 +Permission is granted to copy and distribute modified versions of this
25.88 +manual under the conditions for verbatim copying, provided also that
25.89 +the entire resulting derived work is distributed under the terms of
25.90 +a permission notice identical to this one.
25.91 +
25.92 +\medskip\noindent
25.93 +Permission is granted to copy and distribute translations of this
25.94 +manual into another language, under the above conditions for modified
25.95 +versions.
25.96 +
25.97 +\newpage
25.98 +
25.99 +\tableofcontents
25.100 +
25.101 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
25.102 +
25.103 +\newpage
25.104 +
25.105 +\section{Introduction}
25.106 +
25.107 +{\it GNU MathProg} is a modeling language intended for describing
25.108 +linear mathematical programming models.\footnote{The GNU MathProg
25.109 +language is a subset of the AMPL language. Its GLPK implementation is
25.110 +mainly based on the paper: {\it Robert Fourer}, {\it David M. Gay}, and
25.111 +{\it Brian W. Kernighan}, ``A Modeling Language for Mathematical
25.112 +Programming.'' {\it Management Science} 36 (1990)\linebreak pp. 519-54.}
25.113 +
25.114 +Model descriptions written in the GNU MathProg language consist of
25.115 +a set of statements and data blocks constructed by the user from the
25.116 +language elements described in this document.
25.117 +
25.118 +In a process called {\it translation}, a program called the {\it model
25.119 +translator} analyzes the model description and translates it into
25.120 +internal data structures, which may be then used either for generating
25.121 +mathematical programming problem instance or directly by a program
25.122 +called the {\it solver} to obtain numeric solution of the problem.
25.123 +
25.124 +\subsection{Linear programming problem}
25.125 +\label{problem}
25.126 +
25.127 +In MathProg the linear programming (LP) problem is stated as follows:
25.128 +
25.129 +\medskip
25.130 +
25.131 +\noindent\hspace{.7in}minimize (or maximize)
25.132 +$$z=c_1x_1+c_2x_2+\dots+c_nx_n+c_0\eqno(1.1)$$
25.133 +\noindent\hspace{.7in}subject to linear constraints
25.134 +$$
25.135 +\begin{array}{l@{\ }c@{\ }r@{\ }c@{\ }r@{\ }c@{\ }r@{\ }c@{\ }l}
25.136 +L_1&\leq&a_{11}x_1&+&a_{12}x_2&+\dots+&a_{1n}x_n&\leq&U_1\\
25.137 +L_2&\leq&a_{21}x_1&+&a_{22}x_2&+\dots+&a_{2n}x_n&\leq&U_2\\
25.138 +\multicolumn{9}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}\\
25.139 +L_m&\leq&a_{m1}x_1&+&a_{m2}x_2&+\dots+&a_{mn}x_n&\leq&U_m\\
25.140 +\end{array}\eqno(1.2)
25.141 +$$
25.142 +\noindent\hspace{.7in}and bounds of variables
25.143 +$$
25.144 +\begin{array}{l@{\ }c@{\ }c@{\ }c@{\ }l}
25.145 +l_1&\leq&x_1&\leq&u_1\\
25.146 +l_2&\leq&x_2&\leq&u_2\\
25.147 +\multicolumn{5}{c}{.\ \ .\ \ .\ \ .\ \ .}\\
25.148 +l_n&\leq&x_n&\leq&u_n\\
25.149 +\end{array}\eqno(1.3)
25.150 +$$
25.151 +where $x_1$, $x_2$, \dots, $x_n$ are variables; $z$ is the objective
25.152 +function; $c_1$, $c_2$, \dots, $c_n$ are objective coefficients; $c_0$
25.153 +is the constant term (``shift'') of the objective function; $a_{11}$,
25.154 +$a_{12}$, \dots, $a_{mn}$ are constraint coefficients; $L_1$, $L_2$,
25.155 +\dots, $L_m$ are lower constraint bounds; $U_1$, $U_2$, \dots, $U_m$
25.156 +are upper constraint bounds; $l_1$, $l_2$, \dots, $l_n$ are lower
25.157 +bounds of variables; $u_1$, $u_2$, \dots, $u_n$ are upper bounds of
25.158 +variables.
25.159 +
25.160 +Bounds of variables and constraint bounds can be finite as well as
25.161 +infinite. Besides, lower bounds can be equal to corresponding upper
25.162 +bounds. Thus, the following types of variables and constraints are
25.163 +allowed:
25.164 +
25.165 +\newpage
25.166 +
25.167 +\begin{tabular}{@{}r@{\ }c@{\ }c@{\ }c@{\ }l@{\hspace*{38pt}}l}
25.168 +$-\infty$&$<$&$x$&$<$&$+\infty$&Free (unbounded) variable\\
25.169 +$l$&$\leq$&$x$&$<$&$+\infty$&Variable with lower bound\\
25.170 +$-\infty$&$<$&$x$&$\leq$&$u$&Variable with upper bound\\
25.171 +$l$&$\leq$&$x$&$\leq$&$u$&Double-bounded variable\\
25.172 +$l$&$=$&$x$&=&$u$&Fixed variable\\
25.173 +\end{tabular}
25.174 +
25.175 +\bigskip
25.176 +
25.177 +\begin{tabular}{@{}r@{\ }c@{\ }c@{\ }c@{\ }ll}
25.178 +$-\infty$&$<$&$\sum a_jx_j$&$<$&$+\infty$&Free (unbounded) linear
25.179 +form\\
25.180 +$L$&$\leq$&$\sum a_jx_j$&$<$&$+\infty$&Inequality constraint ``greater
25.181 +than or equal to''\\
25.182 +$-\infty$&$<$&$\sum a_jx_j$&$\leq$&$U$&Inequality constraint ``less
25.183 +than or equal to''\\
25.184 +$L$&$\leq$&$\sum a_jx_j$&$\leq$&$U$&Double-bounded inequality
25.185 +constraint\\
25.186 +$L$&$=$&$\sum a_jx_j$&=&$U$&Equality constraint\\
25.187 +\end{tabular}
25.188 +
25.189 +\bigskip
25.190 +
25.191 +In addition to pure LP problems MathProg also allows mixed integer
25.192 +linear programming (MIP) problems, where some or all variables are
25.193 +restricted to be integer or binary.
25.194 +
25.195 +\subsection{Model objects}
25.196 +
25.197 +In MathProg the model is described in terms of sets, parameters,
25.198 +variables, constraints, and objectives, which are called {\it model
25.199 +objects}.
25.200 +
25.201 +The user introduces particular model objects using the language
25.202 +statements. Each model object is provided with a symbolic name that
25.203 +uniquely identifies the object and is intended for referencing purposes.
25.204 +
25.205 +Model objects, including sets, can be multidimensional arrays built
25.206 +over indexing sets. Formally, $n$-dimensional array $A$ is the mapping:
25.207 +$$A:\Delta\rightarrow\Xi,\eqno(1.4)$$
25.208 +where $\Delta\subseteq S_1\times\dots\times S_n$ is a subset of the
25.209 +Cartesian product of indexing sets,\linebreak $\Xi$ is a set of array members.
25.210 +In MathProg the set $\Delta$ is called the {\it subscript domain}. Its
25.211 +members are $n$-tuples $(i_1,\dots,i_n)$, where $i_1\in S_1$, \dots,
25.212 +$i_n\in S_n$.
25.213 +
25.214 +If $n=0$, the Cartesian product above has exactly one member (namely,
25.215 +\linebreak 0-tuple), so it is convenient to think scalar objects as
25.216 +0-dimensional arrays having one member.
25.217 +
25.218 +The type of array members is determined by the type of corresponding
25.219 +model object as follows:
25.220 +
25.221 +\medskip
25.222 +
25.223 +\noindent\hfil
25.224 +\begin{tabular}{@{}ll@{}}
25.225 +Model object&Array member\\
25.226 +\hline
25.227 +Set&Elemental plain set\\
25.228 +Parameter&Number or symbol\\
25.229 +Variable&Elemental variable\\
25.230 +Constraint&Elemental constraint\\
25.231 +Objective&Elemental objective\\
25.232 +\end{tabular}
25.233 +
25.234 +\medskip
25.235 +
25.236 +In order to refer to a particular object member the object should be
25.237 +provided with {\it subscripts}. For example, if $a$ is a 2-dimensional
25.238 +parameter defined over $I\times J$, a reference to its particular
25.239 +member can be written as $a[i,j]$, where $i\in I$ and $j\in J$. It is
25.240 +understood that scalar objects being 0-dimensional need no subscripts.
25.241 +
25.242 +\subsection{Structure of model description}
25.243 +
25.244 +It is sometimes desirable to write a model which, at various points,
25.245 +may require different data for each problem instance to be solved using
25.246 +that model. For this reason in MathProg the model description consists
25.247 +of two parts: the {\it model section} and the {\it data section}.
25.248 +
25.249 +The model section is a main part of the model description that contains
25.250 +declarations of model objects and is common for all problems based on
25.251 +the corresponding model.
25.252 +
25.253 +The data section is an optional part of the model description that
25.254 +contains data specific for a particular problem instance.
25.255 +
25.256 +Depending on what is more convenient the model and data sections can be
25.257 +placed either in one file or in two separate files. The latter feature
25.258 +allows having arbitrary number of different data sections to be used
25.259 +with the same model section.
25.260 +
25.261 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
25.262 +
25.263 +\newpage
25.264 +
25.265 +\section{Coding model description}
25.266 +\label{coding}
25.267 +
25.268 +The model description is coded in plain text format using ASCII
25.269 +character set. Characters valid in the model description are the
25.270 +following:
25.271 +
25.272 +\begin{itemize}
25.273 +\item alphabetic characters:\\
25.274 +\verb|A B C D E F G H I J K L M N O P Q R S T U V W X Y Z|\\
25.275 +\verb|a b c d e f g h i j k l m n o p q r s t u v w x y z _|
25.276 +\item numeric characters:\\
25.277 +\verb|0 1 2 3 4 5 6 7 8 9|
25.278 +\item special characters:\\
25.279 +\verb?! " # & ' ( ) * + , - . / : ; < = > [ ] ^ { | }?
25.280 +\item white-space characters:\\
25.281 +\verb|SP HT CR NL VT FF|
25.282 +\end{itemize}
25.283 +
25.284 +Within string literals and comments any ASCII characters (except
25.285 +control characters) are valid.
25.286 +
25.287 +White-space characters are non-significant. They can be used freely
25.288 +between lexical units to improve readability of the model description.
25.289 +They are also used to separate lexical units from each other if there
25.290 +is no other way to do that.
25.291 +
25.292 +Syntactically model description is a sequence of lexical units in the
25.293 +following categories:
25.294 +
25.295 +\begin{itemize}
25.296 +\item symbolic names;
25.297 +\item numeric literals;
25.298 +\item string literals;
25.299 +\item keywords;
25.300 +\item delimiters;
25.301 +\item comments.
25.302 +\end{itemize}
25.303 +
25.304 +The lexical units of the language are discussed below.
25.305 +
25.306 +\subsection{Symbolic names}
25.307 +
25.308 +A {\it symbolic name} consists of alphabetic and numeric characters,
25.309 +the first of which must be alphabetic. All symbolic names are distinct
25.310 +(case sensitive).
25.311 +
25.312 +\medskip
25.313 +
25.314 +\noindent{\bf Examples}
25.315 +
25.316 +\medskip
25.317 +
25.318 +\noindent\verb|alpha123|
25.319 +
25.320 +\noindent\verb|This_is_a_name|
25.321 +
25.322 +\noindent\verb|_P123_abc_321|
25.323 +
25.324 +\newpage
25.325 +
25.326 +Symbolic names are used to identify model objects (sets, parameters,
25.327 +variables, constraints, objectives) and dummy indices.
25.328 +
25.329 +All symbolic names (except names of dummy indices) must be unique, i.e.
25.330 +the model description must have no objects with identical names.
25.331 +Symbolic names of dummy indices must be unique within the scope, where
25.332 +they are valid.
25.333 +
25.334 +\subsection{Numeric literals}
25.335 +
25.336 +A {\it numeric literal} has the form {\it xx}{\tt E}{\it syy}, where
25.337 +{\it xx} is a number with optional decimal point, {\it s} is the sign
25.338 +{\tt+} or {\tt-}, {\it yy} is a decimal exponent. The letter {\tt E} is
25.339 +case insensitive and can be coded as {\tt e}.
25.340 +
25.341 +\medskip
25.342 +
25.343 +\noindent{\bf Examples}
25.344 +
25.345 +\medskip
25.346 +
25.347 +\noindent\verb|123|
25.348 +
25.349 +\noindent\verb|3.14159|
25.350 +
25.351 +\noindent\verb|56.E+5|
25.352 +
25.353 +\noindent\verb|.78|
25.354 +
25.355 +\noindent\verb|123.456e-7|
25.356 +
25.357 +\medskip
25.358 +
25.359 +Numeric literals are used to represent numeric quantities. They have
25.360 +obvious fixed meaning.
25.361 +
25.362 +\subsection{String literals}
25.363 +
25.364 +A {\it string literal} is a sequence of arbitrary characters enclosed
25.365 +either in single quotes or in double quotes. Both these forms are
25.366 +equivalent.
25.367 +
25.368 +If the single quote is part of a string literal enclosed in single
25.369 +quotes, it must be coded twice. Analogously, if the double quote is
25.370 +part of a string literal enclosed in double quotes, it must be coded
25.371 +twice.
25.372 +
25.373 +\medskip
25.374 +
25.375 +\noindent{\bf Examples}
25.376 +
25.377 +\medskip
25.378 +
25.379 +\noindent\verb|'This is a string'|
25.380 +
25.381 +\noindent\verb|"This is another string"|
25.382 +
25.383 +\noindent\verb|'1 + 2 = 3'|
25.384 +
25.385 +\noindent\verb|'That''s all'|
25.386 +
25.387 +\noindent\verb|"She said: ""No"""|
25.388 +
25.389 +\medskip
25.390 +
25.391 +String literals are used to represent symbolic quantities.
25.392 +
25.393 +\subsection{Keywords}
25.394 +
25.395 +A {\it keyword} is a sequence of alphabetic characters and possibly
25.396 +some special characters.
25.397 +
25.398 +All keywords fall into two categories: {\it reserved keywords}, which
25.399 +cannot be used as symbolic names, and {\it non-reserved keywords},
25.400 +which being recognized by context can be used as symbolic names.
25.401 +
25.402 +\newpage
25.403 +
25.404 +The reserved keywords are the following:
25.405 +
25.406 +\medskip
25.407 +
25.408 +\noindent\hfil
25.409 +\begin{tabular}{@{}p{.7in}p{.7in}p{.7in}p{.7in}@{}}
25.410 +{\tt and}&{\tt else}&{\tt mod}&{\tt union}\\
25.411 +{\tt by}&{\tt if}&{\tt not}&{\tt within}\\
25.412 +{\tt cross}&{\tt in}&{\tt or}\\
25.413 +{\tt diff}&{\tt inter}&{\tt symdiff}\\
25.414 +{\tt div}&{\tt less}&{\tt then}\\
25.415 +\end{tabular}
25.416 +
25.417 +\medskip
25.418 +
25.419 +Non-reserved keywords are described in following sections.
25.420 +
25.421 +All the keywords have fixed meaning, which will be explained on
25.422 +discussion of corresponding syntactic constructions, where the keywords
25.423 +are used.
25.424 +
25.425 +\subsection{Delimiters}
25.426 +
25.427 +A {\it delimiter} is either a single special character or a sequence of
25.428 +two special characters as follows:
25.429 +
25.430 +\medskip
25.431 +
25.432 +\noindent\hfil
25.433 +\begin{tabular}{@{}p{.3in}p{.3in}p{.3in}p{.3in}p{.3in}p{.3in}@{}}
25.434 +{\tt+}&{\tt\textasciicircum}&{\tt==}&{\tt!}&{\tt:}&{\tt)}\\
25.435 +{\tt-}&{\tt\&}&{\tt>=}&{\tt\&\&}&{\tt;}&{\tt[}\\
25.436 +{\tt*}&{\tt<}&{\tt>}&{\tt||}&{\tt:=}&{\tt|}\\
25.437 +{\tt/}&{\tt<=}&{\tt<>}&{\tt.}&{\tt..}&{\tt\{}\\
25.438 +{\tt**}&{\tt=}&{\tt!=}&{\tt,}&{\tt(}&{\tt\}}\\
25.439 +\end{tabular}
25.440 +
25.441 +\medskip
25.442 +
25.443 +If the delimiter consists of two characters, there must be no spaces
25.444 +between the characters.
25.445 +
25.446 +All the delimiters have fixed meaning, which will be explained on
25.447 +discussion corresponding syntactic constructions, where the delimiters
25.448 +are used.
25.449 +
25.450 +\subsection{Comments}
25.451 +
25.452 +For documenting purposes the model description can be provided with
25.453 +{\it comments}, which may have two different forms. The first form is
25.454 +a {\it single-line comment}, which begins with the character {\tt\#}
25.455 +and extends until end of line. The second form is a {\it comment
25.456 +sequence}, which is a sequence of any characters enclosed within
25.457 +{\tt/*} and {\tt*/}.
25.458 +
25.459 +\medskip
25.460 +
25.461 +\noindent{\bf Examples}
25.462 +
25.463 +\medskip
25.464 +
25.465 +\noindent\verb|param n := 10; # This is a comment|
25.466 +
25.467 +\noindent\verb|/* This is another comment */|
25.468 +
25.469 +\medskip
25.470 +
25.471 +Comments are ignored by the model translator and can appear anywhere in
25.472 +the model description, where white-space characters are allowed.
25.473 +
25.474 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
25.475 +
25.476 +\newpage
25.477 +
25.478 +\section{Expressions}
25.479 +
25.480 +An {\it expression} is a rule for computing a value. In model
25.481 +description expressions are used as constituents of certain statements.
25.482 +
25.483 +In general case expressions consist of operands and operators.
25.484 +
25.485 +Depending on the type of the resultant value all expressions fall into
25.486 +the following categories:
25.487 +
25.488 +\begin{itemize}
25.489 +\item numeric expressions;
25.490 +\item symbolic expressions;
25.491 +\item indexing expressions;
25.492 +\item set expressions;
25.493 +\item logical expressions;
25.494 +\item linear expressions.
25.495 +\end{itemize}
25.496 +
25.497 +\subsection{Numeric expressions}
25.498 +
25.499 +A {\it numeric expression} is a rule for computing a single numeric
25.500 +value represented as a floating-point number.
25.501 +
25.502 +The primary numeric expression may be a numeric literal, dummy index,
25.503 +unsubscripted parameter, subscripted parameter, built-in function
25.504 +reference, iterated numeric expression, conditional numeric expression,
25.505 +or another numeric expression enclosed in parentheses.
25.506 +
25.507 +\medskip
25.508 +
25.509 +\noindent{\bf Examples}
25.510 +
25.511 +\medskip
25.512 +
25.513 +\noindent
25.514 +\begin{tabular}{@{}ll@{}}
25.515 +\verb|1.23|&(numeric literal)\\
25.516 +\verb|j|&(dummy index)\\
25.517 +\verb|time|&(unsubscripted parameter)\\
25.518 +\verb|a['May 2003',j+1]|&(subscripted parameter)\\
25.519 +\verb|abs(b[i,j])|&(function reference)\\
25.520 +\verb|sum{i in S diff T} alpha[i] * b[i,j]|&(iterated expression)\\
25.521 +\verb|if i in I then 2 * p else q[i+1]|&(conditional expression)\\
25.522 +\verb|(b[i,j] + .5 * c)|&(parenthesized expression)\\
25.523 +\end{tabular}
25.524 +
25.525 +\medskip
25.526 +
25.527 +More general numeric expressions containing two or more primary numeric
25.528 +expressions may be constructed by using certain arithmetic operators.
25.529 +
25.530 +\medskip
25.531 +
25.532 +\noindent{\bf Examples}
25.533 +
25.534 +\medskip
25.535 +
25.536 +\noindent\verb|j+1|
25.537 +
25.538 +\noindent\verb|2 * a[i-1,j+1] - b[i,j]|
25.539 +
25.540 +\noindent\verb|sum{j in J} a[i,j] * x[j] + sum{k in K} b[i,k] * x[k]|
25.541 +
25.542 +\noindent\verb|(if i in I then 2 * p else q[i+1]) / (a[i,j] + 1.5)|
25.543 +
25.544 +\subsubsection{Numeric literals}
25.545 +
25.546 +If the primary numeric expression is a numeric literal, the resultant
25.547 +value is obvious.
25.548 +
25.549 +\subsubsection{Dummy indices}
25.550 +
25.551 +If the primary numeric expression is a dummy index, the resultant value
25.552 +is current value assigned to that dummy index.
25.553 +
25.554 +\subsubsection{Unsubscripted parameters}
25.555 +
25.556 +If the primary numeric expression is an unsubscripted parameter (which
25.557 +must be 0-dimensional), the resultant value is the value of that
25.558 +parameter.
25.559 +
25.560 +\subsubsection{Subscripted parameters}
25.561 +
25.562 +The primary numeric expression, which refers to a subscripted parameter,
25.563 +has the following syntactic form:
25.564 +
25.565 +\medskip
25.566 +
25.567 +\noindent\hfil
25.568 +{\it name}{\tt[}$i_1${\tt,} $i_2${\tt,} \dots{\tt,} $i_n${\tt]}
25.569 +
25.570 +\medskip
25.571 +
25.572 +\noindent where {\it name} is the symbolic name of the parameter,
25.573 +$i_1$, $i_2$, \dots, $i_n$ are subscripts.
25.574 +
25.575 +Each subscript must be a numeric or symbolic expression. The number of
25.576 +subscripts in the subscript list must be the same as the dimension of
25.577 +the parameter with which the subscript list is associated.
25.578 +
25.579 +Actual values of subscript expressions are used to identify
25.580 +a particular member of the parameter that determines the resultant
25.581 +value of the primary expression.
25.582 +
25.583 +\subsubsection{Function references}
25.584 +
25.585 +In MathProg there exist the following built-in functions which may be
25.586 +used in numeric expressions:
25.587 +
25.588 +\medskip
25.589 +
25.590 +\begin{tabular}{@{}p{96pt}p{222pt}@{}}
25.591 +{\tt abs(}$x${\tt)}&$|x|$, absolute value of $x$\\
25.592 +{\tt atan(}$x${\tt)}&$\arctan x$, principal value of the arc tangent of
25.593 +$x$ (in radians)\\
25.594 +{\tt atan(}$y${\tt,} $x${\tt)}&$\arctan y/x$, principal value of the
25.595 +arc tangent of $y/x$ (in radians). In this case the signs of both
25.596 +arguments $y$ and $x$ are used to determine the quadrant of the
25.597 +resultant value\\
25.598 +{\tt card(}$X${\tt)}&$|X|$, cardinality (the number of elements) of
25.599 +set $X$\\
25.600 +{\tt ceil(}$x${\tt)}&$\lceil x\rceil$, smallest integer not less than
25.601 +$x$ (``ceiling of $x$'')\\
25.602 +{\tt cos(}$x${\tt)}&$\cos x$, cosine of $x$ (in radians)\\
25.603 +{\tt exp(}$x${\tt)}&$e^x$, base-$e$ exponential of $x$\\
25.604 +{\tt floor(}$x${\tt)}&$\lfloor x\rfloor$, largest integer not greater
25.605 +than $x$ (``floor of $x$'')\\
25.606 +\end{tabular}
25.607 +
25.608 +\begin{tabular}{@{}p{96pt}p{222pt}@{}}
25.609 +{\tt gmtime()}&the number of seconds elapsed since 00:00:00~Jan~1, 1970,
25.610 +Coordinated Universal Time (for details see Subsection \ref{gmtime},
25.611 +page \pageref{gmtime})\\
25.612 +{\tt length(}$s${\tt)}&$|s|$, length of character string $s$\\
25.613 +{\tt log(}$x${\tt)}&$\log x$, natural logarithm of $x$\\
25.614 +{\tt log10(}$x${\tt)}&$\log_{10}x$, common (decimal) logarithm of $x$\\
25.615 +{\tt max(}$x_1${\tt,} $x_2${\tt,} \dots{\tt,} $x_n${\tt)}&the largest
25.616 +of values $x_1$, $x_2$, \dots, $x_n$\\
25.617 +{\tt min(}$x_1${\tt,} $x_2${\tt,} \dots{\tt,} $x_n${\tt)}&the smallest
25.618 +of values $x_1$, $x_2$, \dots, $x_n$\\
25.619 +{\tt round(}$x${\tt)}&rounding $x$ to nearest integer\\
25.620 +{\tt round(}$x${\tt,} $n${\tt)}&rounding $x$ to $n$ fractional decimal
25.621 +digits\\
25.622 +{\tt sin(}$x${\tt)}&$\sin x$, sine of $x$ (in radians)\\
25.623 +{\tt sqrt(}$x${\tt)}&$\sqrt{x}$, non-negative square root of $x$\\
25.624 +{\tt str2time(}$s${\tt,} $f${\tt)}&converting character string $s$ to
25.625 +calendar time (for details see Subsection \ref{str2time}, page
25.626 +\pageref{str2time})\\
25.627 +{\tt trunc(}$x${\tt)}&truncating $x$ to nearest integer\\
25.628 +{\tt trunc(}$x${\tt,} $n${\tt)}&truncating $x$ to $n$ fractional
25.629 +decimal digits\\
25.630 +{\tt Irand224()}&generating pseudo-random integer uniformly distributed
25.631 +in $[0,2^{24})$\\
25.632 +{\tt Uniform01()}&generating pseudo-random number uniformly distributed
25.633 +in $[0,1)$\\
25.634 +{\tt Uniform(}$a${\tt,} $b${\tt)}&generating pseudo-random number
25.635 +uniformly distributed in $[a,b)$\\
25.636 +{\tt Normal01()}&generating Gaussian pseudo-random variate with
25.637 +$\mu=0$ and $\sigma=1$\\
25.638 +{\tt Normal(}$\mu${\tt,} $\sigma${\tt)}&generating Gaussian
25.639 +pseudo-random variate with given $\mu$ and $\sigma$\\
25.640 +\end{tabular}
25.641 +
25.642 +\medskip
25.643 +
25.644 +Arguments of all built-in functions, except {\tt card}, {\tt length},
25.645 +and {\tt str2time}, must be numeric expressions. The argument of
25.646 +{\tt card} must be a set expression. The argument of {\tt length} and
25.647 +both arguments of {\tt str2time} must be symbolic expressions.
25.648 +
25.649 +The resultant value of the numeric expression, which is a function
25.650 +reference, is the result of applying the function to its argument(s).
25.651 +
25.652 +Note that each pseudo-random generator function has a latent argument
25.653 +(i.e. some internal state), which is changed whenever the function has
25.654 +been applied. Thus, if the function is applied repeatedly even to
25.655 +identical arguments, due to the side effect different resultant values
25.656 +are always produced.
25.657 +
25.658 +\subsubsection{Iterated expressions}
25.659 +\label{itexpr}
25.660 +
25.661 +An {\it iterated numeric expression} is a primary numeric expression,
25.662 +which has the following syntactic form:
25.663 +
25.664 +\medskip
25.665 +
25.666 +\noindent\hfil
25.667 +{\it iterated-operator indexing-expression integrand}
25.668 +
25.669 +\medskip
25.670 +
25.671 +\noindent where {\it iterated-operator} is the symbolic name of the
25.672 +iterated operator to be performed (see below), {\it indexing-expression}
25.673 +is an indexing expression which introduces dummy indices and controls
25.674 +iterating, {\it integrand} is a numeric expression that participates in
25.675 +the operation.
25.676 +
25.677 +In MathProg there exist four iterated operators, which may be used in
25.678 +numeric expressions:
25.679 +
25.680 +\medskip
25.681 +
25.682 +\noindent\hfil
25.683 +\begin{tabular}{@{}lll@{}}
25.684 +{\tt sum}&summation&$\displaystyle\sum_{(i_1,\dots,i_n)\in\Delta}
25.685 +f(i_1,\dots,i_n)$\\
25.686 +{\tt prod}&production&$\displaystyle\prod_{(i_1,\dots,i_n)\in\Delta}
25.687 +f(i_1,\dots,i_n)$\\
25.688 +{\tt min}&minimum&$\displaystyle\min_{(i_1,\dots,i_n)\in\Delta}
25.689 +f(i_1,\dots,i_n)$\\
25.690 +{\tt max}&maximum&$\displaystyle\max_{(i_1,\dots,i_n)\in\Delta}
25.691 +f(i_1,\dots,i_n)$\\
25.692 +\end{tabular}
25.693 +
25.694 +\medskip
25.695 +
25.696 +\noindent where $i_1$, \dots, $i_n$ are dummy indices introduced in
25.697 +the indexing expression, $\Delta$ is the domain, a set of $n$-tuples
25.698 +specified by the indexing expression which defines particular values
25.699 +assigned to the dummy indices on performing the iterated operation,
25.700 +$f(i_1,\dots,i_n)$ is the integrand, a numeric expression whose
25.701 +resultant value depends on the dummy indices.
25.702 +
25.703 +The resultant value of an iterated numeric expression is the result of
25.704 +applying of the iterated operator to its integrand over all $n$-tuples
25.705 +contained in the domain.
25.706 +
25.707 +\subsubsection{Conditional expressions}
25.708 +\label{ifthen}
25.709 +
25.710 +A {\it conditional numeric expression} is a primary numeric expression,
25.711 +which has one of the following two syntactic forms:
25.712 +
25.713 +\medskip
25.714 +
25.715 +\noindent\hfil
25.716 +{\tt if} $b$ {\tt then} $x$ {\tt else} $y$
25.717 +
25.718 +\medskip
25.719 +
25.720 +\noindent\hspace{126.5pt}
25.721 +{\tt if} $b$ {\tt then} $x$
25.722 +
25.723 +\medskip
25.724 +
25.725 +\noindent where $b$ is an logical expression, $x$ and $y$ are numeric
25.726 +expressions.
25.727 +
25.728 +The resultant value of the conditional expression depends on the value
25.729 +of the logical expression that follows the keyword {\tt if}. If it
25.730 +takes on the value {\it true}, the value of the conditional expression
25.731 +is the value of the expression that follows the keyword {\tt then}.
25.732 +Otherwise, if the logical expression takes on the value {\it false},
25.733 +the value of the conditional expression is the value of the expression
25.734 +that follows the keyword {\it else}. If the second, reduced form of the
25.735 +conditional expression is used and the logical expression takes on the
25.736 +value {\it false}, the resultant value of the conditional expression is
25.737 +zero.
25.738 +
25.739 +\subsubsection{Parenthesized expressions}
25.740 +
25.741 +Any numeric expression may be enclosed in parentheses that
25.742 +syntactically makes it a primary numeric expression.
25.743 +
25.744 +Parentheses may be used in numeric expressions, as in algebra, to
25.745 +specify the desired order in which operations are to be performed.
25.746 +Where parentheses are used, the expression within the parentheses is
25.747 +evaluated before the resultant value is used.
25.748 +
25.749 +The resultant value of the parenthesized expression is the same as the
25.750 +value of the expression enclosed within parentheses.
25.751 +
25.752 +\subsubsection{Arithmetic operators}
25.753 +
25.754 +In MathProg there exist the following arithmetic operators, which may
25.755 +be used in numeric expressions:
25.756 +
25.757 +\medskip
25.758 +
25.759 +\begin{tabular}{@{}p{96pt}p{222pt}@{}}
25.760 +{\tt +} $x$&unary plus\\
25.761 +{\tt -} $x$&unary minus\\
25.762 +$x$ {\tt +} $y$&addition\\
25.763 +$x$ {\tt -} $y$&subtraction\\
25.764 +$x$ {\tt less} $y$&positive difference (if $x<y$ then 0 else $x-y$)\\
25.765 +$x$ {\tt *} $y$&multiplication\\
25.766 +$x$ {\tt /} $y$&division\\
25.767 +$x$ {\tt div} $y$"ient of exact division\\
25.768 +$x$ {\tt mod} $y$&remainder of exact division\\
25.769 +$x$ {\tt **} $y$, $x$ {\tt\textasciicircum} $y$&exponentiation (raising
25.770 +to power)\\
25.771 +\end{tabular}
25.772 +
25.773 +\medskip
25.774 +
25.775 +\noindent where $x$ and $y$ are numeric expressions.
25.776 +
25.777 +If the expression includes more than one arithmetic operator, all
25.778 +operators are performed from left to right according to the hierarchy
25.779 +of operations (see below) with the only exception that the
25.780 +exponentiaion operators are performed from right to left.
25.781 +
25.782 +The resultant value of the expression, which contains arithmetic
25.783 +operators, is the result of applying the operators to their operands.
25.784 +
25.785 +\subsubsection{Hierarchy of operations}
25.786 +\label{hierarchy}
25.787 +
25.788 +The following list shows the hierarchy of operations in numeric
25.789 +expressions:
25.790 +
25.791 +\medskip
25.792 +
25.793 +\noindent\hfil
25.794 +\begin{tabular}{@{}ll@{}}
25.795 +Operation&Hierarchy\\
25.796 +\hline
25.797 +Evaluation of functions ({\tt abs}, {\tt ceil}, etc.)&1st\\
25.798 +Exponentiation ({\tt**}, {\tt\textasciicircum})&2nd\\
25.799 +Unary plus and minus ({\tt+}, {\tt-})&3rd\\
25.800 +Multiplication and division ({\tt*}, {\tt/}, {\tt div}, {\tt mod})&4th\\
25.801 +Iterated operations ({\tt sum}, {\tt prod}, {\tt min}, {\tt max})&5th\\
25.802 +Addition and subtraction ({\tt+}, {\tt-}, {\tt less})&6th\\
25.803 +Conditional evaluation ({\tt if} \dots {\tt then} \dots {\tt else})&
25.804 +7th\\
25.805 +\end{tabular}
25.806 +
25.807 +\medskip
25.808 +
25.809 +This hierarchy is used to determine which of two consecutive operations
25.810 +is performed first. If the first operator is higher than or equal to
25.811 +the second, the first operation is performed. If it is not, the second
25.812 +operator is compared to the third, etc. When the end of the expression
25.813 +is reached, all of the remaining operations are performed in the
25.814 +reverse order.
25.815 +
25.816 +\newpage
25.817 +
25.818 +\subsection{Symbolic expressions}
25.819 +
25.820 +A {\it symbolic expression} is a rule for computing a single symbolic
25.821 +value represented as a character string.
25.822 +
25.823 +The primary symbolic expression may be a string literal, dummy index,
25.824 +unsubscripted parameter, subscripted parameter, built-in function
25.825 +reference, conditional symbolic expression, or another symbolic
25.826 +expression enclosed in parentheses.
25.827 +
25.828 +It is also allowed to use a numeric expression as the primary symbolic
25.829 +expression, in which case the resultant value of the numeric expression
25.830 +is automatically converted to the symbolic type.
25.831 +
25.832 +\medskip
25.833 +
25.834 +\noindent{\bf Examples}
25.835 +
25.836 +\medskip
25.837 +
25.838 +\noindent
25.839 +\begin{tabular}{@{}ll@{}}
25.840 +\verb|'May 2003'|&(string literal)\\
25.841 +\verb|j|&(dummy index)\\
25.842 +\verb|p|&(unsubscripted parameter)\\
25.843 +\verb|s['abc',j+1]|&(subscripted parameter)\\
25.844 +\verb|substr(name[i],k+1,3)|&(function reference)\\
25.845 +\verb|if i in I then s[i,j] else t[i+1]|&(conditional expression)\\
25.846 +\verb|((10 * b[i,j]) & '.bis')|&(parenthesized expression)\\
25.847 +\end{tabular}
25.848 +
25.849 +\medskip
25.850 +
25.851 +More general symbolic expressions containing two or more primary
25.852 +symbolic expressions may be constructed by using the concatenation
25.853 +operator.
25.854 +
25.855 +\medskip
25.856 +
25.857 +\noindent{\bf Examples}
25.858 +
25.859 +\medskip
25.860 +
25.861 +\noindent\verb|'abc[' & i & ',' & j & ']'|
25.862 +
25.863 +\noindent\verb|"from " & city[i] & " to " & city[j]|
25.864 +
25.865 +\medskip
25.866 +
25.867 +The principles of evaluation of symbolic expressions are completely
25.868 +analogous to the ones given for numeric expressions (see above).
25.869 +
25.870 +\subsubsection{Function references}
25.871 +
25.872 +In MathProg there exist the following built-in functions which may be
25.873 +used in symbolic expressions:
25.874 +
25.875 +\medskip
25.876 +
25.877 +\begin{tabular}{@{}p{96pt}p{222pt}@{}}
25.878 +{\tt substr(}$s${\tt,} $x${\tt)}&substring of $s$ starting from
25.879 +position $x$\\
25.880 +{\tt substr(}$s${\tt,} $x${\tt,} $y${\tt)}&substring of $s$ starting
25.881 +from position $x$ and having length $y$\\
25.882 +{\tt time2str(}$t${\tt,} $f${\tt)}&converting calendar time to
25.883 +character string (for details see Subsection \ref{time2str}, page
25.884 +\pageref{time2str})\\
25.885 +\end{tabular}
25.886 +
25.887 +\medskip
25.888 +
25.889 +The first argument of {\tt substr} must be a symbolic expression while
25.890 +its second and optional third arguments must be numeric expressions.
25.891 +
25.892 +The first argument of {\tt time2str} must be a numeric expression, and
25.893 +its second argument must be a symbolic expression.
25.894 +
25.895 +The resultant value of the symbolic expression, which is a function
25.896 +reference, is the result of applying the function to its arguments.
25.897 +
25.898 +\subsubsection{Symbolic operators}
25.899 +
25.900 +Currently in MathProg there exists the only symbolic operator:
25.901 +
25.902 +\medskip
25.903 +
25.904 +\noindent\hfil
25.905 +{\tt s \& t}
25.906 +
25.907 +\medskip
25.908 +
25.909 +\noindent where $s$ and $t$ are symbolic expressions. This operator
25.910 +means concatenation of its two symbolic operands, which are character
25.911 +strings.
25.912 +
25.913 +\subsubsection{Hierarchy of operations}
25.914 +
25.915 +The following list shows the hierarchy of operations in symbolic
25.916 +expressions:
25.917 +
25.918 +\medskip
25.919 +
25.920 +\noindent\hfil
25.921 +\begin{tabular}{@{}ll@{}}
25.922 +Operation&Hierarchy\\
25.923 +\hline
25.924 +Evaluation of numeric operations&1st-7th\\
25.925 +Concatenation ({\tt\&})&8th\\
25.926 +Conditional evaluation ({\tt if} \dots {\tt then} \dots {\tt else})&
25.927 +7th\\
25.928 +\end{tabular}
25.929 +
25.930 +\medskip
25.931 +
25.932 +This hierarchy has the same meaning as was explained above for numeric
25.933 +expressions (see Subsection \ref{hierarchy}, page \pageref{hierarchy}).
25.934 +
25.935 +\subsection{Indexing expressions and dummy indices}
25.936 +\label{indexing}
25.937 +
25.938 +An {\it indexing expression} is an auxiliary construction, which
25.939 +specifies a plain set of $n$-tuples and introduces dummy indices. It
25.940 +has two syntactic forms:
25.941 +
25.942 +\medskip
25.943 +
25.944 +\noindent\hspace{73.5pt}
25.945 +{\tt\{} {\it entry}$_1${\tt,} {\it entry}$_2${\tt,} \dots{\tt,}
25.946 +{\it entry}$_m$ {\tt\}}
25.947 +
25.948 +\medskip
25.949 +
25.950 +\noindent\hfil
25.951 +{\tt\{} {\it entry}$_1${\tt,} {\it entry}$_2${\tt,} \dots{\tt,}
25.952 +{\it entry}$_m$ {\tt:} {\it predicate} {\tt\}}
25.953 +
25.954 +\medskip
25.955 +
25.956 +\noindent where {\it entry}{$_1$}, {\it entry}{$_2$}, \dots,
25.957 +{\it entry}{$_m$} are indexing entries, {\it predicate} is a logical
25.958 +expression that specifies an optional predicate (logical condition).
25.959 +
25.960 +Each {\it indexing entry} in the indexing expression has one of the
25.961 +following three forms:
25.962 +
25.963 +\medskip
25.964 +
25.965 +\noindent\hspace{123pt}
25.966 +$i$ {\tt in} $S$
25.967 +
25.968 +\medskip
25.969 +
25.970 +\noindent\hfil
25.971 +{\tt(}$i_1${\tt,} $i_2${\tt,} \dots{\tt,}$i_n${\tt)} {\tt in} $S$
25.972 +
25.973 +\medskip
25.974 +
25.975 +\noindent\hspace{123pt}
25.976 +$S$
25.977 +
25.978 +\medskip
25.979 +
25.980 +\noindent where $i_1$, $i_2$, \dots, $i_n$ are indices, $S$ is a set
25.981 +expression (discussed in the next section) that specifies the basic set.
25.982 +
25.983 +The number of indices in the indexing entry must be the same as the
25.984 +dimension of the basic set $S$, i.e. if $S$ consists of 1-tuples, the
25.985 +first form must be used, and if $S$ consists of $n$-tuples, where
25.986 +$n>1$, the second form must be used.
25.987 +
25.988 +If the first form of the indexing entry is used, the index $i$ can be
25.989 +a dummy index only (see below). If the second form is used, the indices
25.990 +$i_1$, $i_2$, \dots, $i_n$ can be either dummy indices or some numeric
25.991 +or symbolic expressions, where at least one index must be a dummy index.
25.992 +The third, reduced form of the indexing entry has the same effect as if
25.993 +there were $i$ (if $S$ is 1-dimensional) or $i_1$, $i_2$, \dots, $i_n$
25.994 +(if $S$ is $n$-dimensional) all specified as dummy indices.
25.995 +
25.996 +A {\it dummy index} is an auxiliary model object, which acts like an
25.997 +individual variable. Values assigned to dummy indices are components of
25.998 +$n$-tuples from basic sets, i.e. some numeric and symbolic quantities.
25.999 +
25.1000 +For referencing purposes dummy indices can be provided with symbolic
25.1001 +names. However, unlike other model objects (sets, parameters, etc.)
25.1002 +dummy indices need not be explicitly declared. Each {\it undeclared}
25.1003 +symbolic name being used in the indexing position of an indexing entry
25.1004 +is recognized as the symbolic name of corresponding dummy index.
25.1005 +
25.1006 +Symbolic names of dummy indices are valid only within the scope of the
25.1007 +indexing expression, where the dummy indices were introduced. Beyond
25.1008 +the scope the dummy indices are completely inaccessible, so the same
25.1009 +symbolic names may be used for other purposes, in particular, to
25.1010 +represent dummy indices in other indexing expressions.
25.1011 +
25.1012 +The scope of indexing expression, where implicit declarations of dummy
25.1013 +indices are valid, depends on the context, in which the indexing
25.1014 +expression is used:
25.1015 +
25.1016 +\begin{enumerate}
25.1017 +\item If the indexing expression is used in iterated operator, its
25.1018 +scope extends until the end of the integrand.
25.1019 +\item If the indexing expression is used as a primary set expression,
25.1020 +its scope extends until the end of that indexing expression.
25.1021 +\item If the indexing expression is used to define the subscript domain
25.1022 +in declarations of some model objects, its scope extends until the end
25.1023 +of the corresponding statement.
25.1024 +\end{enumerate}
25.1025 +
25.1026 +The indexing mechanism implemented by means of indexing expressions is
25.1027 +best explained by some examples discussed below.
25.1028 +
25.1029 +Let there be given three sets:
25.1030 +
25.1031 +\medskip
25.1032 +
25.1033 +\noindent\hspace{33.5pt}
25.1034 +$A=\{4,7,9\}$,
25.1035 +
25.1036 +\medskip
25.1037 +
25.1038 +\noindent\hfil
25.1039 +$B=\{(1,Jan),(1,Feb),(2,Mar),(2,Apr),(3,May),(3,Jun)\}$,
25.1040 +
25.1041 +\medskip
25.1042 +
25.1043 +\noindent\hspace{33.5pt}
25.1044 +$C=\{a,b,c\}$,
25.1045 +
25.1046 +\medskip
25.1047 +
25.1048 +\noindent where $A$ and $C$ consist of 1-tuples (singlets), $B$
25.1049 +consists of 2-tuples (doublets). Consider the following indexing
25.1050 +expression:
25.1051 +
25.1052 +\medskip
25.1053 +
25.1054 +\noindent\hfil
25.1055 +{\tt\{i in A, (j,k) in B, l in C\}}
25.1056 +
25.1057 +\medskip
25.1058 +
25.1059 +\noindent where {\tt i}, {\tt j}, {\tt k}, and {\tt l} are dummy
25.1060 +indices.
25.1061 +
25.1062 +Although MathProg is not a procedural language, for any indexing
25.1063 +expression an equivalent algorithmic description can be given. In
25.1064 +particular, the algorithmic description of the indexing expression
25.1065 +above could look like follows:
25.1066 +
25.1067 +\medskip
25.1068 +
25.1069 +\noindent\hfil
25.1070 +\begin{tabular}{@{}l@{}}
25.1071 +{\bf for all} $i\in A$ {\bf do}\\
25.1072 +\hspace{12pt}{\bf for all} $(j,k)\in B$ {\bf do}\\
25.1073 +\hspace{24pt}{\bf for all} $l\in C$ {\bf do}\\
25.1074 +\hspace{36pt}{\it action};\\
25.1075 +\end{tabular}
25.1076 +
25.1077 +\newpage
25.1078 +
25.1079 +\noindent where the dummy indices $i$, $j$, $k$, $l$ are consecutively
25.1080 +assigned corresponding components of $n$-tuples from the basic sets $A$,
25.1081 +$B$, $C$, and {\it action} is some action that depends on the context,
25.1082 +where the indexing expression is used. For example, if the action were
25.1083 +printing current values of dummy indices, the printout would look like
25.1084 +follows:
25.1085 +
25.1086 +\medskip
25.1087 +
25.1088 +\noindent\hfil
25.1089 +\begin{tabular}{@{}llll@{}}
25.1090 +$i=4$&$j=1$&$k=Jan$&$l=a$\\
25.1091 +$i=4$&$j=1$&$k=Jan$&$l=b$\\
25.1092 +$i=4$&$j=1$&$k=Jan$&$l=c$\\
25.1093 +$i=4$&$j=1$&$k=Feb$&$l=a$\\
25.1094 +$i=4$&$j=1$&$k=Feb$&$l=b$\\
25.1095 +\multicolumn{4}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}\\
25.1096 +$i=9$&$j=3$&$k=Jun$&$l=b$\\
25.1097 +$i=9$&$j=3$&$k=Jun$&$l=c$\\
25.1098 +\end{tabular}
25.1099 +
25.1100 +\medskip
25.1101 +
25.1102 +Let the example indexing expression be used in the following iterated
25.1103 +operation:
25.1104 +
25.1105 +\medskip
25.1106 +
25.1107 +\noindent\hfil
25.1108 +{\tt sum\{i in A, (j,k) in B, l in C\} p[i,j,k,l]}
25.1109 +
25.1110 +\medskip
25.1111 +
25.1112 +\noindent where {\tt p} is a 4-dimensional numeric parameter or some
25.1113 +numeric expression whose resultant value depends on {\tt i}, {\tt j},
25.1114 +{\tt k}, and {\tt l}. In this case the action is summation, so the
25.1115 +resultant value of the primary numeric expression is:
25.1116 +$$\sum_{i\in A,(j,k)\in B,l\in C}(p_{ijkl}).$$
25.1117 +
25.1118 +Now let the example indexing expression be used as a primary set
25.1119 +expression. In this case the action is gathering all 4-tuples
25.1120 +(quadruplets) of the form $(i,j,k,l)$ in one set, so the resultant
25.1121 +value of such operation is simply the Cartesian product of the basic
25.1122 +sets:
25.1123 +$$A\times B\times C=\{(i,j,k,l):i\in A,(j,k)\in B,l\in C\}.$$
25.1124 +Note that in this case the same indexing expression might be written in
25.1125 +the reduced form:
25.1126 +
25.1127 +\medskip
25.1128 +
25.1129 +\noindent\hfil
25.1130 +{\tt\{A, B, C\}}
25.1131 +
25.1132 +\medskip
25.1133 +
25.1134 +\noindent because the dummy indices $i$, $j$, $k$, and $l$ are not
25.1135 +referenced and therefore their symbolic names need not be specified.
25.1136 +
25.1137 +Finally, let the example indexing expression be used as the subscript
25.1138 +domain in the declaration of a 4-dimensional model object, say,
25.1139 +a numeric parameter:
25.1140 +
25.1141 +\medskip
25.1142 +
25.1143 +\noindent\hfil
25.1144 +{\tt param p\{i in A, (j,k) in B, l in C\}} \dots {\tt;}
25.1145 +
25.1146 +\medskip
25.1147 +
25.1148 +\noindent In this case the action is generating the parameter members,
25.1149 +where each member has the form $p[i,j,k,l]$.
25.1150 +
25.1151 +As was said above, some indices in the second form of indexing entries
25.1152 +may be numeric or symbolic expressions, not only dummy indices. In this
25.1153 +case resultant values of such expressions play role of some logical
25.1154 +conditions to select only that $n$-tuples from the Cartesian product of
25.1155 +basic sets that satisfy these conditions.
25.1156 +
25.1157 +Consider, for example, the following indexing expression:
25.1158 +
25.1159 +\medskip
25.1160 +
25.1161 +\noindent\hfil
25.1162 +{\tt\{i in A, (i-1,k) in B, l in C\}}
25.1163 +
25.1164 +\medskip
25.1165 +
25.1166 +\noindent where {\tt i}, {\tt k}, {\tt l} are dummy indices, and
25.1167 +{\tt i-1} is a numeric expression. The algorithmic decsription of this
25.1168 +indexing expression is the following:
25.1169 +
25.1170 +\medskip
25.1171 +
25.1172 +\noindent\hfil
25.1173 +\begin{tabular}{@{}l@{}}
25.1174 +{\bf for all} $i\in A$ {\bf do}\\
25.1175 +\hspace{12pt}{\bf for all} $(j,k)\in B$ {\bf and} $j=i-1$ {\bf do}\\
25.1176 +\hspace{24pt}{\bf for all} $l\in C$ {\bf do}\\
25.1177 +\hspace{36pt}{\it action};\\
25.1178 +\end{tabular}
25.1179 +
25.1180 +\medskip
25.1181 +
25.1182 +\noindent Thus, if this indexing expression were used as a primary set
25.1183 +expression, the resultant set would be the following:
25.1184 +$$\{(4,May,a),(4,May,b),(4,May,c),(4,Jun,a),(4,Jun,b),(4,Jun,c)\}.$$
25.1185 +Should note that in this case the resultant set consists of 3-tuples,
25.1186 +not of 4-tuples, because in the indexing expression there is no dummy
25.1187 +index that corresponds to the first component of 2-tuples from the set
25.1188 +$B$.
25.1189 +
25.1190 +The general rule is: the number of components of $n$-tuples defined by
25.1191 +an indexing expression is the same as the number of dummy indices in
25.1192 +that expression, where the correspondence between dummy indices and
25.1193 +components on $n$-tuples in the resultant set is positional, i.e. the
25.1194 +first dummy index corresponds to the first component, the second dummy
25.1195 +index corresponds to the second component, etc.
25.1196 +
25.1197 +In some cases it is needed to select a subset from the Cartesian
25.1198 +product of some sets. This may be attained by using an optional logical
25.1199 +predicate, which is specified in the indexing expression.
25.1200 +
25.1201 +Consider, for example, the following indexing expression:
25.1202 +
25.1203 +\medskip
25.1204 +
25.1205 +\noindent\hfil
25.1206 +{\tt\{i in A, (j,k) in B, l in C: i <= 5 and k <> 'Mar'\}}
25.1207 +
25.1208 +\medskip
25.1209 +
25.1210 +\noindent where the logical expression following the colon is a
25.1211 +predicate. The algorithmic description of this indexing expression is
25.1212 +the following:
25.1213 +
25.1214 +\medskip
25.1215 +
25.1216 +\noindent\hfil
25.1217 +\begin{tabular}{@{}l@{}}
25.1218 +{\bf for all} $i\in A$ {\bf do}\\
25.1219 +\hspace{12pt}{\bf for all} $(j,k)\in B$ {\bf do}\\
25.1220 +\hspace{24pt}{\bf for all} $l\in C$ {\bf do}\\
25.1221 +\hspace{36pt}{\bf if} $i\leq 5$ {\bf and} $l\neq`Mar'$ {\bf then}\\
25.1222 +\hspace{48pt}{\it action};\\
25.1223 +\end{tabular}
25.1224 +
25.1225 +\medskip
25.1226 +
25.1227 +\noindent Thus, if this indexing expression were used as a primary set
25.1228 +expression, the resultant set would be the following:
25.1229 +$$\{(4,1,Jan,a),(4,1,Feb,a),(4,2,Apr,a),\dots,(4,3,Jun,c)\}.$$
25.1230 +
25.1231 +If no predicate is specified in the indexing expression, one, which
25.1232 +takes on the value {\it true}, is assumed.
25.1233 +
25.1234 +\subsection{Set expressions}
25.1235 +
25.1236 +A {\it set expression} is a rule for computing an elemental set, i.e.
25.1237 +a collection of $n$-tuples, where components of $n$-tuples are numeric
25.1238 +and symbolic quantities.
25.1239 +
25.1240 +The primary set expression may be a literal set, unsubscripted set,
25.1241 +subscripted set, ``arithmetic'' set, indexing expression, iterated set
25.1242 +expression, conditional set expression, or another set expression
25.1243 +enclosed in parentheses.
25.1244 +
25.1245 +\medskip
25.1246 +
25.1247 +\noindent{\bf Examples}
25.1248 +
25.1249 +\medskip
25.1250 +
25.1251 +\noindent
25.1252 +\begin{tabular}{@{}ll@{}}
25.1253 +\verb|{(123,'aa'), (i,'bb'), (j-1,'cc')}|&(literal set)\\
25.1254 +\verb|I|&(unsubscripted set)\\
25.1255 +\verb|S[i-1,j+1]|&(subscripted set)\\
25.1256 +\verb|1..t-1 by 2|&(``arithmetic'' set)\\
25.1257 +\verb|{t in 1..T, (t+1,j) in S: (t,j) in F}|&(indexing expression)\\
25.1258 +\verb|setof{i in I, j in J}(i+1,j-1)|&(iterated expression)\\
25.1259 +\verb|if i < j then S[i] else F diff S[j]|&(conditional expression)\\
25.1260 +\verb|(1..10 union 21..30)|&(parenthesized expression)\\
25.1261 +\end{tabular}
25.1262 +
25.1263 +\medskip
25.1264 +
25.1265 +More general set expressions containing two or more primary set
25.1266 +expressions may be constructed by using certain set operators.
25.1267 +
25.1268 +\medskip
25.1269 +
25.1270 +\noindent{\bf Examples}
25.1271 +
25.1272 +\medskip
25.1273 +
25.1274 +\noindent\verb|(A union B) inter (I cross J)|
25.1275 +
25.1276 +\noindent
25.1277 +\verb|1..10 cross (if i < j then {'a', 'b', 'c'} else {'d', 'e', 'f'})|
25.1278 +
25.1279 +\subsubsection{Literal sets}
25.1280 +
25.1281 +A {\it literal set} is a primary set expression, which has the
25.1282 +following two syntactic forms:
25.1283 +
25.1284 +\medskip
25.1285 +
25.1286 +\noindent\hspace{39pt}
25.1287 +{\tt\{}$e_1${\tt,} $e_2${\tt,} \dots{\tt,} $e_m${\tt\}}
25.1288 +
25.1289 +\medskip
25.1290 +
25.1291 +\noindent\hfil
25.1292 +{\tt\{(}$e_{11}${\tt,} \dots{\tt,} $e_{1n}${\tt),}
25.1293 +{\tt(}$e_{21}${\tt,} \dots{\tt,} $e_{2n}${\tt),} \dots{\tt,}
25.1294 +{\tt(}$e_{m1}${\tt,} \dots{\tt,} $e_{mn}${\tt)\}}
25.1295 +
25.1296 +\medskip
25.1297 +
25.1298 +\noindent where $e_1$, \dots, $e_m$, $e_{11}$, \dots, $e_{mn}$ are
25.1299 +numeric or symbolic expressions.
25.1300 +
25.1301 +If the first form is used, the resultant set consists of 1-tuples
25.1302 +(singlets) enumerated within the curly braces. It is allowed to specify
25.1303 +an empty set as {\tt\{\ \}}, which has no 1-tuples. If the second form
25.1304 +is used, the resultant set consists of $n$-tuples enumerated within the
25.1305 +curly braces, where a particular $n$-tuple consists of corresponding
25.1306 +components enumerated within the parentheses. All $n$-tuples must have
25.1307 +the same number of components.
25.1308 +
25.1309 +\subsubsection{Unsubscripted sets}
25.1310 +
25.1311 +If the primary set expression is an unsubscripted set (which must be
25.1312 +0-dimen\-sional), the resultant set is an elemental set associated with
25.1313 +the corresponding set object.
25.1314 +
25.1315 +\newpage
25.1316 +
25.1317 +\subsubsection{Subscripted sets}
25.1318 +
25.1319 +The primary set expression, which refers to a subscripted set, has the
25.1320 +following syntactic form:
25.1321 +
25.1322 +\medskip
25.1323 +
25.1324 +\noindent\hfil
25.1325 +{\it name}{\tt[}$i_1${\tt,} $i_2${\tt,} \dots{\tt,} $i_n${\tt]}
25.1326 +
25.1327 +\medskip
25.1328 +
25.1329 +\noindent where {\it name} is the symbolic name of the set object,
25.1330 +$i_1$, $i_2$, \dots, $i_n$ are subscripts.
25.1331 +
25.1332 +Each subscript must be a numeric or symbolic expression. The number of
25.1333 +subscripts in the subscript list must be the same as the dimension of
25.1334 +the set object with which the subscript list is associated.
25.1335 +
25.1336 +Actual values of subscript expressions are used to identify a
25.1337 +particular member of the set object that determines the resultant set.
25.1338 +
25.1339 +\subsubsection{``Arithmetic'' sets}
25.1340 +
25.1341 +The primary set expression, which is an ``arithmetic'' set, has the
25.1342 +following two syntactic forms:
25.1343 +
25.1344 +\medskip
25.1345 +
25.1346 +\noindent\hfil
25.1347 +$t_0$ {\tt..} $t_1$ {\tt by} $\delta t$
25.1348 +
25.1349 +\medskip
25.1350 +
25.1351 +\noindent\hspace{138.5pt}
25.1352 +$t_0$ {\tt..} $t_1$
25.1353 +
25.1354 +\medskip
25.1355 +
25.1356 +\noindent where $t_0$, $t_1$, and $\delta t$ are numeric expressions
25.1357 +(the value of $\delta t$ must not be zero). The second form is
25.1358 +equivalent to the first form, where $\delta t=1$.
25.1359 +
25.1360 +If $\delta t>0$, the resultant set is determined as follows:
25.1361 +$$\{t:\exists k\in{\cal Z}(t=t_0+k\delta t,\ t_0\leq t\leq t_1)\}.$$
25.1362 +Otherwise, if $\delta t<0$, the resultant set is determined as follows:
25.1363 +$$\{t:\exists k\in{\cal Z}(t=t_0+k\delta t,\ t_1\leq t\leq t_0)\}.$$
25.1364 +
25.1365 +\subsubsection{Indexing expressions}
25.1366 +
25.1367 +If the primary set expression is an indexing expression, the resultant
25.1368 +set is determined as described above in Subsection \ref{indexing}, page
25.1369 +\pageref{indexing}.
25.1370 +
25.1371 +\subsubsection{Iterated expressions}
25.1372 +
25.1373 +An {\it iterated set expression} is a primary set expression, which has
25.1374 +the following syntactic form:
25.1375 +
25.1376 +\medskip
25.1377 +
25.1378 +\noindent\hfil
25.1379 +{\tt setof} {\it indexing-expression} {\it integrand}
25.1380 +
25.1381 +\medskip
25.1382 +
25.1383 +\noindent where {\it indexing-expression} is an indexing expression,
25.1384 +which introduces dummy indices and controls iterating, {\it integrand}
25.1385 +is either a single numeric or symbolic expression or a list of numeric
25.1386 +and symbolic expressions separated by commae and enclosed in
25.1387 +parentheses.
25.1388 +
25.1389 +If the integrand is a single numeric or symbolic expression, the
25.1390 +resultant set consists of 1-tuples and is determined as follows:
25.1391 +$$\{x:(i_1,\dots,i_n)\in\Delta\},$$
25.1392 +\noindent where $x$ is a value of the integrand, $i_1$, \dots, $i_n$
25.1393 +are dummy indices introduced in the indexing expression, $\Delta$ is
25.1394 +the domain, a set of $n$-tuples specified by the indexing expression,
25.1395 +which defines particular values assigned to the dummy indices on
25.1396 +performing the iterated operation.
25.1397 +
25.1398 +If the integrand is a list containing $m$ numeric and symbolic
25.1399 +expressions, the resultant set consists of $m$-tuples and is determined
25.1400 +as follows:
25.1401 +$$\{(x_1,\dots,x_m):(i_1,\dots,i_n)\in\Delta\},$$
25.1402 +where $x_1$, \dots, $x_m$ are values of the expressions in the
25.1403 +integrand list, $i_1$, \dots, $i_n$ and $\Delta$ have the same meaning
25.1404 +as above.
25.1405 +
25.1406 +\subsubsection{Conditional expressions}
25.1407 +
25.1408 +A {\it conditional set expression} is a primary set expression that has
25.1409 +the following syntactic form:
25.1410 +
25.1411 +\medskip
25.1412 +
25.1413 +\noindent\hfil
25.1414 +{\tt if} $b$ {\tt then} $X$ {\tt else} $Y$
25.1415 +
25.1416 +\medskip
25.1417 +
25.1418 +\noindent where $b$ is an logical expression, $X$ and $Y$ are set
25.1419 +expressions, which must define sets of the same dimension.
25.1420 +
25.1421 +The resultant value of the conditional expression depends on the value
25.1422 +of the logical expression that follows the keyword {\tt if}. If it
25.1423 +takes on the value {\it true}, the resultant set is the value of the
25.1424 +expression that follows the keyword {\tt then}. Otherwise, if the
25.1425 +logical expression takes on the value {\it false}, the resultant set is
25.1426 +the value of the expression that follows the keyword {\tt else}.
25.1427 +
25.1428 +\subsubsection{Parenthesized expressions}
25.1429 +
25.1430 +Any set expression may be enclosed in parentheses that syntactically
25.1431 +makes it a primary set expression.
25.1432 +
25.1433 +Parentheses may be used in set expressions, as in algebra, to specify
25.1434 +the desired order in which operations are to be performed. Where
25.1435 +parentheses are used, the expression within the parentheses is
25.1436 +evaluated before the resultant value is used.
25.1437 +
25.1438 +The resultant value of the parenthesized expression is the same as the
25.1439 +value of the expression enclosed within parentheses.
25.1440 +
25.1441 +\subsubsection{Set operators}
25.1442 +
25.1443 +In MathProg there exist the following set operators, which may be used
25.1444 +in set expressions:
25.1445 +
25.1446 +\medskip
25.1447 +
25.1448 +\begin{tabular}{@{}p{96pt}p{222pt}@{}}
25.1449 +$X$ {\tt union} $Y$&union $X\cup Y$\\
25.1450 +$X$ {\tt diff} $Y$&difference $X\backslash Y$\\
25.1451 +$X$ {\tt symdiff} $Y$&symmetric difference $X\oplus Y$\\
25.1452 +$X$ {\tt inter} $Y$&intersection $X\cap Y$\\
25.1453 +$X$ {\tt cross} $Y$&cross (Cartesian) product $X\times Y$\\
25.1454 +\end{tabular}
25.1455 +
25.1456 +\medskip
25.1457 +
25.1458 +\noindent where $X$ and Y are set expressions, which must define sets
25.1459 +of the identical dimension (except the Cartesian product).
25.1460 +
25.1461 +If the expression includes more than one set operator, all operators
25.1462 +are performed from left to right according to the hierarchy of
25.1463 +operations (see below).
25.1464 +
25.1465 +The resultant value of the expression, which contains set operators, is
25.1466 +the result of applying the operators to their operands.
25.1467 +
25.1468 +The dimension of the resultant set, i.e. the dimension of $n$-tuples,
25.1469 +of which the resultant set consists of, is the same as the dimension of
25.1470 +the operands, except the Cartesian product, where the dimension of the
25.1471 +resultant set is the sum of the dimensions of its operands.
25.1472 +
25.1473 +\subsubsection{Hierarchy of operations}
25.1474 +
25.1475 +The following list shows the hierarchy of operations in set
25.1476 +expressions:
25.1477 +
25.1478 +\medskip
25.1479 +
25.1480 +\noindent\hfil
25.1481 +\begin{tabular}{@{}ll@{}}
25.1482 +Operation&Hierarchy\\
25.1483 +\hline
25.1484 +Evaluation of numeric operations&1st-7th\\
25.1485 +Evaluation of symbolic operations&8th-9th\\
25.1486 +Evaluation of iterated or ``arithmetic'' set ({\tt setof}, {\tt..})&
25.1487 +10th\\
25.1488 +Cartesian product ({\tt cross})&11th\\
25.1489 +Intersection ({\tt inter})&12th\\
25.1490 +Union and difference ({\tt union}, {\tt diff}, {\tt symdiff})&13th\\
25.1491 +Conditional evaluation ({\tt if} \dots {\tt then} \dots {\tt else})&
25.1492 +14th\\
25.1493 +\end{tabular}
25.1494 +
25.1495 +\medskip
25.1496 +
25.1497 +This hierarchy has the same meaning as was explained above for numeric
25.1498 +expressions (see Subsection \ref{hierarchy}, page \pageref{hierarchy}).
25.1499 +
25.1500 +\subsection{Logical expressions}
25.1501 +
25.1502 +A {\it logical expression} is a rule for computing a single logical
25.1503 +value, which can be either {\it true} or {\it false}.
25.1504 +
25.1505 +The primary logical expression may be a numeric expression, relational
25.1506 +expression, iterated logical expression, or another logical expression
25.1507 +enclosed in parentheses.
25.1508 +
25.1509 +\medskip
25.1510 +
25.1511 +\noindent{\bf Examples}
25.1512 +
25.1513 +\medskip
25.1514 +
25.1515 +\noindent
25.1516 +\begin{tabular}{@{}ll@{}}
25.1517 +\verb|i+1|&(numeric expression)\\
25.1518 +\verb|a[i,j] < 1.5|&(relational expression)\\
25.1519 +\verb|s[i+1,j-1] <> 'Mar'|&(relational expression)\\
25.1520 +\verb|(i+1,'Jan') not in I cross J|&(relational expression)\\
25.1521 +\verb|S union T within A[i] inter B[j]|&(relational expression)\\
25.1522 +\verb|forall{i in I, j in J} a[i,j] < .5 * b|&(iterated expression)\\
25.1523 +\verb|(a[i,j] < 1.5 or b[i] >= a[i,j])|&(parenthesized expression)\\
25.1524 +\end{tabular}
25.1525 +
25.1526 +\medskip
25.1527 +
25.1528 +More general logical expressions containing two or more primary logical
25.1529 +expressions may be constructed by using certain logical operators.
25.1530 +
25.1531 +\newpage
25.1532 +
25.1533 +\noindent{\bf Examples}
25.1534 +
25.1535 +\medskip
25.1536 +
25.1537 +\noindent\verb|not (a[i,j] < 1.5 or b[i] >= a[i,j]) and (i,j) in S|
25.1538 +
25.1539 +\noindent\verb|(i,j) in S or (i,j) not in T diff U|
25.1540 +
25.1541 +\subsubsection{Numeric expressions}
25.1542 +
25.1543 +The resultant value of the primary logical expression, which is a
25.1544 +numeric expression, is {\it true}, if the resultant value of the
25.1545 +numeric expression is non-zero. Otherwise the resultant value of the
25.1546 +logical expression is {\it false}.
25.1547 +
25.1548 +\subsubsection{Relational operators}
25.1549 +
25.1550 +In MathProg there exist the following relational operators, which may
25.1551 +be used in logical expressions:
25.1552 +
25.1553 +\medskip
25.1554 +
25.1555 +\begin{tabular}{@{}ll@{}}
25.1556 +$x$ {\tt<} $y$&test on $x<y$\\
25.1557 +$x$ {\tt<=} $y$&test on $x\leq y$\\
25.1558 +$x$ {\tt=} $y$, $x$ {\tt==} $y$&test on $x=y$\\
25.1559 +$x$ {\tt>=} $y$&test on $x\geq y$\\
25.1560 +$x$ {\tt>} $y$&test on $x>y$\\
25.1561 +$x$ {\tt<>} $y$, $x$ {\tt!=} $y$&test on $x\neq y$\\
25.1562 +$x$ {\tt in} $Y$&test on $x\in Y$\\
25.1563 +{\tt(}$x_1${\tt,}\dots{\tt,}$x_n${\tt)} {\tt in} $Y$&test on
25.1564 +$(x_1,\dots,x_n)\in Y$\\
25.1565 +$x$ {\tt not} {\tt in} $Y$, $x$ {\tt!in} $Y$&test on $x\not\in Y$\\
25.1566 +{\tt(}$x_1${\tt,}\dots{\tt,}$x_n${\tt)} {\tt not} {\tt in} $Y$,
25.1567 +{\tt(}$x_1${\tt,}\dots{\tt,}$x_n${\tt)} {\tt !in} $Y$&test on
25.1568 +$(x_1,\dots,x_n)\not\in Y$\\
25.1569 +$X$ {\tt within} $Y$&test on $X\subseteq Y$\\
25.1570 +$X$ {\tt not} {\tt within} $Y$, $X$ {\tt !within} $Y$&test on
25.1571 +$X\not\subseteq Y$\\
25.1572 +\end{tabular}
25.1573 +
25.1574 +\medskip
25.1575 +
25.1576 +\noindent where $x$, $x_1$, \dots, $x_n$, $y$ are numeric or symbolic
25.1577 +expressions, $X$ and $Y$ are set expression.
25.1578 +
25.1579 +{\it Notes:}
25.1580 +
25.1581 +1. In the operations {\tt in}, {\tt not in}, and {\tt !in} the
25.1582 +number of components in the first operands must be the same as the
25.1583 +dimension of the second operand.
25.1584 +
25.1585 +2. In the operations {\tt within}, {\tt not within}, and {\tt !within}
25.1586 +both operands must have identical dimension.
25.1587 +
25.1588 +All the relational operators listed above have their conventional
25.1589 +mathematical meaning. The resultant value is {\it true}, if
25.1590 +corresponding relation is satisfied for its operands, otherwise
25.1591 +{\it false}. (Note that symbolic values are ordered lexicographically,
25.1592 +and any numeric value precedes any symbolic value.)
25.1593 +
25.1594 +\subsubsection{Iterated expressions}
25.1595 +
25.1596 +An {\it iterated logical expression} is a primary logical expression,
25.1597 +which has the following syntactic form:
25.1598 +
25.1599 +\medskip
25.1600 +
25.1601 +\noindent\hfil
25.1602 +{\it iterated-operator} {\it indexing-expression} {\it integrand}
25.1603 +
25.1604 +\medskip
25.1605 +
25.1606 +\noindent where {\it iterated-operator} is the symbolic name of the
25.1607 +iterated operator to be performed (see below), {\it indexing-expression}
25.1608 +is an indexing expression which introduces dummy indices and controls
25.1609 +iterating, {\it integrand} is a numeric expression that participates in
25.1610 +the operation.
25.1611 +
25.1612 +In MathProg there exist two iterated operators, which may be used in
25.1613 +logical expressions:
25.1614 +
25.1615 +\medskip
25.1616 +
25.1617 +\noindent\hfil
25.1618 +\begin{tabular}{@{}lll@{}}
25.1619 +{\tt forall}&$\forall$-quantification&$\displaystyle
25.1620 +\forall(i_1,\dots,i_n)\in\Delta[f(i_1,\dots,i_n)],$\\
25.1621 +{\tt exists}&$\exists$-quantification&$\displaystyle
25.1622 +\exists(i_1,\dots,i_n)\in\Delta[f(i_1,\dots,i_n)],$\\
25.1623 +\end{tabular}
25.1624 +
25.1625 +\medskip
25.1626 +
25.1627 +\noindent where $i_1$, \dots, $i_n$ are dummy indices introduced in
25.1628 +the indexing expression, $\Delta$ is the domain, a set of $n$-tuples
25.1629 +specified by the indexing expression which defines particular values
25.1630 +assigned to the dummy indices on performing the iterated operation,
25.1631 +$f(i_1,\dots,i_n)$ is the integrand, a logical expression whose
25.1632 +resultant value depends on the dummy indices.
25.1633 +
25.1634 +For $\forall$-quantification the resultant value of the iterated
25.1635 +logical expression is {\it true}, if the value of the integrand is
25.1636 +{\it true} for all $n$-tuples contained in the domain, otherwise
25.1637 +{\it false}.
25.1638 +
25.1639 +For $\exists$-quantification the resultant value of the iterated
25.1640 +logical expression is {\it false}, if the value of the integrand is
25.1641 +{\it false} for all $n$-tuples contained in the domain, otherwise
25.1642 +{\it true}.
25.1643 +
25.1644 +\subsubsection{Parenthesized expressions}
25.1645 +
25.1646 +Any logical expression may be enclosed in parentheses that
25.1647 +syntactically makes it a primary logical expression.
25.1648 +
25.1649 +Parentheses may be used in logical expressions, as in algebra, to
25.1650 +specify the desired order in which operations are to be performed.
25.1651 +Where parentheses are used, the expression within the parentheses is
25.1652 +evaluated before the resultant value is used.
25.1653 +
25.1654 +The resultant value of the parenthesized expression is the same as the
25.1655 +value of the expression enclosed within parentheses.
25.1656 +
25.1657 +\subsubsection{Logical operators}
25.1658 +
25.1659 +In MathProg there exist the following logical operators, which may be
25.1660 +used in logical expressions:
25.1661 +
25.1662 +\medskip
25.1663 +
25.1664 +\begin{tabular}{@{}p{96pt}p{222pt}@{}}
25.1665 +{\tt not} $x$, {\tt!}$x$&negation $\neg\ x$\\
25.1666 +$x$ {\tt and} $y$, $x$ {\tt\&\&} $y$&conjunction (logical ``and'')
25.1667 +$x\;\&\;y$\\
25.1668 +$x$ {\tt or} $y$, $x$ {\tt||} $y$&disjunction (logical ``or'')
25.1669 +$x\vee y$\\
25.1670 +\end{tabular}
25.1671 +
25.1672 +\medskip
25.1673 +
25.1674 +\noindent where $x$ and $y$ are logical expressions.
25.1675 +
25.1676 +If the expression includes more than one logical operator, all
25.1677 +operators are performed from left to right according to the hierarchy
25.1678 +of the operations (see below). The resultant value of the expression,
25.1679 +which contains logical operators, is the result of applying the
25.1680 +operators to their operands.
25.1681 +
25.1682 +\subsubsection{Hierarchy of operations}
25.1683 +
25.1684 +The following list shows the hierarchy of operations in logical
25.1685 +expressions:
25.1686 +
25.1687 +\medskip
25.1688 +
25.1689 +\noindent\hfil
25.1690 +\begin{tabular}{@{}ll@{}}
25.1691 +Operation&Hierarchy\\
25.1692 +\hline
25.1693 +Evaluation of numeric operations&1st-7th\\
25.1694 +Evaluation of symbolic operations&8th-9th\\
25.1695 +Evaluation of set operations&10th-14th\\
25.1696 +Relational operations ({\tt<}, {\tt<=}, etc.)&15th\\
25.1697 +Negation ({\tt not}, {\tt!})&16th\\
25.1698 +Conjunction ({\tt and}, {\tt\&\&})&17th\\
25.1699 +$\forall$- and $\exists$-quantification ({\tt forall}, {\tt exists})&
25.1700 +18th\\
25.1701 +Disjunction ({\tt or}, {\tt||})&19th\\
25.1702 +\end{tabular}
25.1703 +
25.1704 +\medskip
25.1705 +
25.1706 +This hierarchy has the same meaning as was explained above for numeric
25.1707 +expressions (see Subsection \ref{hierarchy}, page \pageref{hierarchy}).
25.1708 +
25.1709 +\subsection{Linear expressions}
25.1710 +
25.1711 +An {\it linear expression} is a rule for computing so called
25.1712 +a {\it linear form} or simply a {\it formula}, which is a linear (or
25.1713 +affine) function of elemental variables.
25.1714 +
25.1715 +The primary linear expression may be an unsubscripted variable,
25.1716 +subscripted variable, iterated linear expression, conditional linear
25.1717 +expression, or another linear expression enclosed in parentheses.
25.1718 +
25.1719 +It is also allowed to use a numeric expression as the primary linear
25.1720 +expression, in which case the resultant value of the numeric expression
25.1721 +is automatically converted to a formula that includes the constant term
25.1722 +only.
25.1723 +
25.1724 +\medskip
25.1725 +
25.1726 +\noindent{\bf Examples}
25.1727 +
25.1728 +\medskip
25.1729 +
25.1730 +\noindent
25.1731 +\begin{tabular}{@{}ll@{}}
25.1732 +\verb|z|&(unsubscripted variable)\\
25.1733 +\verb|x[i,j]|&(subscripted variable)\\
25.1734 +\verb|sum{j in J} (a[i] * x[i,j] + 3 * y)|&(iterated expression)\\
25.1735 +\verb|if i in I then x[i,j] else 1.5 * z + 3|&(conditional expression)\\
25.1736 +\verb|(a[i,j] * x[i,j] + y[i-1] + .1)|&(parenthesized expression)\\
25.1737 +\end{tabular}
25.1738 +
25.1739 +\medskip
25.1740 +
25.1741 +More general linear expressions containing two or more primary linear
25.1742 +expressions may be constructed by using certain arithmetic operators.
25.1743 +
25.1744 +\medskip
25.1745 +
25.1746 +\noindent{\bf Examples}
25.1747 +
25.1748 +\medskip
25.1749 +
25.1750 +\noindent\verb|2 * x[i-1,j+1] + 3.5 * y[k] + .5 * z|
25.1751 +
25.1752 +\noindent\verb|(- x[i,j] + 3.5 * y[k]) / sum{t in T} abs(d[i,j,t])|
25.1753 +
25.1754 +\subsubsection{Unsubscripted variables}
25.1755 +
25.1756 +If the primary linear expression is an unsubscripted variable (which
25.1757 +must be 0-dimensional), the resultant formula is that unsubscripted
25.1758 +variable.
25.1759 +
25.1760 +\subsubsection{Subscripted variables}
25.1761 +
25.1762 +The primary linear expression, which refers to a subscripted variable,
25.1763 +has the following syntactic form:
25.1764 +
25.1765 +\medskip
25.1766 +
25.1767 +\noindent\hfil
25.1768 +{\it name}{\tt[}$i_1${\tt,} $i_2${\tt,} \dots{\tt,} $i_n${\tt]}
25.1769 +
25.1770 +\medskip
25.1771 +
25.1772 +\noindent where {\it name} is the symbolic name of the model variable,
25.1773 +$i_1$, $i_2$, \dots, $i_n$ are subscripts.
25.1774 +
25.1775 +Each subscript must be a numeric or symbolic expression. The number of
25.1776 +subscripts in the subscript list must be the same as the dimension of
25.1777 +the model variable with which the subscript list is associated.
25.1778 +
25.1779 +Actual values of the subscript expressions are used to identify a
25.1780 +particular member of the model variable that determines the resultant
25.1781 +formula, which is an elemental variable associated with corresponding
25.1782 +member.
25.1783 +
25.1784 +\subsubsection{Iterated expressions}
25.1785 +
25.1786 +An {\it iterated linear expression} is a primary linear expression,
25.1787 +which has the following syntactic form:
25.1788 +
25.1789 +\medskip
25.1790 +
25.1791 +\noindent\hfil
25.1792 +{\tt sum} {\it indexing-expression} {\it integrand}
25.1793 +
25.1794 +\medskip
25.1795 +
25.1796 +\noindent where {\it indexing-expression} is an indexing expression,
25.1797 +which introduces dummy indices and controls iterating, {\it integrand}
25.1798 +is a linear expression that participates in the operation.
25.1799 +
25.1800 +The iterated linear expression is evaluated exactly in the same way as
25.1801 +the iterated numeric expression (see Subection \ref{itexpr}, page
25.1802 +\pageref{itexpr}) with exception that the integrand participated in the
25.1803 +summation is a formula, not a numeric value.
25.1804 +
25.1805 +\subsubsection{Conditional expressions}
25.1806 +
25.1807 +A {\it conditional linear expression} is a primary linear expression,
25.1808 +which has one of the following two syntactic forms:
25.1809 +
25.1810 +\medskip
25.1811 +
25.1812 +\noindent\hfil
25.1813 +{\tt if} $b$ {\tt then} $f$ {\tt else} $g$
25.1814 +
25.1815 +\medskip
25.1816 +
25.1817 +\noindent\hspace{127pt}
25.1818 +{\tt if} $b$ {\tt then} $f$
25.1819 +
25.1820 +\medskip
25.1821 +
25.1822 +\noindent where $b$ is an logical expression, $f$ and $g$ are linear
25.1823 +expressions.
25.1824 +
25.1825 +The conditional linear expression is evaluated exactly in the same way
25.1826 +as the conditional numeric expression (see Subsection \ref{ifthen},
25.1827 +page \pageref{ifthen}) with exception that operands participated in the
25.1828 +operation are formulae, not numeric values.
25.1829 +
25.1830 +\subsubsection{Parenthesized expressions}
25.1831 +
25.1832 +Any linear expression may be enclosed in parentheses that syntactically
25.1833 +makes it a primary linear expression.
25.1834 +
25.1835 +Parentheses may be used in linear expressions, as in algebra, to
25.1836 +specify the desired order in which operations are to be performed.
25.1837 +Where parentheses are used, the expression within the parentheses is
25.1838 +evaluated before the resultant formula is used.
25.1839 +
25.1840 +The resultant value of the parenthesized expression is the same as the
25.1841 +value of the expression enclosed within parentheses.
25.1842 +
25.1843 +\subsubsection{Arithmetic operators}
25.1844 +
25.1845 +In MathProg there exists the following arithmetic operators, which may
25.1846 +be used in linear expressions:
25.1847 +
25.1848 +\medskip
25.1849 +
25.1850 +\begin{tabular}{@{}p{96pt}p{222pt}@{}}
25.1851 +{\tt+} $f$&unary plus\\
25.1852 +{\tt-} $f$&unary minus\\
25.1853 +$f$ {\tt+} $g$&addition\\
25.1854 +$f$ {\tt-} $g$&subtraction\\
25.1855 +$x$ {\tt*} $f$, $f$ {\tt*} $x$&multiplication\\
25.1856 +$f$ {\tt/} $x$&division
25.1857 +\end{tabular}
25.1858 +
25.1859 +\medskip
25.1860 +
25.1861 +\noindent where $f$ and $g$ are linear expressions, $x$ is a numeric
25.1862 +expression (more precisely, a linear expression containing only the
25.1863 +constant term).
25.1864 +
25.1865 +If the expression includes more than one arithmetic operator, all
25.1866 +operators are performed from left to right according to the hierarchy
25.1867 +of operations (see below). The resultant value of the expression, which
25.1868 +contains arithmetic operators, is the result of applying the operators
25.1869 +to their operands.
25.1870 +
25.1871 +\subsubsection{Hierarchy of operations}
25.1872 +
25.1873 +The hierarchy of arithmetic operations used in linear expressions is
25.1874 +the same as for numeric expressions (see Subsection \ref{hierarchy},
25.1875 +page \pageref{hierarchy}).
25.1876 +
25.1877 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
25.1878 +
25.1879 +\newpage
25.1880 +
25.1881 +\section{Statements}
25.1882 +
25.1883 +{\it Statements} are basic units of the model description. In MathProg
25.1884 +all statements are divided into two categories: declaration statements
25.1885 +and functional statements.
25.1886 +
25.1887 +{\it Declaration statements} (set statement, parameter statement,
25.1888 +variable statement, constraint statement, and objective statement) are
25.1889 +used to declare model objects of certain kinds and define certain
25.1890 +properties of such objects.
25.1891 +
25.1892 +{\it Functional statements} (solve statement, check statement, display
25.1893 +statement, printf statement, loop statement) are intended for
25.1894 +performing some specific actions.
25.1895 +
25.1896 +Note that declaration statements may follow in arbitrary order, which
25.1897 +does not affect the result of translation. However, any model object
25.1898 +must be declared before it is referenced in other statements.
25.1899 +
25.1900 +\subsection{Set statement}
25.1901 +
25.1902 +\medskip
25.1903 +
25.1904 +\framebox[345pt][l]{
25.1905 +\parbox[c][24pt]{345pt}{
25.1906 +\hspace{6pt} {\tt set} {\it name} {\it alias} {\it domain} {\tt,}
25.1907 +{\it attrib} {\tt,} \dots {\tt,} {\it attrib} {\tt;}
25.1908 +}}
25.1909 +
25.1910 +\setlength{\leftmargini}{60pt}
25.1911 +
25.1912 +\begin{description}
25.1913 +\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
25.1914 +set;
25.1915 +\item[\hspace*{54pt}] {\it alias} is an optional string literal, which
25.1916 +specifies an alias of the set;
25.1917 +\item[\hspace*{54pt}] {\it domain} is an optional indexing expression,
25.1918 +which specifies a subscript domain of the set;
25.1919 +\item[\hspace*{54pt}] {\it attrib}, \dots, {\it attrib} are optional
25.1920 +attributes of the set. (Commae preceding attributes may be omitted.)
25.1921 +\end{description}
25.1922 +
25.1923 +\noindent Optional attributes:
25.1924 +
25.1925 +\begin{description}
25.1926 +\item[{\tt dimen} $n$\hspace*{19pt}] specifies the dimension of
25.1927 +$n$-tuples, which the set consists of;
25.1928 +\item[{\tt within} {\it expression}]\hspace*{0pt}\\
25.1929 +specifies a superset which restricts the set or all its members
25.1930 +(elemental sets) to be within that superset;
25.1931 +\item[{\tt:=} {\it expression}]\hspace*{0pt}\\
25.1932 +specifies an elemental set assigned to the set or its members;
25.1933 +\item[{\tt default} {\it expression}]\hspace*{0pt}\\
25.1934 +specifies an elemental set assigned to the set or its members whenever
25.1935 +no appropriate data are available in the data section.
25.1936 +\end{description}
25.1937 +
25.1938 +\newpage
25.1939 +
25.1940 +\noindent{\bf Examples}
25.1941 +
25.1942 +\begin{verbatim}
25.1943 +set V;
25.1944 +set E within V cross V;
25.1945 +set step{s in 1..maxiter} dimen 2 := if s = 1 then E else
25.1946 + step[s-1] union setof{k in V, (i,k) in step[s-1], (k,j)
25.1947 + in step[s-1]}(i,j);
25.1948 +set A{i in I, j in J}, within B[i+1] cross C[j-1], within
25.1949 + D diff E, default {('abc',123), (321,'cba')};
25.1950 +\end{verbatim}
25.1951 +
25.1952 +The set statement declares a set. If the subscript domain is not
25.1953 +specified, the set is a simple set, otherwise it is an array of
25.1954 +elemental sets.
25.1955 +
25.1956 +The {\tt dimen} attribute specifies the dimension of $n$-tuples, which
25.1957 +the set (if it is a simple set) or its members (if the set is an array
25.1958 +of elemental sets) consist of, where $n$ must be unsigned integer from
25.1959 +1 to 20. At most one {\tt dimen} attribute can be specified. If the
25.1960 +{\tt dimen} attribute is not specified, the dimension of\linebreak
25.1961 +$n$-tuples is implicitly determined by other attributes (for example,
25.1962 +if there is a set expression that follows {\tt:=} or the keyword
25.1963 +{\tt default}, the dimension of $n$-tuples of corresponding elemental
25.1964 +set is used). If no dimension information is available, {\tt dimen 1}
25.1965 +is assumed.
25.1966 +
25.1967 +The {\tt within} attribute specifies a set expression whose resultant
25.1968 +value is a superset used to restrict the set (if it is a simple set) or
25.1969 +its members (if the set is an array of elemental sets) to be within
25.1970 +that superset. Arbitrary number of {\tt within} attributes may be
25.1971 +specified in the same set statement.
25.1972 +
25.1973 +The assign ({\tt:=}) attribute specifies a set expression used to
25.1974 +evaluate elemental set(s) assigned to the set (if it is a simple set)
25.1975 +or its members (if the set is an array of elemental sets). If the
25.1976 +assign attribute is specified, the set is {\it computable} and
25.1977 +therefore needs no data to be provided in the data section. If the
25.1978 +assign attribute is not specified, the set must be provided with data
25.1979 +in the data section. At most one assign or default attribute can be
25.1980 +specified for the same set.
25.1981 +
25.1982 +The {\tt default} attribute specifies a set expression used to evaluate
25.1983 +elemental set(s) assigned to the set (if it is a simple set) or its
25.1984 +members (if the set is an array of elemental sets) whenever
25.1985 +no appropriate data are available in the data section. If neither
25.1986 +assign nor default attribute is specified, missing data will cause an
25.1987 +error.
25.1988 +
25.1989 +\subsection{Parameter statement}
25.1990 +
25.1991 +\medskip
25.1992 +
25.1993 +\framebox[345pt][l]{
25.1994 +\parbox[c][24pt]{345pt}{
25.1995 +\hspace{6pt} {\tt param} {\it name} {\it alias} {\it domain} {\tt,}
25.1996 +{\it attrib} {\tt,} \dots {\tt,} {\it attrib} {\tt;}
25.1997 +}}
25.1998 +
25.1999 +\setlength{\leftmargini}{60pt}
25.2000 +
25.2001 +\begin{description}
25.2002 +\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
25.2003 +parameter;
25.2004 +\item[\hspace*{54pt}] {\it alias} is an optional string literal, which
25.2005 +specifies an alias of the parameter;
25.2006 +\item[\hspace*{54pt}] {\it domain} is an optional indexing expression,
25.2007 +which specifies a subscript domain of the parameter;
25.2008 +\item[\hspace*{54pt}] {\it attrib}, \dots, {\it attrib} are optional
25.2009 +attributes of the parameter. (Commae preceding attributes may be
25.2010 +omitted.)
25.2011 +\end{description}
25.2012 +
25.2013 +\noindent Optional attributes:
25.2014 +
25.2015 +\begin{description}
25.2016 +\item[{\tt integer}\hspace*{18.5pt}] specifies that the parameter is
25.2017 +integer;
25.2018 +\item[{\tt binary}\hspace*{24pt}] specifies that the parameter is
25.2019 +binary;
25.2020 +\item[{\tt symbolic}\hspace*{13.5pt}] specifies that the parameter is
25.2021 +symbolic;
25.2022 +\item[{\it relation expression}]\hspace*{0pt}\\
25.2023 +(where {\it relation} is one of: {\tt<}, {\tt<=}, {\tt=}, {\tt==},
25.2024 +{\tt>=}, {\tt>}, {\tt<>}, {\tt!=})\\
25.2025 +specifies a condition that restricts the parameter or its members to
25.2026 +satisfy that condition;
25.2027 +\item[{\tt in} {\it expression}]\hspace*{0pt}\\
25.2028 +specifies a superset that restricts the parameter or its members to be
25.2029 +in that superset;
25.2030 +\item[{\tt:=} {\it expression}]\hspace*{0pt}\\
25.2031 +specifies a value assigned to the parameter or its members;
25.2032 +\item[{\tt default} {\it expression}]\hspace*{0pt}\\
25.2033 +specifies a value assigned to the parameter or its members whenever
25.2034 +no appropriate data are available in the data section.
25.2035 +\end{description}
25.2036 +
25.2037 +\noindent{\bf Examples}
25.2038 +
25.2039 +\begin{verbatim}
25.2040 +param units{raw, prd} >= 0;
25.2041 +param profit{prd, 1..T+1};
25.2042 +param N := 20, integer, >= 0, <= 100;
25.2043 +param comb 'n choose k' {n in 0..N, k in 0..n} :=
25.2044 + if k = 0 or k = n then 1 else comb[n-1,k-1] + comb[n-1,k];
25.2045 +param p{i in I, j in J}, integer, >= 0, <= i+j,
25.2046 + in A[i] symdiff B[j], in C[i,j], default 0.5 * (i + j);
25.2047 +param month symbolic default 'May' in {'Mar', 'Apr', 'May'};
25.2048 +\end{verbatim}
25.2049 +
25.2050 +The parameter statement declares a parameter. If a subscript domain is
25.2051 +not specified, the parameter is a simple (scalar) parameter, otherwise
25.2052 +it is a $n$-dimensional array.
25.2053 +
25.2054 +The type attributes {\tt integer}, {\tt binary}, and {\tt symbolic}
25.2055 +qualify the type of values that can be assigned to the parameter as
25.2056 +shown below:
25.2057 +
25.2058 +\medskip
25.2059 +
25.2060 +\noindent\hfil
25.2061 +\begin{tabular}{@{}ll@{}}
25.2062 +Type attribute&Assigned values\\
25.2063 +\hline
25.2064 +(not specified)&Any numeric values\\
25.2065 +{\tt integer}&Only integer numeric values\\
25.2066 +{\tt binary}&Either 0 or 1\\
25.2067 +{\tt symbolic}&Any numeric and symbolic values\\
25.2068 +\end{tabular}
25.2069 +
25.2070 +\newpage
25.2071 +
25.2072 +The {\tt symbolic} attribute cannot be specified along with other type
25.2073 +attributes. Being specified it must precede all other attributes.
25.2074 +
25.2075 +The condition attribute specifies an optional condition that restricts
25.2076 +values assigned to the parameter to satisfy that condition. This
25.2077 +attribute has the following syntactic forms:
25.2078 +
25.2079 +\medskip
25.2080 +
25.2081 +\begin{tabular}{@{}ll@{}}
25.2082 +{\tt<} $v$&check for $x<v$\\
25.2083 +{\tt<=} $v$&check for $x\leq v$\\
25.2084 +{\tt=} $v$, {\tt==} $v$&check for $x=v$\\
25.2085 +{\tt>=} $v$&check for $x\geq v$\\
25.2086 +{\tt>} $v$&check for $x\geq v$\\
25.2087 +{\tt<>} $v$, {\tt!=} $v$&check for $x\neq v$\\
25.2088 +\end{tabular}
25.2089 +
25.2090 +\medskip
25.2091 +
25.2092 +\noindent where $x$ is a value assigned to the parameter, $v$ is the
25.2093 +resultant value of a numeric or symbolic expression specified in the
25.2094 +condition attribute. Arbitrary number of condition attributes can be
25.2095 +specified for the same parameter. If a value being assigned to the
25.2096 +parameter during model evaluation violates at least one of specified
25.2097 +conditions, an error is raised. (Note that symbolic values are ordered
25.2098 +lexicographically, and any numeric value precedes any symbolic value.)
25.2099 +
25.2100 +The {\tt in} attribute is similar to the condition attribute and
25.2101 +specifies a set expression whose resultant value is a superset used to
25.2102 +restrict numeric or symbolic values assigned to the parameter to be in
25.2103 +that superset. Arbitrary number of the {\tt in} attributes can be
25.2104 +specified for the same parameter. If a value being assigned to the
25.2105 +parameter during model evaluation is not in at least one of specified
25.2106 +supersets, an error is raised.
25.2107 +
25.2108 +The assign ({\tt:=}) attribute specifies a numeric or symbolic
25.2109 +expression used to compute a value assigned to the parameter (if it is
25.2110 +a simple parameter) or its member (if the parameter is an array). If
25.2111 +the assign attribute is specified, the parameter is {\it computable}
25.2112 +and therefore needs no data to be provided in the data section. If the
25.2113 +assign attribute is not specified, the parameter must be provided with
25.2114 +data in the data section. At most one assign or {\tt default} attribute
25.2115 +can be specified for the same parameter.
25.2116 +
25.2117 +The {\tt default} attribute specifies a numeric or symbolic expression
25.2118 +used to compute a value assigned to the parameter or its member
25.2119 +whenever no appropriate data are available in the data section. If
25.2120 +neither assign nor {\tt default} attribute is specified, missing data
25.2121 +will cause an error.
25.2122 +
25.2123 +\subsection{Variable statement}
25.2124 +
25.2125 +\medskip
25.2126 +
25.2127 +\framebox[345pt][l]{
25.2128 +\parbox[c][24pt]{345pt}{
25.2129 +\hspace{6pt} {\tt var} {\it name} {\it alias} {\it domain} {\tt,}
25.2130 +{\it attrib} {\tt,} \dots {\tt,} {\it attrib} {\tt;}
25.2131 +}}
25.2132 +
25.2133 +\setlength{\leftmargini}{60pt}
25.2134 +
25.2135 +\begin{description}
25.2136 +\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
25.2137 +variable;
25.2138 +\item[\hspace*{54pt}] {\it alias} is an optional string literal, which
25.2139 +specifies an alias of the variable;
25.2140 +\item[\hspace*{54pt}] {\it domain} is an optional indexing expression,
25.2141 +which specifies a subscript domain of the variable;
25.2142 +\item[\hspace*{54pt}] {\it attrib}, \dots, {\it attrib} are optional
25.2143 +attributes of the variable. (Commae preceding attributes may be
25.2144 +omitted.)
25.2145 +\end{description}
25.2146 +
25.2147 +\noindent Optional attributes:
25.2148 +
25.2149 +\begin{description}
25.2150 +\item[{\tt integer}\hspace*{18.5pt}] restricts the variable to be
25.2151 +integer;
25.2152 +\item[{\tt binary}\hspace*{24pt}] restricts the variable to be binary;
25.2153 +\item[{\tt>=} {\it expression}]\hspace*{0pt}\\
25.2154 +specifies an lower bound of the variable;
25.2155 +\item[{\tt<=} {\it expression}]\hspace*{0pt}\\
25.2156 +specifies an upper bound of the variable;
25.2157 +\item[{\tt=} {\it expression}]\hspace*{0pt}\\
25.2158 +specifies a fixed value of the variable;
25.2159 +\end{description}
25.2160 +
25.2161 +\noindent{\bf Examples}
25.2162 +
25.2163 +\begin{verbatim}
25.2164 +var x >= 0;
25.2165 +var y{I,J};
25.2166 +var make{p in prd}, integer, >= commit[p], <= market[p];
25.2167 +var store{raw, 1..T+1} >= 0;
25.2168 +var z{i in I, j in J} >= i+j;
25.2169 +\end{verbatim}
25.2170 +
25.2171 +The variable statement declares a variable. If a subscript domain is
25.2172 +not specified, the variable is a simple (scalar) variable, otherwise it
25.2173 +is a $n$-dimensional array of elemental variables.
25.2174 +
25.2175 +Elemental variable(s) associated with the model variable (if it is a
25.2176 +simple variable) or its members (if it is an array) correspond to the
25.2177 +variables in the LP/MIP problem formulation (see Subsection
25.2178 +\ref{problem}, page \pageref{problem}). Note that only elemental
25.2179 +variables actually referenced in some constraints and/or objectives are
25.2180 +included in the LP/MIP problem instance to be generated.
25.2181 +
25.2182 +The type attributes {\tt integer} and {\tt binary} restrict the
25.2183 +variable to be integer or binary, respectively. If no type attribute is
25.2184 +specified, the variable is continuous. If all variables in the model
25.2185 +are continuous, the corresponding problem is of LP class. If there is
25.2186 +at least one integer or binary variable, the problem is of MIP class.
25.2187 +
25.2188 +The lower bound ({\tt>=}) attribute specifies a numeric expression for
25.2189 +computing an lower bound of the variable. At most one lower bound can
25.2190 +be specified. By default all variables (except binary ones) have no
25.2191 +lower bound, so if a variable is required to be non-negative, its zero
25.2192 +lower bound should be explicitly specified.
25.2193 +
25.2194 +The upper bound ({\tt<=}) attribute specifies a numeric expression for
25.2195 +computing an upper bound of the variable. At most one upper bound
25.2196 +attribute can be specified.
25.2197 +
25.2198 +The fixed value ({\tt=}) attribute specifies a numeric expression for
25.2199 +computing a value, at which the variable is fixed. This attribute
25.2200 +cannot be specified along with the bound attributes.
25.2201 +
25.2202 +\subsection{Constraint statement}
25.2203 +
25.2204 +\medskip
25.2205 +
25.2206 +\framebox[345pt][l]{
25.2207 +\parbox[c][96pt]{345pt}{
25.2208 +\hspace{6pt} {\tt s.t.} {\it name} {\it alias} {\it domain} {\tt:}
25.2209 +{\it expression} {\tt,} {\tt=} {\it expression} {\tt;}
25.2210 +
25.2211 +\medskip
25.2212 +
25.2213 +\hspace{6pt} {\tt s.t.} {\it name} {\it alias} {\it domain} {\tt:}
25.2214 +{\it expression} {\tt,} {\tt<=} {\it expression} {\tt;}
25.2215 +
25.2216 +\medskip
25.2217 +
25.2218 +\hspace{6pt} {\tt s.t.} {\it name} {\it alias} {\it domain} {\tt:}
25.2219 +{\it expression} {\tt,} {\tt>=} {\it expression} {\tt;}
25.2220 +
25.2221 +\medskip
25.2222 +
25.2223 +\hspace{6pt} {\tt s.t.} {\it name} {\it alias} {\it domain} {\tt:}
25.2224 +{\it expression} {\tt,} {\tt<=} {\it expression} {\tt,} {\tt<=}
25.2225 +{\it expression} {\tt;}
25.2226 +
25.2227 +\medskip
25.2228 +
25.2229 +\hspace{6pt} {\tt s.t.} {\it name} {\it alias} {\it domain} {\tt:}
25.2230 +{\it expression} {\tt,} {\tt>=} {\it expression} {\tt,} {\tt>=}
25.2231 +{\it expression} {\tt;}
25.2232 +}}
25.2233 +
25.2234 +\setlength{\leftmargini}{60pt}
25.2235 +
25.2236 +\begin{description}
25.2237 +\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
25.2238 +constraint;
25.2239 +\item[\hspace*{54pt}] {\it alias} is an optional string literal, which
25.2240 +specifies an alias of the constraint;
25.2241 +\item[\hspace*{54pt}] {\it domain} is an optional indexing expression,
25.2242 +which specifies a subscript domain of the constraint;
25.2243 +\item[\hspace*{54pt}] {\it expression} is a linear expression used to
25.2244 +compute a component of the constraint. (Commae following expressions
25.2245 +may be omitted.)
25.2246 +\end{description}
25.2247 +
25.2248 +\begin{description}
25.2249 +\item[{\rm Note:}\hspace*{31pt}] The keyword {\tt s.t.} may be written
25.2250 +as {\tt subject to} or as {\tt subj to}, or may be omitted at all.
25.2251 +\end{description}
25.2252 +
25.2253 +\noindent{\bf Examples}
25.2254 +
25.2255 +\begin{verbatim}
25.2256 +s.t. r: x + y + z, >= 0, <= 1;
25.2257 +limit{t in 1..T}: sum{j in prd} make[j,t] <= max_prd;
25.2258 +subject to balance{i in raw, t in 1..T}: store[i,t+1] -
25.2259 + store[i,t] - sum{j in prd} units[i,j] * make[j,t];
25.2260 +subject to rlim 'regular-time limit' {t in time}:
25.2261 +sum{p in prd} pt[p] * rprd[p,t] <= 1.3 * dpp[t] * crews[t];
25.2262 +\end{verbatim}
25.2263 +
25.2264 +The constraint statement declares a constraint. If a subscript domain
25.2265 +is not specified, the constraint is a simple (scalar) constraint,
25.2266 +otherwise it is a $n$-dimensional array of elemental constraints.
25.2267 +
25.2268 +Elemental constraint(s) associated with the model constraint (if it is
25.2269 +a simple constraint) or its members (if it is an array) correspond to
25.2270 +the linear constraints in the LP/MIP problem formulation (see
25.2271 +Subsection \ref{problem}, page \pageref{problem}).
25.2272 +
25.2273 +If the constraint has the form of equality or single inequality, i.e.
25.2274 +includes two expressions, one of which follows the colon and other
25.2275 +follows the relation sign {\tt=}, {\tt<=}, or {\tt>=}, both expressions
25.2276 +in the statement can be linear expressions. If the constraint has the
25.2277 +form of double inequality, i.e. includes three expressions, the middle
25.2278 +expression can be a linear expression while the leftmost and rightmost
25.2279 +ones can be only numeric expressions.
25.2280 +
25.2281 +Generating the model is, roughly speaking, generating its constraints,
25.2282 +which are always evaluated for the entire subscript domain. Evaluation
25.2283 +of the constraints leads, in turn, to evaluation of other model objects
25.2284 +such as sets, parameters, and variables.
25.2285 +
25.2286 +Constructing an actual linear constraint included in the problem
25.2287 +instance, which (constraint) corresponds to a particular elemental
25.2288 +constraint, is performed as follows.
25.2289 +
25.2290 +If the constraint has the form of equality or single inequality,
25.2291 +evaluation of both linear expressions gives two resultant linear forms:
25.2292 +$$\begin{array}{r@{\ }c@{\ }r@{\ }c@{\ }r@{\ }c@{\ }r@{\ }c@{\ }r}
25.2293 +f&=&a_1x_1&+&a_2x_2&+\dots+&a_nx_n&+&a_0,\\
25.2294 +g&=&b_1x_1&+&a_2x_2&+\dots+&a_nx_n&+&b_0,\\
25.2295 +\end{array}$$
25.2296 +where $x_1$, $x_2$, \dots, $x_n$ are elemental variables; $a_1$, $a_2$,
25.2297 +\dots, $a_n$, $b_1$, $b_2$, \dots, $b_n$ are numeric coefficients;
25.2298 +$a_0$ and $b_0$ are constant terms. Then all linear terms of $f$ and
25.2299 +$g$ are carried to the left-hand side, and the constant terms are
25.2300 +carried to the right-hand side, that gives the final elemental
25.2301 +constraint in the standard form:
25.2302 +$$(a_1-b_1)x_1+(a_2-b_2)x_2+\dots+(a_n-b_n)x_n\left\{
25.2303 +\begin{array}{@{}c@{}}=\\\leq\\\geq\\\end{array}\right\}b_0-a_0.$$
25.2304 +
25.2305 +If the constraint has the form of double inequality, evaluation of the
25.2306 +middle linear expression gives the resultant linear form:
25.2307 +$$f=a_1x_1+a_2x_2+\dots+a_nx_n+a_0,$$
25.2308 +and evaluation of the leftmost and rightmost numeric expressions gives
25.2309 +two numeric values $l$ and $u$, respectively. Then the constant term of
25.2310 +the linear form is carried to both left-hand and right-handsides that
25.2311 +gives the final elemental constraint in the standard form:
25.2312 +$$l-a_0\leq a_1x_1+a_2x_2+\dots+a_nx_n\leq u-a_0.$$
25.2313 +
25.2314 +\subsection{Objective statement}
25.2315 +
25.2316 +\medskip
25.2317 +
25.2318 +\framebox[345pt][l]{
25.2319 +\parbox[c][44pt]{345pt}{
25.2320 +\hspace{6pt} {\tt minimize} {\it name} {\it alias} {\it domain} {\tt:}
25.2321 +{\it expression} {\tt;}
25.2322 +
25.2323 +\medskip
25.2324 +
25.2325 +\hspace{6pt} {\tt maximize} {\it name} {\it alias} {\it domain} {\tt:}
25.2326 +{\it expression} {\tt;}
25.2327 +}}
25.2328 +
25.2329 +\setlength{\leftmargini}{60pt}
25.2330 +
25.2331 +\begin{description}
25.2332 +\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
25.2333 +objective;
25.2334 +\item[\hspace*{54pt}] {\it alias} is an optional string literal, which
25.2335 +specifies an alias of the objective;
25.2336 +\item[\hspace*{54pt}] {\it domain} is an optional indexing expression,
25.2337 +which specifies a subscript domain of the objective;
25.2338 +\item[\hspace*{54pt}] {\it expression} is a linear expression used to
25.2339 +compute the linear form of the objective.
25.2340 +\end{description}
25.2341 +
25.2342 +\noindent{\bf Examples}
25.2343 +
25.2344 +\begin{verbatim}
25.2345 +minimize obj: x + 1.5 * (y + z);
25.2346 +maximize total_profit: sum{p in prd} profit[p] * make[p];
25.2347 +\end{verbatim}
25.2348 +
25.2349 +The objective statement declares an objective. If a subscript domain is
25.2350 +not specified, the objective is a simple (scalar) objective. Otherwise
25.2351 +it is a $n$-dimensional array of elemental objectives.
25.2352 +
25.2353 +Elemental objective(s) associated with the model objective (if it is a
25.2354 +simple objective) or its members (if it is an array) correspond to
25.2355 +general linear constraints in the LP/MIP problem formulation (see
25.2356 +Subsection \ref{problem}, page \pageref{problem}). However, unlike
25.2357 +constraints the corresponding linear forms are free (unbounded).
25.2358 +
25.2359 +Constructing an actual linear constraint included in the problem
25.2360 +instance, which (constraint) corresponds to a particular elemental
25.2361 +constraint, is performed as follows. The linear expression specified in
25.2362 +the objective statement is evaluated that, gives the resultant linear
25.2363 +form:
25.2364 +$$f=a_1x_1+a_2x_2+\dots+a_nx_n+a_0,$$
25.2365 +where $x_1$, $x_2$, \dots, $x_n$ are elemental variables; $a_1$, $a_2$,
25.2366 +\dots, $a_n$ are numeric coefficients; $a_0$ is the constant term. Then
25.2367 +the linear form is used to construct the final elemental constraint in
25.2368 +the standard form:
25.2369 +$$-\infty<a_1x_1+a_2x_2+\dots+a_nx_n+a_0<+\infty.$$
25.2370 +
25.2371 +As a rule the model description contains only one objective statement
25.2372 +that defines the objective function used in the problem instance.
25.2373 +However, it is allowed to declare arbitrary number of objectives, in
25.2374 +which case the actual objective function is the first objective
25.2375 +encountered in the model description. Other objectives are also
25.2376 +included in the problem instance, but they do not affect the objective
25.2377 +function.
25.2378 +
25.2379 +\subsection{Solve statement}
25.2380 +
25.2381 +\medskip
25.2382 +
25.2383 +\framebox[345pt][l]{
25.2384 +\parbox[c][24pt]{345pt}{
25.2385 +\hspace{6pt} {\tt solve} {\tt;}
25.2386 +}}
25.2387 +
25.2388 +\setlength{\leftmargini}{60pt}
25.2389 +
25.2390 +\begin{description}
25.2391 +\item[{\rm Note:}\hspace*{31pt}] The solve statement is optional and
25.2392 +can be used only once. If no solve statement is used, one is assumed at
25.2393 +the end of the model section.
25.2394 +\end{description}
25.2395 +
25.2396 +The solve statement causes the model to be solved, that means computing
25.2397 +numeric values of all model variables. This allows using variables in
25.2398 +statements below the solve statement in the same way as if they were
25.2399 +numeric parameters.
25.2400 +
25.2401 +Note that the variable, constraint, and objective statements cannot be
25.2402 +used below the solve statement, i.e. all principal components of the
25.2403 +model must be declared above the solve statement.
25.2404 +
25.2405 +\subsection{Check statement}
25.2406 +
25.2407 +\medskip
25.2408 +
25.2409 +\framebox[345pt][l]{
25.2410 +\parbox[c][24pt]{345pt}{
25.2411 +\hspace{6pt} {\tt check} {\it domain} {\tt:} {\it expression} {\tt;}
25.2412 +}}
25.2413 +
25.2414 +\setlength{\leftmargini}{60pt}
25.2415 +
25.2416 +\begin{description}
25.2417 +\item[{\rm Where:}\hspace*{23pt}] {\it domain} is an optional indexing
25.2418 +expression, which specifies a subscript domain of the check statement;
25.2419 +\item[\hspace*{54pt}] {\it expression} is an logical expression which
25.2420 +specifies the logical condition to be checked. (The colon preceding
25.2421 +{\it expression} may be omitted.)
25.2422 +\end{description}
25.2423 +
25.2424 +\noindent{\bf Examples}
25.2425 +
25.2426 +\begin{verbatim}
25.2427 +check: x + y <= 1 and x >= 0 and y >= 0;
25.2428 +check sum{i in ORIG} supply[i] = sum{j in DEST} demand[j];
25.2429 +check{i in I, j in 1..10}: S[i,j] in U[i] union V[j];
25.2430 +\end{verbatim}
25.2431 +
25.2432 +The check statement allows checking the resultant value of an logical
25.2433 +expression specified in the statement. If the value is {\it false}, an
25.2434 +error is reported.
25.2435 +
25.2436 +If the subscript domain is not specified, the check is performed only
25.2437 +once. Specifying the subscript domain allows performing multiple checks
25.2438 +for every\linebreak $n$-tuple in the domain set. In the latter case the
25.2439 +logical expression may include dummy indices introduced in
25.2440 +corresponding indexing expression.
25.2441 +
25.2442 +\subsection{Display statement}
25.2443 +
25.2444 +\medskip
25.2445 +
25.2446 +\framebox[345pt][l]{
25.2447 +\parbox[c][24pt]{345pt}{
25.2448 +\hspace{6pt} {\tt display} {\it domain} {\tt:} {\it item} {\tt,}
25.2449 +\dots {\tt,} {\it item} {\tt;}
25.2450 +}}
25.2451 +
25.2452 +\setlength{\leftmargini}{60pt}
25.2453 +
25.2454 +\begin{description}
25.2455 +\item[{\rm Where:}\hspace*{23pt}] {\it domain} is an optional indexing
25.2456 +expression, which specifies a subscript domain of the check statement;
25.2457 +\item[\hspace*{54pt}] {\it item}, \dots, {\it item} are items to be
25.2458 +displayed. (The colon preceding the first item may be omitted.)
25.2459 +\end{description}
25.2460 +
25.2461 +\noindent{\bf Examples}
25.2462 +
25.2463 +\begin{verbatim}
25.2464 +display: 'x =', x, 'y =', y, 'z =', z;
25.2465 +display sqrt(x ** 2 + y ** 2 + z ** 2);
25.2466 +display{i in I, j in J}: i, j, a[i,j], b[i,j];
25.2467 +\end{verbatim}
25.2468 +
25.2469 +\newpage
25.2470 +
25.2471 +The display statement evaluates all items specified in the statement
25.2472 +and writes their values to the terminal in plain text format.
25.2473 +
25.2474 +If a subscript domain is not specified, items are evaluated and then
25.2475 +displayed only once. Specifying the subscript domain causes items to be
25.2476 +evaluated and displayed for every $n$-tuple in the domain set. In the
25.2477 +latter case items may include dummy indices introduced in corresponding
25.2478 +indexing expression.
25.2479 +
25.2480 +An item to be displayed can be a model object (set, parameter, variable,
25.2481 +constraint, objective) or an expression.
25.2482 +
25.2483 +If the item is a computable object (i.e. a set or parameter provided
25.2484 +with the assign attribute), the object is evaluated over the entire
25.2485 +domain and then its content (i.e. the content of the object array) is
25.2486 +displayed. Otherwise, if the item is not a computable object, only its
25.2487 +current content (i.e. members actually generated during the model
25.2488 +evaluation) is displayed.
25.2489 +
25.2490 +If the item is an expression, the expression is evaluated and its
25.2491 +resultant value is displayed.
25.2492 +
25.2493 +\subsection{Printf statement}
25.2494 +
25.2495 +\medskip
25.2496 +
25.2497 +\framebox[345pt][l]{
25.2498 +\parbox[c][60pt]{345pt}{
25.2499 +\hspace{6pt} {\tt printf} {\it domain} {\tt:} {\it format} {\tt,}
25.2500 +{\it expression} {\tt,} \dots {\tt,} {\it expression} {\tt;}
25.2501 +
25.2502 +\medskip
25.2503 +
25.2504 +\hspace{6pt} {\tt printf} {\it domain} {\tt:} {\it format} {\tt,}
25.2505 +{\it expression} {\tt,} \dots {\tt,} {\it expression} {\tt>}
25.2506 +{\it filename} {\tt;}
25.2507 +
25.2508 +\medskip
25.2509 +
25.2510 +\hspace{6pt} {\tt printf} {\it domain} {\tt:} {\it format} {\tt,}
25.2511 +{\it expression} {\tt,} \dots {\tt,} {\it expression} {\tt>>}
25.2512 +{\it filename} {\tt;}
25.2513 +}}
25.2514 +
25.2515 +\setlength{\leftmargini}{60pt}
25.2516 +
25.2517 +\begin{description}
25.2518 +\item[{\rm Where:}\hspace*{23pt}] {\it domain} is an optional indexing
25.2519 +expression, which specifies a subscript domain of the printf statement;
25.2520 +\item[\hspace*{54pt}] {\it format} is a symbolic expression whose value
25.2521 +specifies a format control string. (The colon preceding the format
25.2522 +expression may be omitted.)
25.2523 +\item[\hspace*{54pt}] {\it expression}, \dots, {\it expression} are
25.2524 +zero or more expressions whose values have to be formatted and printed.
25.2525 +Each expression must be of numeric, symbolic, or logical type.
25.2526 +\item[\hspace*{54pt}] {\it filename} is a symbolic expression whose
25.2527 +value specifies a name of a text file, to which the output is
25.2528 +redirected. The flag {\tt>} means creating a new empty file while the
25.2529 +flag {\tt>>} means appending the output to an existing file. If no file
25.2530 +name is specified, the output is written to the terminal.
25.2531 +\end{description}
25.2532 +
25.2533 +\noindent{\bf Examples}
25.2534 +
25.2535 +\begin{verbatim}
25.2536 +printf 'Hello, world!\n';
25.2537 +printf: "x = %.3f; y = %.3f; z = %.3f\n",
25.2538 + x, y, z > "result.txt";
25.2539 +printf{i in I, j in J}: "flow from %s to %s is %d\n",
25.2540 + i, j, x[i,j] >> result_file & ".txt";
25.2541 +\end{verbatim}
25.2542 +
25.2543 +\newpage
25.2544 +
25.2545 +\begin{verbatim}
25.2546 +printf{i in I} 'total flow from %s is %g\n',
25.2547 + i, sum{j in J} x[i,j];
25.2548 +printf{k in K} "x[%s] = " & (if x[k] < 0 then "?" else "%g"),
25.2549 + k, x[k];
25.2550 +\end{verbatim}
25.2551 +
25.2552 +The printf statement is similar to the display statement, however, it
25.2553 +allows formatting data to be written.
25.2554 +
25.2555 +If a subscript domain is not specified, the printf statement is
25.2556 +executed only once. Specifying a subscript domain causes executing the
25.2557 +printf statement for every $n$-tuple in the domain set. In the latter
25.2558 +case the format and expression may include dummy indices introduced in
25.2559 +corresponding indexing expression.
25.2560 +
25.2561 +The format control string is a value of the symbolic expression
25.2562 +{\it format} specified in the printf statement. It is composed of zero
25.2563 +or more directives as follows: ordinary characters (not {\tt\%}), which
25.2564 +are copied unchanged to the output stream, and conversion
25.2565 +specifications, each of which causes evaluating corresponding
25.2566 +expression specified in the printf statement, formatting it, and
25.2567 +writing its resultant value to the output stream.
25.2568 +
25.2569 +Conversion specifications that may be used in the format control string
25.2570 +are the following: {\tt d}, {\tt i}, {\tt f}, {\tt F}, {\tt e}, {\tt E},
25.2571 +{\tt g}, {\tt G}, and {\tt s}. These specifications have the same
25.2572 +syntax and semantics as in the C programming language.
25.2573 +
25.2574 +\subsection{For statement}
25.2575 +
25.2576 +\medskip
25.2577 +
25.2578 +\framebox[345pt][l]{
25.2579 +\parbox[c][44pt]{345pt}{
25.2580 +\hspace{6pt} {\tt for} {\it domain} {\tt:} {\it statement} {\tt;}
25.2581 +
25.2582 +\medskip
25.2583 +
25.2584 +\hspace{6pt} {\tt for} {\it domain} {\tt:} {\tt\{} {\it statement}
25.2585 +\dots {\it statement} {\tt\}} {\tt;}
25.2586 +}}
25.2587 +
25.2588 +\setlength{\leftmargini}{60pt}
25.2589 +
25.2590 +\begin{description}
25.2591 +\item[{\rm Where:}\hspace*{23pt}] {\it domain} is an indexing
25.2592 +expression which specifies a subscript domain of the for statement.
25.2593 +(The colon following the indexing expression may be omitted.)
25.2594 +\item[\hspace*{54pt}] {\it statement} is a statement, which should be
25.2595 +executed under control of the for statement;
25.2596 +\item[\hspace*{54pt}] {\it statement}, \dots, {\it statement} is a
25.2597 +sequence of statements (enclosed in curly braces), which should be
25.2598 +executed under control of the for statement.
25.2599 +\end{description}
25.2600 +
25.2601 +\begin{description}
25.2602 +\item[{\rm Note:}\hspace*{31pt}] Only the following statements can be
25.2603 +used within the for statement: check, display, printf, and another for.
25.2604 +\end{description}
25.2605 +
25.2606 +\noindent{\bf Examples}
25.2607 +
25.2608 +\begin{verbatim}
25.2609 +for {(i,j) in E: i != j}
25.2610 +{ printf "flow from %s to %s is %g\n", i, j, x[i,j];
25.2611 + check x[i,j] >= 0;
25.2612 +}
25.2613 +\end{verbatim}
25.2614 +
25.2615 +\newpage
25.2616 +
25.2617 +\begin{verbatim}
25.2618 +for {i in 1..n}
25.2619 +{ for {j in 1..n} printf " %s", if x[i,j] then "Q" else ".";
25.2620 + printf("\n");
25.2621 +}
25.2622 +for {1..72} printf("*");
25.2623 +\end{verbatim}
25.2624 +
25.2625 +The for statement causes a statement or a sequence of statements
25.2626 +specified as part of the for statement to be executed for every
25.2627 +$n$-tuple in the domain set. Thus, statements within the for statement
25.2628 +may include dummy indices introduced in corresponding indexing
25.2629 +expression.
25.2630 +
25.2631 +\subsection{Table statement}
25.2632 +
25.2633 +\medskip
25.2634 +
25.2635 +\framebox[345pt][l]{
25.2636 +\parbox[c][68pt]{345pt}{
25.2637 +\hspace{6pt} {\tt table} {\it name} {\it alias} {\tt IN} {\it driver}
25.2638 +{\it arg} \dots {\it arg} {\tt:}
25.2639 +
25.2640 +\hspace{6pt} {\tt\ \ \ \ \ } {\it set} {\tt<-} {\tt[} {\it fld} {\tt,}
25.2641 +\dots {\tt,} {\it fld} {\tt]} {\tt,} {\it par} {\tt\textasciitilde}
25.2642 +{\it fld} {\tt,} \dots {\tt,} {\it par} {\tt\textasciitilde} {\it fld}
25.2643 +{\tt;}
25.2644 +
25.2645 +\medskip
25.2646 +
25.2647 +\hspace{6pt} {\tt table} {\it name} {\it alias} {\it domain} {\tt OUT}
25.2648 +{\it driver} {\it arg} \dots {\it arg} {\tt:}
25.2649 +
25.2650 +\hspace{6pt} {\tt\ \ \ \ \ } {\it expr} {\tt\textasciitilde} {\it fld}
25.2651 +{\tt,} \dots {\tt,} {\it expr} {\tt\textasciitilde} {\it fld} {\tt;}
25.2652 +}}
25.2653 +
25.2654 +\setlength{\leftmargini}{60pt}
25.2655 +
25.2656 +\begin{description}
25.2657 +\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
25.2658 +table;
25.2659 +\item[\hspace*{54pt}] {\it alias} is an optional string literal, which
25.2660 +specifies an alias of the table;
25.2661 +\item[\hspace*{54pt}] {\it domain} is an indexing expression, which
25.2662 +specifies a subscript domain of the (output) table;
25.2663 +\item[\hspace*{54pt}] {\tt IN} means reading data from the input table;
25.2664 +\item[\hspace*{54pt}] {\tt OUT} means writing data to the output table;
25.2665 +\item[\hspace*{54pt}] {\it driver} is a symbolic expression, which
25.2666 +specifies the driver used to access the table (for details see Section
25.2667 +\ref{drivers}, page \pageref{drivers});
25.2668 +\item[\hspace*{54pt}] {\it arg} is an optional symbolic expression,
25.2669 +which is an argument pass\-ed to the table driver. This symbolic
25.2670 +expression must not include dummy indices specified in the domain;
25.2671 +\item[\hspace*{54pt}] {\it set} is the name of an optional simple set
25.2672 +called {\it control set}. It can be omitted along with the delimiter
25.2673 +{\tt<-};
25.2674 +\item[\hspace*{54pt}] {\it fld} is a field name. Within square brackets
25.2675 +at least one field should be specified. The field name following
25.2676 +a parameter name or expression is optional and can be omitted along
25.2677 +with the delimiter {\tt\textasciitilde}, in which case the name of
25.2678 +corresponding model object is used as the field name;
25.2679 +\item[\hspace*{54pt}] {\it par} is a symbolic name of a model parameter;
25.2680 +\item[\hspace*{54pt}] {\it expr} is a numeric or symbolic expression.
25.2681 +\end{description}
25.2682 +
25.2683 +\newpage
25.2684 +
25.2685 +\noindent{\bf Examples}
25.2686 +
25.2687 +\begin{verbatim}
25.2688 +table data IN "CSV" "data.csv":
25.2689 + S <- [FROM,TO], d~DISTANCE, c~COST;
25.2690 +table result{(f,t) in S} OUT "CSV" "result.csv":
25.2691 + f~FROM, t~TO, x[f,t]~FLOW;
25.2692 +\end{verbatim}
25.2693 +
25.2694 +The table statement allows reading data from a table into model
25.2695 +objects such as sets and (non-scalar) parameters as well as writing
25.2696 +data from the model to a table.
25.2697 +
25.2698 +\subsubsection{Table structure}
25.2699 +
25.2700 +A {\it data table} is an (unordered) set of {\it records}, where each
25.2701 +record consists of the same number of {\it fields}, and each field is
25.2702 +provided with a unique symbolic name called the {\it field name}. For
25.2703 +example:
25.2704 +
25.2705 +\bigskip
25.2706 +
25.2707 +\begin{tabular}{@{\hspace*{38mm}}c@{\hspace*{11mm}}c@{\hspace*{10mm}}c
25.2708 +@{\hspace*{9mm}}c}
25.2709 +First&Second&&Last\\
25.2710 +field&field&.\ \ .\ \ .&field\\
25.2711 +$\downarrow$&$\downarrow$&&$\downarrow$\\
25.2712 +\end{tabular}
25.2713 +
25.2714 +\begin{tabular}{ll@{}}
25.2715 +Table header&$\rightarrow$\\
25.2716 +First record&$\rightarrow$\\
25.2717 +Second record&$\rightarrow$\\
25.2718 +\\
25.2719 +\hfil .\ \ .\ \ .\\
25.2720 +\\
25.2721 +Last record&$\rightarrow$\\
25.2722 +\end{tabular}
25.2723 +\begin{tabular}{|l|l|c|c|}
25.2724 +\hline
25.2725 +{\tt FROM}&{\tt TO}&{\tt DISTANCE}&{\tt COST}\\
25.2726 +\hline
25.2727 +{\tt Seattle} &{\tt New-York}&{\tt 2.5}&{\tt 0.12}\\
25.2728 +{\tt Seattle} &{\tt Chicago} &{\tt 1.7}&{\tt 0.08}\\
25.2729 +{\tt Seattle} &{\tt Topeka} &{\tt 1.8}&{\tt 0.09}\\
25.2730 +{\tt San-Diego}&{\tt New-York}&{\tt 2.5}&{\tt 0.15}\\
25.2731 +{\tt San-Diego}&{\tt Chicago} &{\tt 1.8}&{\tt 0.10}\\
25.2732 +{\tt San-Diego}&{\tt Topeka} &{\tt 1.4}&{\tt 0.07}\\
25.2733 +\hline
25.2734 +\end{tabular}
25.2735 +
25.2736 +\subsubsection{Reading data from input table}
25.2737 +
25.2738 +The input table statement causes reading data from the specified table
25.2739 +record by record.
25.2740 +
25.2741 +Once a next record has been read, numeric or symbolic values of fields,
25.2742 +whose names are enclosed in square brackets in the table statement, are
25.2743 +gathered into $n$-tuple, and if the control set is specified in the
25.2744 +table statement, this $n$-tuple is added to it. Besides, a numeric or
25.2745 +symbolic value of each field associated with a model parameter is
25.2746 +assigned to the parameter member identified by subscripts, which are
25.2747 +components of the $n$-tuple just read.
25.2748 +
25.2749 +For example, the following input table statement:
25.2750 +
25.2751 +\medskip
25.2752 +
25.2753 +\noindent\hfil
25.2754 +\verb|table data IN "...": S <- [FROM,TO], d~DISTANCE, c~COST;|
25.2755 +
25.2756 +\medskip
25.2757 +
25.2758 +\noindent
25.2759 +causes reading values of four fields named {\tt FROM}, {\tt TO},
25.2760 +{\tt DISTANCE}, and {\tt COST} from each record of the specified table.
25.2761 +Values of fields {\tt FROM} and {\tt TO} give a pair $(f,t)$, which is
25.2762 +added to the control set {\tt S}. The value of field {\tt DISTANCE} is
25.2763 +assigned to parameter member ${\tt d}[f,t]$, and the value of field
25.2764 +{\tt COST} is assigned to parameter member ${\tt c}[f,t]$.
25.2765 +
25.2766 +Note that the input table may contain extra fields whose names are not
25.2767 +specified in the table statement, in which case values of these fields
25.2768 +on reading the table are ignored.
25.2769 +
25.2770 +\subsubsection{Writing data to output table}
25.2771 +
25.2772 +The output table statement causes writing data to the specified table.
25.2773 +Note that some drivers (namely, CSV and xBASE) destroy the output table
25.2774 +before writing data, i.e. delete all its existing records.
25.2775 +
25.2776 +Each $n$-tuple in the specified domain set generates one record written
25.2777 +to the output table. Values of fields are numeric or symbolic values of
25.2778 +corresponding expressions specified in the table statement. These
25.2779 +expressions are evaluated for each $n$-tuple in the domain set and,
25.2780 +thus, may include dummy indices introduced in the corresponding indexing
25.2781 +expression.
25.2782 +
25.2783 +For example, the following output table statement:
25.2784 +
25.2785 +\medskip
25.2786 +
25.2787 +\noindent
25.2788 +\verb| table result{(f,t) in S} OUT "...": f~FROM, t~TO, x[f,t]~FLOW;|
25.2789 +
25.2790 +\medskip
25.2791 +
25.2792 +\noindent
25.2793 +causes writing records, by one record for each pair $(f,t)$ in set
25.2794 +{\tt S}, to the output table, where each record consists of three
25.2795 +fields named {\tt FROM}, {\tt TO}, and {\tt FLOW}. The values written
25.2796 +to fields {\tt FROM} and {\tt TO} are current values of dummy indices
25.2797 +{\tt f} and {\tt t}, and the value written to field {\tt FLOW} is
25.2798 +a value of member ${\tt x}[f,t]$ of corresponding subscripted parameter
25.2799 +or variable.
25.2800 +
25.2801 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
25.2802 +
25.2803 +\newpage
25.2804 +
25.2805 +\section{Model data}
25.2806 +
25.2807 +{\it Model data} include elemental sets, which are ``values'' of model
25.2808 +sets, and numeric and symbolic values of model parameters.
25.2809 +
25.2810 +In MathProg there are two different ways to saturate model sets and
25.2811 +parameters with data. One way is simply providing necessary data using
25.2812 +the assign attribute. However, in many cases it is more practical to
25.2813 +separate the model itself and particular data needed for the model. For
25.2814 +the latter reason in MathProg there is another way, when the model
25.2815 +description is divided into two parts: model section and data section.
25.2816 +
25.2817 +A {\it model section} is a main part of the model description that
25.2818 +contains declarations of all model objects and is common for all
25.2819 +problems based on that model.
25.2820 +
25.2821 +A {\it data section} is an optional part of the model description that
25.2822 +contains model data specific for a particular problem.
25.2823 +
25.2824 +In MathProg model and data sections can be placed either in one text
25.2825 +file or in two separate text files.
25.2826 +
25.2827 +1. If both model and data sections are placed in one file, the file is
25.2828 +composed as follows:
25.2829 +
25.2830 +\bigskip
25.2831 +
25.2832 +\noindent\hfil
25.2833 +\framebox{\begin{tabular}{l}
25.2834 +{\it statement}{\tt;}\\
25.2835 +{\it statement}{\tt;}\\
25.2836 +\hfil.\ \ .\ \ .\\
25.2837 +{\it statement}{\tt;}\\
25.2838 +{\tt data;}\\
25.2839 +{\it data block}{\tt;}\\
25.2840 +{\it data block}{\tt;}\\
25.2841 +\hfil.\ \ .\ \ .\\
25.2842 +{\it data block}{\tt;}\\
25.2843 +{\tt end;}
25.2844 +\end{tabular}}
25.2845 +
25.2846 +\bigskip
25.2847 +
25.2848 +2. If the model and data sections are placed in two separate files, the
25.2849 +files are composed as follows:
25.2850 +
25.2851 +\bigskip
25.2852 +
25.2853 +\noindent\hfil
25.2854 +\begin{tabular}{@{}c@{}}
25.2855 +\framebox{\begin{tabular}{l}
25.2856 +{\it statement}{\tt;}\\
25.2857 +{\it statement}{\tt;}\\
25.2858 +\hfil.\ \ .\ \ .\\
25.2859 +{\it statement}{\tt;}\\
25.2860 +{\tt end;}\\
25.2861 +\end{tabular}}\\
25.2862 +\\\\Model file\\
25.2863 +\end{tabular}
25.2864 +\hspace{32pt}
25.2865 +\begin{tabular}{@{}c@{}}
25.2866 +\framebox{\begin{tabular}{l}
25.2867 +{\tt data;}\\
25.2868 +{\it data block}{\tt;}\\
25.2869 +{\it data block}{\tt;}\\
25.2870 +\hfil.\ \ .\ \ .\\
25.2871 +{\it data block}{\tt;}\\
25.2872 +{\tt end;}\\
25.2873 +\end{tabular}}\\
25.2874 +\\Data file\\
25.2875 +\end{tabular}
25.2876 +
25.2877 +\bigskip
25.2878 +
25.2879 +\begin{description}
25.2880 +\item[{\rm Note:}\hspace*{31pt}] If the data section is placed in a
25.2881 +separate file, the keyword {\tt data} is optional and may be omitted
25.2882 +along with the semicolon that follows it.
25.2883 +\end{description}
25.2884 +
25.2885 +\subsection{Coding data section}
25.2886 +
25.2887 +The {\it data section} is a sequence of data blocks in various formats,
25.2888 +which are discussed in following subsections. The order, in which data
25.2889 +blocks follow in the data section, may be arbitrary, not necessarily
25.2890 +the same, in which corresponding model objects follow in the model
25.2891 +section.
25.2892 +
25.2893 +The rules of coding the data section are commonly the same as the rules
25.2894 +of coding the model description (see Subsection \ref{coding}, page
25.2895 +\pageref{coding}), i.e. data blocks are composed from basic lexical
25.2896 +units such as symbolic names, numeric and string literals, keywords,
25.2897 +delimiters, and comments. However, for the sake of convenience and
25.2898 +improving readability there is one deviation from the common rule: if
25.2899 +a string literal consists of only alphanumeric characters (including
25.2900 +the underscore character), the signs {\tt+} and {\tt-}, and/or the
25.2901 +decimal point, it may be coded without bordering by (single or double)
25.2902 +quotes.
25.2903 +
25.2904 +All numeric and symbolic material provided in the data section is coded
25.2905 +in the form of numbers and symbols, i.e. unlike the model section
25.2906 +no expressions are allowed in the data section. Nevertheless, the signs
25.2907 +{\tt+} and {\tt-} can precede numeric literals to allow coding signed
25.2908 +numeric quantities, in which case there must be no white-space
25.2909 +characters between the sign and following numeric literal (if there is
25.2910 +at least one white-space, the sign and following numeric literal are
25.2911 +recognized as two different lexical units).
25.2912 +
25.2913 +\subsection{Set data block}
25.2914 +
25.2915 +\medskip
25.2916 +
25.2917 +\framebox[345pt][l]{
25.2918 +\parbox[c][44pt]{345pt}{
25.2919 +\hspace{6pt} {\tt set} {\it name} {\tt,} {\it record} {\tt,} \dots
25.2920 +{\tt,} {\it record} {\tt;}
25.2921 +
25.2922 +\medskip
25.2923 +
25.2924 +\hspace{6pt} {\tt set} {\it name} {\tt[} {\it symbol} {\tt,} \dots
25.2925 +{\tt,} {\it symbol} {\tt]} {\tt,} {\it record} {\tt,} \dots {\tt,}
25.2926 +{\it record} {\tt;}
25.2927 +}}
25.2928 +
25.2929 +\setlength{\leftmargini}{60pt}
25.2930 +
25.2931 +\begin{description}
25.2932 +\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
25.2933 +set;
25.2934 +\item[\hspace*{54pt}] {\it symbol}, \dots, {\it symbol} are subscripts,
25.2935 +which specify a particular member of the set (if the set is an array,
25.2936 +i.e. a set of sets);
25.2937 +\item[\hspace*{54pt}] {\it record}, \dots, {\it record} are data
25.2938 +records.
25.2939 +\end{description}
25.2940 +
25.2941 +\begin{description}
25.2942 +\item[{\rm Note:}\hspace*{31pt}] Commae preceding data records may be
25.2943 +omitted.
25.2944 +\end{description}
25.2945 +
25.2946 +\noindent Data records:
25.2947 +
25.2948 +\begin{description}
25.2949 +\item[{\tt :=}\hspace*{45pt}] is a non-significant data record, which
25.2950 +may be used freely to improve readability;
25.2951 +\item[{\tt(} {\it slice} {\tt)}\hspace*{18.5pt}] specifies a slice;
25.2952 +\item[{\it simple-data}\hspace*{5.5pt}] specifies set data in the
25.2953 +simple format;
25.2954 +\item[{\tt:} {\it matrix-data}]\hspace*{0pt}\\
25.2955 +specifies set data in the matrix format;
25.2956 +\item[{\tt(tr)} {\tt:} {\it matrix-data}]\hspace*{0pt}\\
25.2957 +specifies set data in the transposed matrix format. (In this case the
25.2958 +colon following the keyword {\tt(tr)} may be omitted.)
25.2959 +\end{description}
25.2960 +
25.2961 +\noindent{\bf Examples}
25.2962 +
25.2963 +\begin{verbatim}
25.2964 +set month := Jan Feb Mar Apr May Jun;
25.2965 +set month "Jan", "Feb", "Mar", "Apr", "May", "Jun";
25.2966 +set A[3,Mar] := (1,2) (2,3) (4,2) (3,1) (2,2) (4,4) (3,4);
25.2967 +set A[3,'Mar'] := 1 2 2 3 4 2 3 1 2 2 4 4 2 4;
25.2968 +set A[3,'Mar'] : 1 2 3 4 :=
25.2969 + 1 - + - -
25.2970 + 2 - + + -
25.2971 + 3 + - - +
25.2972 + 4 - + - + ;
25.2973 +set B := (1,2,3) (1,3,2) (2,3,1) (2,1,3) (1,2,2) (1,1,1) (2,1,1);
25.2974 +set B := (*,*,*) 1 2 3, 1 3 2, 2 3 1, 2 1 3, 1 2 2, 1 1 1, 2 1 1;
25.2975 +set B := (1,*,2) 3 2 (2,*,1) 3 1 (1,2,3) (2,1,3) (1,1,1);
25.2976 +set B := (1,*,*) : 1 2 3 :=
25.2977 + 1 + - -
25.2978 + 2 - + +
25.2979 + 3 - + -
25.2980 + (2,*,*) : 1 2 3 :=
25.2981 + 1 + - +
25.2982 + 2 - - -
25.2983 + 3 + - - ;
25.2984 +\end{verbatim}
25.2985 +
25.2986 +\noindent(In these examples {\tt month} is a simple set of singlets,
25.2987 +{\tt A} is a 2-dimensional array of doublets, and {\tt B} is a simple
25.2988 +set of triplets. Data blocks for the same set are equivalent in the
25.2989 +sense that they specify the same data in different formats.)
25.2990 +
25.2991 +\medskip
25.2992 +
25.2993 +The {\it set data block} is used to specify a complete elemental set,
25.2994 +which is assigned to a set (if it is a simple set) or one of its
25.2995 +members (if the set is an array of sets).\footnote{There is another way
25.2996 +to specify data for a simple set along with data for parameters. This
25.2997 +feature is discussed in the next subsection.}
25.2998 +
25.2999 +Data blocks can be specified only for non-computable sets, i.e. for
25.3000 +sets, which have no assign ({\tt:=}) attribute in the corresponding set
25.3001 +statements.
25.3002 +
25.3003 +If the set is a simple set, only its symbolic name should be specified
25.3004 +in the header of the data block. Otherwise, if the set is a
25.3005 +$n$-dimensional array, its symbolic name should be provided with a
25.3006 +complete list of subscripts separated by commae and enclosed in square
25.3007 +brackets to specify a particular member of the set array. The number of
25.3008 +subscripts must be the same as the dimension of the set array, where
25.3009 +each subscript must be a number or symbol.
25.3010 +
25.3011 +An elemental set defined in the set data block is coded as a sequence
25.3012 +of data records described below.\footnote{{\it Data record} is simply a
25.3013 +technical term. It does not mean that data records have any special
25.3014 +formatting.}
25.3015 +
25.3016 +\newpage
25.3017 +
25.3018 +\subsubsection{Assign data record}
25.3019 +
25.3020 +The {\it assign} ({\tt:=}) {\it data record} is a non-signficant
25.3021 +element. It may be used for improving readability of data blocks.
25.3022 +
25.3023 +\subsubsection{Slice data record}
25.3024 +
25.3025 +The {\it slice data record} is a control record, which specifies a
25.3026 +{\it slice} of the elemental set defined in the data block. It has the
25.3027 +following syntactic form:
25.3028 +
25.3029 +\medskip
25.3030 +
25.3031 +\noindent\hfil
25.3032 +{\tt(} $s_1$ {\tt,} $s_2$ {\tt,} \dots {\tt,} $s_n$ {\tt)}
25.3033 +
25.3034 +\medskip
25.3035 +
25.3036 +\noindent where $s_1$, $s_2$, \dots, $s_n$ are components of the slice.
25.3037 +
25.3038 +Each component of the slice can be a number or symbol or the asterisk
25.3039 +({\tt*}). The number of components in the slice must be the same as the
25.3040 +dimension of $n$-tuples in the elemental set to be defined. For
25.3041 +instance, if the elemental set contains 4-tuples (quadruplets), the
25.3042 +slice must have four components. The number of asterisks in the slice
25.3043 +is called the {\it slice dimension}.
25.3044 +
25.3045 +The effect of using slices is the following. If a $m$-dimensional slice
25.3046 +(i.e. a slice having $m$ asterisks) is specified in the data block, all
25.3047 +subsequent data records must specify tuples of the dimension $m$.
25.3048 +Whenever a $m$-tuple is encountered, each asterisk in the slice is
25.3049 +replaced by corresponding components of the $m$-tuple that gives the
25.3050 +resultant $n$-tuple, which is included in the elemental set to be
25.3051 +defined. For example, if the slice $(a,*,1,2,*)$ is in effect, and
25.3052 +2-tuple $(3,b)$ is encountered in a subsequent data record, the
25.3053 +resultant 5-tuple included in the elemental set is $(a,3,1,2,b)$.
25.3054 +
25.3055 +The slice having no asterisks itself defines a complete $n$-tuple,
25.3056 +which is included in the elemental set.
25.3057 +
25.3058 +Being once specified the slice effects until either a new slice or the
25.3059 +end of data block is encountered. Note that if no slice is specified in
25.3060 +the data block, one, components of which are all asterisks, is assumed.
25.3061 +
25.3062 +\subsubsection{Simple data record}
25.3063 +
25.3064 +The {\it simple data record} defines one $n$-tuple in a simple format
25.3065 +and has the following syntactic form:
25.3066 +
25.3067 +\medskip
25.3068 +
25.3069 +\noindent\hfil
25.3070 +$t_1$ {\tt,} $t_2$ {\tt,} \dots {\tt,} $t_n$
25.3071 +
25.3072 +\medskip
25.3073 +
25.3074 +\noindent where $t_1$, $t_2$, \dots, $t_n$ are components of the
25.3075 +$n$-tuple. Each component can be a number or symbol. Commae between
25.3076 +components are optional and may be omitted.
25.3077 +
25.3078 +\subsubsection{Matrix data record}
25.3079 +
25.3080 +The {\it matrix data record} defines several 2-tuples (doublets) in
25.3081 +a matrix format and has the following syntactic form:
25.3082 +
25.3083 +\newpage
25.3084 +
25.3085 +$$\begin{array}{cccccc}
25.3086 +\mbox{{\tt:}}&c_1&c_2&\dots&c_n&\mbox{{\tt:=}}\\
25.3087 +r_1&a_{11}&a_{12}&\dots&a_{1n}&\\
25.3088 +r_2&a_{21}&a_{22}&\dots&a_{2n}&\\
25.3089 +\multicolumn{5}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}&\\
25.3090 +r_m&a_{m1}&a_{m2}&\dots&a_{mn}&\\
25.3091 +\end{array}$$
25.3092 +where $r_1$, $r_2$, \dots, $r_m$ are numbers and/or symbols
25.3093 +corresponding to rows of the matrix; $c_1$, $c_2$, \dots, $c_n$ are
25.3094 +numbers and/or symbols corresponding to columns of the matrix, $a_{11}$,
25.3095 +$a_{12}$, \dots, $a_{mn}$ are matrix elements, which can be either
25.3096 +{\tt+} or {\tt-}. (In this data record the delimiter {\tt:} preceding
25.3097 +the column list and the delimiter {\tt:=} following the column list
25.3098 +cannot be omitted.)
25.3099 +
25.3100 +Each element $a_{ij}$ of the matrix data block (where $1\leq i\leq m$,
25.3101 +$1\leq j\leq n$) corresponds to 2-tuple $(r_i,c_j)$. If $a_{ij}$ is the
25.3102 +plus sign ({\tt+}), that 2-tuple (or a longer $n$-tuple, if a slice is
25.3103 +used) is included in the elemental set. Otherwise, if $a_{ij}$ is the
25.3104 +minus sign ({\tt-}), that 2-tuple is not included in the elemental set.
25.3105 +
25.3106 +Since the matrix data record defines 2-tuples, either the elemental set
25.3107 +must consist of 2-tuples or the slice currently used must be
25.3108 +2-dimensional.
25.3109 +
25.3110 +\subsubsection{Transposed matrix data record}
25.3111 +
25.3112 +The {\it transposed matrix data record} has the following syntactic
25.3113 +form:
25.3114 +$$\begin{array}{cccccc}
25.3115 +\mbox{{\tt(tr) :}}&c_1&c_2&\dots&c_n&\mbox{{\tt:=}}\\
25.3116 +r_1&a_{11}&a_{12}&\dots&a_{1n}&\\
25.3117 +r_2&a_{21}&a_{22}&\dots&a_{2n}&\\
25.3118 +\multicolumn{5}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}&\\
25.3119 +r_m&a_{m1}&a_{m2}&\dots&a_{mn}&\\
25.3120 +\end{array}$$
25.3121 +(In this case the delimiter {\tt:} following the keyword {\tt(tr)} is
25.3122 +optional and may be omitted.)
25.3123 +
25.3124 +This data record is completely analogous to the matrix data record (see
25.3125 +above) with only exception that in this case each element $a_{ij}$ of
25.3126 +the matrix corresponds to 2-tuple $(c_j,r_i)$ rather than $(r_i,c_j)$.
25.3127 +
25.3128 +Being once specified the {\tt(tr)} indicator affects all subsequent
25.3129 +data records until either a slice or the end of data block is
25.3130 +encountered.
25.3131 +
25.3132 +\subsection{Parameter data block}
25.3133 +
25.3134 +\medskip
25.3135 +
25.3136 +\framebox[345pt][l]{
25.3137 +\parbox[c][80pt]{345pt}{
25.3138 +\hspace{6pt} {\tt param} {\it name} {\tt,} {\it record} {\tt,} \dots
25.3139 +{\tt,} {\it record} {\tt;}
25.3140 +
25.3141 +\medskip
25.3142 +
25.3143 +\hspace{6pt} {\tt param} {\it name} {\tt default} {\it value} {\tt,}
25.3144 +{\it record} {\tt,} \dots {\tt,} {\it record} {\tt;}
25.3145 +
25.3146 +\medskip
25.3147 +
25.3148 +\hspace{6pt} {\tt param} {\tt:} {\it tabbing-data} {\tt;}
25.3149 +
25.3150 +\medskip
25.3151 +
25.3152 +\hspace{6pt} {\tt param} {\tt default} {\it value} {\tt:}
25.3153 +{\it tabbing-data} {\tt;}
25.3154 +}}
25.3155 +
25.3156 +\newpage
25.3157 +
25.3158 +\setlength{\leftmargini}{60pt}
25.3159 +
25.3160 +\begin{description}
25.3161 +\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
25.3162 +parameter;
25.3163 +\item[\hspace*{54pt}] {\it value} is an optional default value of the
25.3164 +parameter;
25.3165 +\item[\hspace*{54pt}] {\it record}, \dots, {\it record} are data
25.3166 +records;
25.3167 +\item[\hspace*{54pt}] {\it tabbing-data} specifies parameter data in
25.3168 +the tabbing format.
25.3169 +\end{description}
25.3170 +
25.3171 +\begin{description}
25.3172 +\item[{\rm Note:}\hspace*{31pt}] Commae preceding data records may be
25.3173 +omitted.
25.3174 +\end{description}
25.3175 +
25.3176 +\noindent Data records:
25.3177 +
25.3178 +\begin{description}
25.3179 +\item[{\tt :=}\hspace*{45pt}] is a non-significant data record, which
25.3180 +may be used freely to improve readability;
25.3181 +\item[{\tt[} {\it slice} {\tt]}\hspace*{18.5pt}] specifies a slice;
25.3182 +\item[{\it plain-data}\hspace*{11pt}] specifies parameter data in the
25.3183 +plain format;
25.3184 +\item[{\tt:} {\it tabular-data}]\hspace*{0pt}\\
25.3185 +specifies parameter data in the tabular format;
25.3186 +\item[{\tt(tr)} {\tt:} {\it tabular-data}]\hspace*{0pt}\\
25.3187 +specifies set data in the transposed tabular format. (In this case the
25.3188 +colon following the keyword {\tt(tr)} may be omitted.)
25.3189 +\end{description}
25.3190 +
25.3191 +\noindent{\bf Examples}
25.3192 +
25.3193 +\begin{verbatim}
25.3194 +param T := 4;
25.3195 +param month := 1 'Jan' 2 'Feb' 3 'Mar' 4 'Apr' 5 'May';
25.3196 +param month := [1] Jan, [2] Feb, [3] Mar, [4] Apr, [5] May;
25.3197 +param day := [Sun] 0, [Mon] 1, [Tue] 2, [Wed] 3, [Thu] 4,
25.3198 + [Fri] 5, [Sat] 6;
25.3199 +param init_stock := iron 7.32 nickel 35.8;
25.3200 +param init_stock [*] iron 7.32, nickel 35.8;
25.3201 +param cost [iron] .025 [nickel] .03;
25.3202 +param value := iron -.1, nickel .02;
25.3203 +param : init_stock cost value :=
25.3204 + iron 7.32 .025 -.1
25.3205 + nickel 35.8 .03 .02 ;
25.3206 +param : raw : init_stock cost value :=
25.3207 + iron 7.32 .025 -.1
25.3208 + nickel 35.8 .03 .02 ;
25.3209 +param demand default 0 (tr)
25.3210 + : FRA DET LAN WIN STL FRE LAF :=
25.3211 + bands 300 . 100 75 . 225 250
25.3212 + coils 500 750 400 250 . 850 500
25.3213 + plate 100 . . 50 200 . 250 ;
25.3214 +\end{verbatim}
25.3215 +
25.3216 +\newpage
25.3217 +
25.3218 +\begin{verbatim}
25.3219 +param trans_cost :=
25.3220 + [*,*,bands]: FRA DET LAN WIN STL FRE LAF :=
25.3221 + GARY 30 10 8 10 11 71 6
25.3222 + CLEV 22 7 10 7 21 82 13
25.3223 + PITT 19 11 12 10 25 83 15
25.3224 + [*,*,coils]: FRA DET LAN WIN STL FRE LAF :=
25.3225 + GARY 39 14 11 14 16 82 8
25.3226 + CLEV 27 9 12 9 26 95 17
25.3227 + PITT 24 14 17 13 28 99 20
25.3228 + [*,*,plate]: FRA DET LAN WIN STL FRE LAF :=
25.3229 + GARY 41 15 12 16 17 86 8
25.3230 + CLEV 29 9 13 9 28 99 18
25.3231 + PITT 26 14 17 13 31 104 20 ;
25.3232 +\end{verbatim}
25.3233 +
25.3234 +The {\it parameter data block} is used to specify complete data for a
25.3235 +parameter (or parameters, if data are specified in the tabbing format).
25.3236 +
25.3237 +Data blocks can be specified only for non-computable parameters, i.e.
25.3238 +for parameters, which have no assign ({\tt:=}) attribute in the
25.3239 +corresponding parameter statements.
25.3240 +
25.3241 +Data defined in the parameter data block are coded as a sequence of
25.3242 +data records described below. Additionally the data block can be
25.3243 +provided with the optional {\tt default} attribute, which specifies a
25.3244 +default numeric or symbolic value of the parameter (parameters). This
25.3245 +default value is assigned to the parameter or its members, if
25.3246 +no appropriate value is defined in the parameter data block. The
25.3247 +{\tt default} attribute cannot be used, if it is already specified in
25.3248 +the corresponding parameter statement.
25.3249 +
25.3250 +\subsubsection{Assign data record}
25.3251 +
25.3252 +The {\it assign} ({\tt:=}) {\it data record} is a non-signficant
25.3253 +element. It may be used for improving readability of data blocks.
25.3254 +
25.3255 +\subsubsection{Slice data record}
25.3256 +
25.3257 +The {\it slice data record} is a control record, which specifies a
25.3258 +{\it slice} of the parameter array. It has the following syntactic form:
25.3259 +
25.3260 +\medskip
25.3261 +
25.3262 +\noindent\hfil
25.3263 +{\tt[} $s_1$ {\tt,} $s_2$ {\tt,} \dots {\tt,} $s_n$ {\tt]}
25.3264 +
25.3265 +\medskip
25.3266 +
25.3267 +\noindent where $s_1$, $s_2$, \dots, $s_n$ are components of the slice.
25.3268 +
25.3269 +Each component of the slice can be a number or symbol or the asterisk
25.3270 +({\tt*}). The number of components in the slice must be the same as the
25.3271 +dimension of the parameter. For instance, if the parameter is a
25.3272 +4-dimensional array, the slice must have four components. The number of
25.3273 +asterisks in the slice is called the {\it slice dimension}.
25.3274 +
25.3275 +The effect of using slices is the following. If a $m$-dimensional slice
25.3276 +(i.e. a slice having $m$ asterisks) is specified in the data block, all
25.3277 +subsequent data records must specify subscripts of the parameter
25.3278 +members as if the parameter were $m$-dimensional, not $n$-dimensional.
25.3279 +
25.3280 +Whenever $m$ subscripts are encountered, each asterisk in the slice is
25.3281 +replaced by corresponding subscript that gives $n$ subscripts, which
25.3282 +define the actual parameter member. For example, if the slice
25.3283 +$[a,*,1,2,*]$ is in effect, and subscripts 3 and $b$ are encountered in
25.3284 +a subsequent data record, the complete subscript list used to choose a
25.3285 +parameter member is $[a,3,1,2,b]$.
25.3286 +
25.3287 +It is allowed to specify a slice having no asterisks. Such slice itself
25.3288 +defines a complete subscript list, in which case the next data record
25.3289 +should define only a single value of corresponding parameter member.
25.3290 +
25.3291 +Being once specified the slice effects until either a new slice or the
25.3292 +end of data block is encountered. Note that if no slice is specified in
25.3293 +the data block, one, components of which are all asterisks, is assumed.
25.3294 +
25.3295 +\subsubsection{Plain data record}
25.3296 +
25.3297 +The {\it plain data record} defines a subscript list and a single value
25.3298 +in the plain format. This record has the following syntactic form:
25.3299 +
25.3300 +\medskip
25.3301 +
25.3302 +\noindent\hfil
25.3303 +$t_1$ {\tt,} $t_2$ {\tt,} \dots {\tt,} $t_n$ {\tt,} $v$
25.3304 +
25.3305 +\medskip
25.3306 +
25.3307 +\noindent where $t_1$, $t_2$, \dots, $t_n$ are subscripts, and $v$ is a
25.3308 +value. Each subscript as well as the value can be a number or symbol.
25.3309 +Commae following subscripts are optional and may be omitted.
25.3310 +
25.3311 +In case of 0-dimensional parameter or slice the plain data record has
25.3312 +no subscripts and consists of a single value only.
25.3313 +
25.3314 +\subsubsection{Tabular data record}
25.3315 +
25.3316 +The {\it tabular data record} defines several values, where each value
25.3317 +is provided with two subscripts. This record has the following
25.3318 +syntactic form:
25.3319 +$$\begin{array}{cccccc}
25.3320 +\mbox{{\tt:}}&c_1&c_2&\dots&c_n&\mbox{{\tt:=}}\\
25.3321 +r_1&a_{11}&a_{12}&\dots&a_{1n}&\\
25.3322 +r_2&a_{21}&a_{22}&\dots&a_{2n}&\\
25.3323 +\multicolumn{5}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}&\\
25.3324 +r_m&a_{m1}&a_{m2}&\dots&a_{mn}&\\
25.3325 +\end{array}$$
25.3326 +where $r_1$, $r_2$, \dots, $r_m$ are numbers and/or symbols
25.3327 +corresponding to rows of the table; $c_1$, $c_2$, \dots, $c_n$ are
25.3328 +numbers and/or symbols corresponding to columns of the table, $a_{11}$,
25.3329 +$a_{12}$, \dots, $a_{mn}$ are table elements. Each element can be a
25.3330 +number or symbol or the single decimal point ({\tt.}). (In this data
25.3331 +record the delimiter {\tt:} preceding the column list and the delimiter
25.3332 +{\tt:=} following the column list cannot be omitted.)
25.3333 +
25.3334 +Each element $a_{ij}$ of the tabular data block ($1\leq i\leq m$,
25.3335 +$1\leq j\leq n$) defines two subscripts, where the first subscript is
25.3336 +$r_i$, and the second one is $c_j$. These subscripts are used in
25.3337 +conjunction with the current slice to form the complete subscript list
25.3338 +that identifies a particular member of the parameter array. If $a_{ij}$
25.3339 +is a number or symbol, this value is assigned to the parameter member.
25.3340 +However, if $a_{ij}$ is the single decimal point, the member is
25.3341 +assigned a default value specified either in the parameter data block
25.3342 +or in the parameter statement, or, if no default value is specified,
25.3343 +the member remains undefined.
25.3344 +
25.3345 +Since the tabular data record provides two subscripts for each value,
25.3346 +either the parameter or the slice currently used must be 2-dimensional.
25.3347 +
25.3348 +\subsubsection{Transposed tabular data record}
25.3349 +
25.3350 +The {\it transposed tabular data record} has the following syntactic
25.3351 +form:
25.3352 +$$\begin{array}{cccccc}
25.3353 +\mbox{{\tt(tr) :}}&c_1&c_2&\dots&c_n&\mbox{{\tt:=}}\\
25.3354 +r_1&a_{11}&a_{12}&\dots&a_{1n}&\\
25.3355 +r_2&a_{21}&a_{22}&\dots&a_{2n}&\\
25.3356 +\multicolumn{5}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}&\\
25.3357 +r_m&a_{m1}&a_{m2}&\dots&a_{mn}&\\
25.3358 +\end{array}$$
25.3359 +(In this case the delimiter {\tt:} following the keyword {\tt(tr)} is
25.3360 +optional and may be omitted.)
25.3361 +
25.3362 +This data record is completely analogous to the tabular data record
25.3363 +(see above) with only exception that the first subscript defined by
25.3364 +element $a_{ij}$ is $c_j$ while the second one is $r_i$.
25.3365 +
25.3366 +Being once specified the {\tt(tr)} indicator affects all subsequent
25.3367 +data records until either a slice or the end of data block is
25.3368 +encountered.
25.3369 +
25.3370 +\subsubsection{Tabbing data format}
25.3371 +
25.3372 +The parameter data block in the {\it tabbing format} has the following
25.3373 +syntactic form:
25.3374 +$$\begin{array}{p{12pt}@{\ }l@{\ }c@{\ }l@{\ }c@{\ }l@{\ }r@{\ }l@{\ }c
25.3375 +@{\ }l@{\ }c@{\ }l@{\ }l}
25.3376 +\multicolumn{7}{@{}c@{}}{\mbox{\tt param}\ \mbox{\tt default}\ \mbox
25.3377 +{\it value}\ \mbox{\tt:}\ \mbox{\it s}\ \mbox{\tt:}}&
25.3378 +p_1&\mbox{\tt,}&p_2&\mbox{\tt,} \dots \mbox{\tt,}&p_k&\mbox{\tt:=}\\
25.3379 +&t_{11}&\mbox{\tt,}&t_{12}&\mbox{\tt,} \dots \mbox{\tt,}&t_{1n}&
25.3380 +\mbox{\tt,}&a_{11}&\mbox{\tt,}&a_{12}&\mbox{\tt,} \dots \mbox{\tt,}&
25.3381 +a_{1k}\\
25.3382 +&t_{21}&\mbox{\tt,}&t_{22}&\mbox{\tt,} \dots \mbox{\tt,}&t_{2n}&
25.3383 +\mbox{\tt,}&a_{21}&\mbox{\tt,}&a_{22}&\mbox{\tt,} \dots \mbox{\tt,}&
25.3384 +a_{2k}\\
25.3385 +\multicolumn{13}{c}
25.3386 +{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}\\
25.3387 +&t_{m1}&\mbox{\tt,}&t_{m2}&\mbox{\tt,} \dots \mbox{\tt,}&t_{mn}&
25.3388 +\mbox{\tt,}&a_{m1}&\mbox{\tt,}&a_{m2}&\mbox{\tt,} \dots \mbox{\tt,}&
25.3389 +a_{mk}&\mbox{\tt;}\\
25.3390 +\end{array}$$
25.3391 +
25.3392 +{\it Notes:}
25.3393 +
25.3394 +1. The keyword {\tt default} may be omitted along with a value
25.3395 +following it.
25.3396 +
25.3397 +2. Symbolic name {\tt s} may be omitted along with the colon following
25.3398 +it.
25.3399 +
25.3400 +3. All comae are optional and may be omitted.
25.3401 +
25.3402 +\medskip
25.3403 +
25.3404 +The data block in the tabbing format shown above is exactly equivalent
25.3405 +to the following data blocks for $j=1,2,\dots,k$:
25.3406 +
25.3407 +\medskip
25.3408 +
25.3409 +{\tt set} {\it s} {\tt:=}
25.3410 +{\tt(}$t_{11}${\tt,}$t_{12}${\tt,}\dots{\tt,}$t_{1n}${\tt)}
25.3411 +{\tt(}$t_{21}${\tt,}$t_{22}${\tt,}\dots{\tt,}$t_{2n}${\tt)} \dots
25.3412 +{\tt(}$t_{m1}${\tt,}$t_{m2}${\tt,}\dots{\tt,}$t_{mn}${\tt)} {\tt;}
25.3413 +
25.3414 +{\tt param} $p_j$ {\tt default} {\it value} {\tt:=}
25.3415 +
25.3416 +$\!${\tt[}$t_{11}${\tt,}$t_{12}${\tt,}\dots{\tt,}$t_{1n}${\tt]}
25.3417 +$a_{1j}$
25.3418 +{\tt[}$t_{21}${\tt,}$t_{22}${\tt,}\dots{\tt,}$t_{2n}${\tt]} $a_{2j}$
25.3419 +\dots
25.3420 +{\tt[}$t_{m1}${\tt,}$t_{m2}${\tt,}\dots{\tt,}$t_{mn}${\tt]} $a_{mj}$
25.3421 +{\tt;}
25.3422 +
25.3423 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
25.3424 +
25.3425 +\appendix
25.3426 +
25.3427 +\newpage
25.3428 +
25.3429 +\section{Using suffixes}
25.3430 +
25.3431 +Suffixes can be used to retrieve additional values associated with
25.3432 +model variables, constraints, and objectives.
25.3433 +
25.3434 +A {\it suffix} consists of a period ({\tt.}) followed by a non-reserved
25.3435 +keyword. For example, if {\tt x} is a two-dimensional variable,
25.3436 +{\tt x[i,j].lb} is a numeric value equal to the lower bound of
25.3437 +elemental variable {\tt x[i,j]}, which (value) can be used everywhere
25.3438 +in expressions like a numeric parameter.
25.3439 +
25.3440 +For model variables suffixes have the following meaning:
25.3441 +
25.3442 +\medskip
25.3443 +
25.3444 +\begin{tabular}{@{}p{96pt}p{222pt}@{}}
25.3445 +{\tt.lb}&lower bound\\
25.3446 +{\tt.ub}&upper bound\\
25.3447 +{\tt.status}&status in the solution:\\
25.3448 +&0 --- undefined\\
25.3449 +&1 --- basic\\
25.3450 +&2 --- non-basic on lower bound\\
25.3451 +&3 --- non-basic on upper bound\\
25.3452 +&4 --- non-basic free (unbounded) variable\\
25.3453 +&5 --- non-basic fixed variable\\
25.3454 +{\tt.val}&primal value in the solution\\
25.3455 +{\tt.dual}&dual value (reduced cost) in the solution\\
25.3456 +\end{tabular}
25.3457 +
25.3458 +\medskip
25.3459 +
25.3460 +For model constraints and objectives suffixes have the following
25.3461 +meaning:
25.3462 +
25.3463 +\medskip
25.3464 +
25.3465 +\begin{tabular}{@{}p{96pt}p{222pt}@{}}
25.3466 +{\tt.lb}&lower bound of the linear form\\
25.3467 +{\tt.ub}&upper bound of the linear form\\
25.3468 +{\tt.status}&status in the solution:\\
25.3469 +&0 --- undefined\\
25.3470 +&1 --- non-active\\
25.3471 +&2 --- active on lower bound\\
25.3472 +&3 --- active on upper bound\\
25.3473 +&4 --- active free (unbounded) row\\
25.3474 +&5 --- active equality constraint\\
25.3475 +{\tt.val}&primal value of the linear form in the solution\\
25.3476 +{\tt.dual}&dual value (reduced cost) of the linear form in the
25.3477 +solution\\
25.3478 +\end{tabular}
25.3479 +
25.3480 +\medskip
25.3481 +
25.3482 +Note that suffixes {\tt.status}, {\tt.val}, and {\tt.dual} can be used
25.3483 +only below the solve statement.
25.3484 +
25.3485 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
25.3486 +
25.3487 +\newpage
25.3488 +
25.3489 +\section{Date and time functions}
25.3490 +
25.3491 +\noindent\hfil
25.3492 +by Andrew Makhorin \verb|<mao@gnu.org>|
25.3493 +
25.3494 +\noindent\hfil
25.3495 +and Heinrich Schuchardt \verb|<heinrich.schuchardt@gmx.de>|
25.3496 +
25.3497 +\subsection{Obtaining current calendar time}
25.3498 +\label{gmtime}
25.3499 +
25.3500 +To obtain the current calendar time in MathProg there exists the
25.3501 +function {\tt gmtime}. It has no arguments and returns the number of
25.3502 +seconds elapsed since 00:00:00 on January 1, 1970, Coordinated
25.3503 +Universal Time (UTC). For example:
25.3504 +
25.3505 +\medskip
25.3506 +
25.3507 +\verb| param utc := gmtime();|
25.3508 +
25.3509 +\medskip
25.3510 +
25.3511 +MathProg has no function to convert UTC time returned by the function
25.3512 +{\tt gmtime} to {\it local} calendar times. Thus, if you need to
25.3513 +determine the current local calendar time, you have to add to the UTC
25.3514 +time returned the time offset from UTC expressed in seconds. For
25.3515 +example, the time in Berlin during the winter is one hour ahead of UTC
25.3516 +that corresponds to the time offset +1 hour = +3600 secs, so the
25.3517 +current winter calendar time in Berlin may be determined as follows:
25.3518 +
25.3519 +\medskip
25.3520 +
25.3521 +\verb| param now := gmtime() + 3600;|
25.3522 +
25.3523 +\medskip
25.3524 +
25.3525 +\noindent Similarly, the summer time in Chicago (Central Daylight Time)
25.3526 +is five hours behind UTC, so the corresponding current local calendar
25.3527 +time may be determined as follows:
25.3528 +
25.3529 +\medskip
25.3530 +
25.3531 +\verb| param now := gmtime() - 5 * 3600;|
25.3532 +
25.3533 +\medskip
25.3534 +
25.3535 +Note that the value returned by {\tt gmtime} is volatile, i.e. being
25.3536 +called several times this function may return different values.
25.3537 +
25.3538 +\subsection{Converting character string to calendar time}
25.3539 +\label{str2time}
25.3540 +
25.3541 +The function {\tt str2time(}{\it s}{\tt,} {\it f}{\tt)} converts a
25.3542 +character string (timestamp) specified by its first argument {\it s},
25.3543 +which must be a symbolic expression, to the calendar time suitable for
25.3544 +arithmetic calculations. The conversion is controlled by the specified
25.3545 +format string {\it f} (the second argument), which also must be a
25.3546 +symbolic expression.
25.3547 +
25.3548 +The result of conversion returned by {\tt str2time} has the same
25.3549 +meaning as values returned by the function {\tt gmtime} (see Subsection
25.3550 +\ref{gmtime}, page \pageref{gmtime}). Note that {\tt str2time} does
25.3551 +{\tt not} correct the calendar time returned for the local timezone,
25.3552 +i.e. being applied to 00:00:00 on January 1, 1970 it always returns 0.
25.3553 +
25.3554 +For example, the model statements:
25.3555 +
25.3556 +\medskip
25.3557 +
25.3558 +\verb| param s, symbolic, := "07/14/98 13:47";|
25.3559 +
25.3560 +\verb| param t := str2time(s, "%m/%d/%y %H:%M");|
25.3561 +
25.3562 +\verb| display t;|
25.3563 +
25.3564 +\medskip
25.3565 +
25.3566 +\noindent produce the following printout:
25.3567 +
25.3568 +\medskip
25.3569 +
25.3570 +\verb| t = 900424020|
25.3571 +
25.3572 +\medskip
25.3573 +
25.3574 +\noindent where the calendar time printed corresponds to 13:47:00 on
25.3575 +July 14, 1998.
25.3576 +
25.3577 +\newpage
25.3578 +
25.3579 +The format string passed to the function {\tt str2time} consists of
25.3580 +conversion specifiers and ordinary characters. Each conversion
25.3581 +specifier begins with a percent ({\tt\%}) character followed by a
25.3582 +letter.
25.3583 +
25.3584 +The following conversion specifiers may be used in the format string:
25.3585 +
25.3586 +\medskip
25.3587 +
25.3588 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3589 +{\tt\%b}&The abbreviated month name (case insensitive). At least three
25.3590 +first letters of the month name must appear in the input string.\\
25.3591 +\end{tabular}
25.3592 +
25.3593 +\medskip
25.3594 +
25.3595 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3596 +{\tt\%d}&The day of the month as a decimal number (range 1 to 31).
25.3597 +Leading zero is permitted, but not required.\\
25.3598 +\end{tabular}
25.3599 +
25.3600 +\medskip
25.3601 +
25.3602 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3603 +{\tt\%h}&The same as {\tt\%b}.\\
25.3604 +\end{tabular}
25.3605 +
25.3606 +\medskip
25.3607 +
25.3608 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3609 +{\tt\%H}&The hour as a decimal number, using a 24-hour clock (range 0
25.3610 +to 23). Leading zero is permitted, but not required.\\
25.3611 +\end{tabular}
25.3612 +
25.3613 +\medskip
25.3614 +
25.3615 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3616 +{\tt\%m}&The month as a decimal number (range 1 to 12). Leading zero is
25.3617 +permitted, but not required.\\
25.3618 +\end{tabular}
25.3619 +
25.3620 +\medskip
25.3621 +
25.3622 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3623 +{\tt\%M}&The minute as a decimal number (range 0 to 59). Leading zero
25.3624 +is permitted, but not required.\\
25.3625 +\end{tabular}
25.3626 +
25.3627 +\medskip
25.3628 +
25.3629 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3630 +{\tt\%S}&The second as a decimal number (range 0 to 60). Leading zero
25.3631 +is permitted, but not required.\\
25.3632 +\end{tabular}
25.3633 +
25.3634 +\medskip
25.3635 +
25.3636 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3637 +{\tt\%y}&The year without a century as a decimal number (range 0 to 99).
25.3638 +Leading zero is permitted, but not required. Input values in the range
25.3639 +0 to 68 are considered as the years 2000 to 2068 while the values 69 to
25.3640 +99 as the years 1969 to 1999.\\
25.3641 +\end{tabular}
25.3642 +
25.3643 +\medskip
25.3644 +
25.3645 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3646 +{\tt\%z}&The offset from GMT in ISO 8601 format.\\
25.3647 +\end{tabular}
25.3648 +
25.3649 +\medskip
25.3650 +
25.3651 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3652 +{\tt\%\%}&A literal {\tt\%} character.\\
25.3653 +\end{tabular}
25.3654 +
25.3655 +\medskip
25.3656 +
25.3657 +All other (ordinary) characters in the format string must have a
25.3658 +matching character in the input string to be converted. Exceptions are
25.3659 +spaces in the input string which can match zero or more space
25.3660 +characters in the format string.
25.3661 +
25.3662 +If some date and/or time component(s) are missing in the format and,
25.3663 +therefore, in the input string, the function {\tt str2time} uses their
25.3664 +default values corresponding to 00:00:00 on January 1, 1970, that is,
25.3665 +the default value of the year is 1970, the default value of the month
25.3666 +is January, etc.
25.3667 +
25.3668 +The function {\tt str2time} is applicable to all calendar times in the
25.3669 +range 00:00:00 on January 1, 0001 to 23:59:59 on December 31, 4000 of
25.3670 +the Gregorian calendar.
25.3671 +
25.3672 +\subsection{Converting calendar time to character string}
25.3673 +\label{time2str}
25.3674 +
25.3675 +The function {\tt time2str(}{\it t}{\tt,} {\it f}{\tt)} converts the
25.3676 +calendar time specified by its first argument {\it t}, which must be a
25.3677 +numeric expression, to a character string (symbolic value). The
25.3678 +conversion is controlled by the specified format string {\it f} (the
25.3679 +second argument), which must be a symbolic expression.
25.3680 +
25.3681 +The calendar time passed to {\tt time2str} has the same meaning as
25.3682 +values returned by the function {\tt gmtime} (see Subsection
25.3683 +\ref{gmtime}, page \pageref{gmtime}). Note that {\tt time2str} does
25.3684 +{\it not} correct the specified calendar time for the local timezone,
25.3685 +i.e. the calendar time 0 always corresponds to 00:00:00 on January 1,
25.3686 +1970.
25.3687 +
25.3688 +For example, the model statements:
25.3689 +
25.3690 +\medskip
25.3691 +
25.3692 +\verb| param s, symbolic, := time2str(gmtime(), "%FT%TZ");|
25.3693 +
25.3694 +\verb| display s;|
25.3695 +
25.3696 +\medskip
25.3697 +
25.3698 +\noindent may produce the following printout:
25.3699 +
25.3700 +\medskip
25.3701 +
25.3702 +\verb| s = '2008-12-04T00:23:45Z'|
25.3703 +
25.3704 +\medskip
25.3705 +
25.3706 +\noindent which is a timestamp in the ISO format.
25.3707 +
25.3708 +The format string passed to the function {\tt time2str} consists of
25.3709 +conversion specifiers and ordinary characters. Each conversion
25.3710 +specifier begins with a percent ({\tt\%}) character followed by a
25.3711 +letter.
25.3712 +
25.3713 +The following conversion specifiers may be used in the format string:
25.3714 +
25.3715 +\medskip
25.3716 +
25.3717 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3718 +{\tt\%a}&The abbreviated (2-character) weekday name.\\
25.3719 +\end{tabular}
25.3720 +
25.3721 +\medskip
25.3722 +
25.3723 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3724 +{\tt\%A}&The full weekday name.\\
25.3725 +\end{tabular}
25.3726 +
25.3727 +\medskip
25.3728 +
25.3729 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3730 +{\tt\%b}&The abbreviated (3-character) month name.\\
25.3731 +\end{tabular}
25.3732 +
25.3733 +\medskip
25.3734 +
25.3735 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3736 +{\tt\%B}&The full month name.\\
25.3737 +\end{tabular}
25.3738 +
25.3739 +\medskip
25.3740 +
25.3741 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3742 +{\tt\%C}&The century of the year, that is the greatest integer not
25.3743 +greater than the year divided by 100.\\
25.3744 +\end{tabular}
25.3745 +
25.3746 +\medskip
25.3747 +
25.3748 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3749 +{\tt\%d}&The day of the month as a decimal number (range 01 to 31).\\
25.3750 +\end{tabular}
25.3751 +
25.3752 +\medskip
25.3753 +
25.3754 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3755 +{\tt\%D}&The date using the format \verb|%m/%d/%y|.\\
25.3756 +\end{tabular}
25.3757 +
25.3758 +\medskip
25.3759 +
25.3760 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3761 +{\tt\%e}&The day of the month like with \verb|%d|, but padded with
25.3762 +blank rather than zero.\\
25.3763 +\end{tabular}
25.3764 +
25.3765 +\medskip
25.3766 +
25.3767 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3768 +{\tt\%F}&The date using the format \verb|%Y-%m-%d|.\\
25.3769 +\end{tabular}
25.3770 +
25.3771 +\medskip
25.3772 +
25.3773 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3774 +{\tt\%g}&The year corresponding to the ISO week number, but without the
25.3775 +century (range 00 to 99). This has the same format and value as
25.3776 +\verb|%y|, except that if the ISO week number (see \verb|%V|) belongs
25.3777 +to the previous or next year, that year is used instead.\\
25.3778 +\end{tabular}
25.3779 +
25.3780 +\medskip
25.3781 +
25.3782 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3783 +{\tt\%G}&The year corresponding to the ISO week number. This has the
25.3784 +same format and value as \verb|%Y|, except that if the ISO week number
25.3785 +(see \verb|%V|) belongs to the previous or next year, that year is used
25.3786 +instead.
25.3787 +\end{tabular}
25.3788 +
25.3789 +\medskip
25.3790 +
25.3791 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3792 +{\tt\%h}&The same as \verb|%b|.\\
25.3793 +\end{tabular}
25.3794 +
25.3795 +\medskip
25.3796 +
25.3797 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3798 +{\tt\%H}&The hour as a decimal number, using a 24-hour clock (range 00
25.3799 +to 23).\\
25.3800 +\end{tabular}
25.3801 +
25.3802 +\medskip
25.3803 +
25.3804 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3805 +{\tt\%I}&The hour as a decimal number, using a 12-hour clock (range 01
25.3806 +to 12).\\
25.3807 +\end{tabular}
25.3808 +
25.3809 +\medskip
25.3810 +
25.3811 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3812 +{\tt\%j}&The day of the year as a decimal number (range 001 to 366).\\
25.3813 +\end{tabular}
25.3814 +
25.3815 +\medskip
25.3816 +
25.3817 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3818 +{\tt\%k}&The hour as a decimal number, using a 24-hour clock like
25.3819 +\verb|%H|, but padded with blank rather than zero.\\
25.3820 +\end{tabular}
25.3821 +
25.3822 +\medskip
25.3823 +
25.3824 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3825 +{\tt\%l}&The hour as a decimal number, using a 12-hour clock like
25.3826 +\verb|%I|, but padded with blank rather than zero.
25.3827 +\end{tabular}
25.3828 +
25.3829 +\medskip
25.3830 +
25.3831 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3832 +{\tt\%m}&The month as a decimal number (range 01 to 12).\\
25.3833 +\end{tabular}
25.3834 +
25.3835 +\medskip
25.3836 +
25.3837 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3838 +{\tt\%M}&The minute as a decimal number (range 00 to 59).\\
25.3839 +\end{tabular}
25.3840 +
25.3841 +\medskip
25.3842 +
25.3843 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3844 +{\tt\%p}&Either {\tt AM} or {\tt PM}, according to the given time value.
25.3845 +Midnight is treated as {\tt AM} and noon as {\tt PM}.\\
25.3846 +\end{tabular}
25.3847 +
25.3848 +\medskip
25.3849 +
25.3850 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3851 +{\tt\%P}&Either {\tt am} or {\tt pm}, according to the given time value.
25.3852 +Midnight is treated as {\tt am} and noon as {\tt pm}.\\
25.3853 +\end{tabular}
25.3854 +
25.3855 +\medskip
25.3856 +
25.3857 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3858 +{\tt\%R}&The hour and minute in decimal numbers using the format
25.3859 +\verb|%H:%M|.\\
25.3860 +\end{tabular}
25.3861 +
25.3862 +\medskip
25.3863 +
25.3864 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3865 +{\tt\%S}&The second as a decimal number (range 00 to 59).\\
25.3866 +\end{tabular}
25.3867 +
25.3868 +\medskip
25.3869 +
25.3870 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3871 +{\tt\%T}&The time of day in decimal numbers using the format
25.3872 +\verb|%H:%M:%S|.\\
25.3873 +\end{tabular}
25.3874 +
25.3875 +\medskip
25.3876 +
25.3877 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3878 +{\tt\%u}&The day of the week as a decimal number (range 1 to 7), Monday
25.3879 +being 1.\\
25.3880 +\end{tabular}
25.3881 +
25.3882 +\medskip
25.3883 +
25.3884 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3885 +{\tt\%U}&The week number of the current year as a decimal number (range
25.3886 +00 to 53), starting with the first Sunday as the first day of the first
25.3887 +week. Days preceding the first Sunday in the year are considered to be
25.3888 +in week 00.
25.3889 +\end{tabular}
25.3890 +
25.3891 +\medskip
25.3892 +
25.3893 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3894 +{\tt\%V}&The ISO week number as a decimal number (range 01 to 53). ISO
25.3895 +weeks start with Monday and end with Sunday. Week 01 of a year is the
25.3896 +first week which has the majority of its days in that year; this is
25.3897 +equivalent to the week containing January 4. Week 01 of a year can
25.3898 +contain days from the previous year. The week before week 01 of a year
25.3899 +is the last week (52 or 53) of the previous year even if it contains
25.3900 +days from the new year. In other word, if 1 January is Monday, Tuesday,
25.3901 +Wednesday or Thursday, it is in week 01; if 1 January is Friday,
25.3902 +Saturday or Sunday, it is in week 52 or 53 of the previous year.\\
25.3903 +\end{tabular}
25.3904 +
25.3905 +\medskip
25.3906 +
25.3907 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3908 +{\tt\%w}&The day of the week as a decimal number (range 0 to 6), Sunday
25.3909 +being 0.\\
25.3910 +\end{tabular}
25.3911 +
25.3912 +\medskip
25.3913 +
25.3914 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3915 +{\tt\%W}&The week number of the current year as a decimal number (range
25.3916 +00 to 53), starting with the first Monday as the first day of the first
25.3917 +week. Days preceding the first Monday in the year are considered to be
25.3918 +in week 00.\\
25.3919 +\end{tabular}
25.3920 +
25.3921 +\medskip
25.3922 +
25.3923 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3924 +{\tt\%y}&The year without a century as a decimal number (range 00 to
25.3925 +99), that is the year modulo 100.\\
25.3926 +\end{tabular}
25.3927 +
25.3928 +\medskip
25.3929 +
25.3930 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3931 +{\tt\%Y}&The year as a decimal number, using the Gregorian calendar.\\
25.3932 +\end{tabular}
25.3933 +
25.3934 +\medskip
25.3935 +
25.3936 +\begin{tabular}{@{}p{20pt}p{298pt}@{}}
25.3937 +{\tt\%\%}&A literal \verb|%| character.\\
25.3938 +\end{tabular}
25.3939 +
25.3940 +\medskip
25.3941 +
25.3942 +All other (ordinary) characters in the format string are simply copied
25.3943 +to the resultant string.
25.3944 +
25.3945 +The first argument (calendar time) passed to the function {\tt time2str}
25.3946 +must be in the range from $-62135596800$ to $+64092211199$ that
25.3947 +corresponds to the period from 00:00:00 on January 1, 0001 to 23:59:59
25.3948 +on December 31, 4000 of the Gregorian calendar.
25.3949 +
25.3950 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
25.3951 +
25.3952 +\newpage
25.3953 +
25.3954 +\section{Table drivers}
25.3955 +\label{drivers}
25.3956 +
25.3957 +\noindent\hfil
25.3958 +by Andrew Makhorin \verb|<mao@gnu.org>|
25.3959 +
25.3960 +\noindent\hfil
25.3961 +and Heinrich Schuchardt \verb|<heinrich.schuchardt@gmx.de>|
25.3962 +
25.3963 +\bigskip\bigskip
25.3964 +
25.3965 +The {\it table driver} is a program module which provides transmitting
25.3966 +data between MathProg model objects and data tables.
25.3967 +
25.3968 +Currently the GLPK package has four table drivers:
25.3969 +
25.3970 +\setlength{\leftmargini}{2.5em}
25.3971 +
25.3972 +\begin{itemize}
25.3973 +\item built-in CSV table driver;
25.3974 +\item built-in xBASE table driver;
25.3975 +\item ODBC table driver;
25.3976 +\item MySQL table driver.
25.3977 +\end{itemize}
25.3978 +
25.3979 +\subsection{CSV table driver}
25.3980 +
25.3981 +The CSV table driver assumes that the data table is represented in the
25.3982 +form of a plain text file in the CSV (comma-separated values) file
25.3983 +format as described below.
25.3984 +
25.3985 +To choose the CSV table driver its name in the table statement should
25.3986 +be specified as \verb|"CSV"|, and the only argument should specify the
25.3987 +name of a plain text file containing the table. For example:
25.3988 +
25.3989 +\medskip
25.3990 +
25.3991 +\verb| table data IN "CSV" "data.csv": ... ;|
25.3992 +
25.3993 +\medskip
25.3994 +
25.3995 +The filename suffix may be arbitrary, however, it is recommended to use
25.3996 +the suffix `\verb|.csv|'.
25.3997 +
25.3998 +On reading input tables the CSV table driver provides an implicit field
25.3999 +named \verb|RECNO|, which contains the current record number. This
25.4000 +field can be specified in the input table statement as if there were
25.4001 +the actual field having the name \verb|RECNO| in the CSV file. For
25.4002 +example:
25.4003 +
25.4004 +\medskip
25.4005 +
25.4006 +\verb| table list IN "CSV" "list.csv": num <- [RECNO], ... ;|
25.4007 +
25.4008 +\subsubsection*{CSV format\footnote{This material is based on the RFC
25.4009 +document 4180.}}
25.4010 +
25.4011 +The CSV (comma-separated values) format is a plain text file format
25.4012 +defined as follows.
25.4013 +
25.4014 +1. Each record is located on a separate line, delimited by a line
25.4015 +break. For example:
25.4016 +
25.4017 +\medskip
25.4018 +
25.4019 +\verb| aaa,bbb,ccc\n|
25.4020 +
25.4021 +\verb| xxx,yyy,zzz\n|
25.4022 +
25.4023 +\medskip
25.4024 +
25.4025 +\noindent
25.4026 +where \verb|\n| means the control character \verb|LF| ({\tt 0x0A}).
25.4027 +
25.4028 +\newpage
25.4029 +
25.4030 +2. The last record in the file may or may not have an ending line
25.4031 +break. For example:
25.4032 +
25.4033 +\medskip
25.4034 +
25.4035 +\verb| aaa,bbb,ccc\n|
25.4036 +
25.4037 +\verb| xxx,yyy,zzz|
25.4038 +
25.4039 +\medskip
25.4040 +
25.4041 +3. There should be a header line appearing as the first line of the
25.4042 +file in the same format as normal record lines. This header should
25.4043 +contain names corresponding to the fields in the file. The number of
25.4044 +field names in the header line should be the same as the number of
25.4045 +fields in the records of the file. For example:
25.4046 +
25.4047 +\medskip
25.4048 +
25.4049 +\verb| name1,name2,name3\n|
25.4050 +
25.4051 +\verb| aaa,bbb,ccc\n|
25.4052 +
25.4053 +\verb| xxx,yyy,zzz\n|
25.4054 +
25.4055 +\medskip
25.4056 +
25.4057 +4. Within the header and each record there may be one or more fields
25.4058 +separated by commas. Each line should contain the same number of fields
25.4059 +throughout the file. Spaces are considered as part of a field and
25.4060 +therefore not ignored. The last field in the record should not be
25.4061 +followed by a comma. For example:
25.4062 +
25.4063 +\medskip
25.4064 +
25.4065 +\verb| aaa,bbb,ccc\n|
25.4066 +
25.4067 +\medskip
25.4068 +
25.4069 +5. Fields may or may not be enclosed in double quotes. For example:
25.4070 +
25.4071 +\medskip
25.4072 +
25.4073 +\verb| "aaa","bbb","ccc"\n|
25.4074 +
25.4075 +\verb| zzz,yyy,xxx\n|
25.4076 +
25.4077 +\medskip
25.4078 +
25.4079 +6. If a field is enclosed in double quotes, each double quote which is
25.4080 +part of the field should be coded twice. For example:
25.4081 +
25.4082 +\medskip
25.4083 +
25.4084 +\verb| "aaa","b""bb","ccc"\n|
25.4085 +
25.4086 +\medskip
25.4087 +
25.4088 +\noindent{\bf Example}
25.4089 +
25.4090 +\begin{verbatim}
25.4091 +FROM,TO,DISTANCE,COST
25.4092 +Seattle,New-York,2.5,0.12
25.4093 +Seattle,Chicago,1.7,0.08
25.4094 +Seattle,Topeka,1.8,0.09
25.4095 +San-Diego,New-York,2.5,0.15
25.4096 +San-Diego,Chicago,1.8,0.10
25.4097 +San-Diego,Topeka,1.4,0.07
25.4098 +\end{verbatim}
25.4099 +
25.4100 +\subsection{xBASE table driver}
25.4101 +
25.4102 +The xBASE table driver assumes that the data table is stored in the
25.4103 +.dbf file format.
25.4104 +
25.4105 +To choose the xBASE table driver its name in the table statement should
25.4106 +be specified as \verb|"xBASE"|, and the first argument should specify
25.4107 +the name of a .dbf file containing the table. For the output table there
25.4108 +should be the second argument defining the table format in the form
25.4109 +\verb|"FF...F"|, where \verb|F| is either {\tt C({\it n})},
25.4110 +which specifies a character field of length $n$, or
25.4111 +{\tt N({\it n}{\rm [},{\it p}{\rm ]})}, which specifies a numeric field
25.4112 +of length $n$ and precision $p$ (by default $p$ is 0).
25.4113 +
25.4114 +The following is a simple example which illustrates creating and
25.4115 +reading a .dbf file:
25.4116 +
25.4117 +\begin{verbatim}
25.4118 +table tab1{i in 1..10} OUT "xBASE" "foo.dbf"
25.4119 + "N(5)N(10,4)C(1)C(10)": 2*i+1 ~ B, Uniform(-20,+20) ~ A,
25.4120 + "?" ~ FOO, "[" & i & "]" ~ C;
25.4121 +set S, dimen 4;
25.4122 +table tab2 IN "xBASE" "foo.dbf": S <- [B, C, RECNO, A];
25.4123 +display S;
25.4124 +end;
25.4125 +\end{verbatim}
25.4126 +
25.4127 +\subsection{ODBC table driver}
25.4128 +
25.4129 +The ODBC table driver allows connecting to SQL databases using an
25.4130 +implementation of the ODBC interface based on the Call Level Interface
25.4131 +(CLI).\footnote{The corresponding software standard is defined in
25.4132 +ISO/IEC 9075-3:2003.}
25.4133 +
25.4134 +\paragraph{Debian GNU/Linux.}
25.4135 +Under Debian GNU/Linux the ODBC table driver uses the iODBC
25.4136 +package,\footnote{See {\tt<http://www.iodbc.org/>}.} which should be
25.4137 +installed before building the GLPK package. The installation can be
25.4138 +effected with the following command:
25.4139 +
25.4140 +\begin{verbatim}
25.4141 +sudo apt-get install libiodbc2-dev
25.4142 +\end{verbatim}
25.4143 +
25.4144 +Note that on configuring the GLPK package to enable using the iODBC
25.4145 +library the option `\verb|--enable-odbc|' should be passed to the
25.4146 +configure script.
25.4147 +
25.4148 +The individual databases must be entered for systemwide usage in
25.4149 +\linebreak \verb|/etc/odbc.ini| and \verb|/etc/odbcinst.ini|. Database
25.4150 +connections to be used by a single user are specified by files in the
25.4151 +home directory (\verb|.odbc.ini| and \verb|.odbcinst.ini|).
25.4152 +
25.4153 +\paragraph{Microsoft Windows.}
25.4154 +Under Microsoft Windows the ODBC table driver uses the Microsoft ODBC
25.4155 +library. To enable this feature the symbol:
25.4156 +
25.4157 +\begin{verbatim}
25.4158 +#define ODBC_DLNAME "odbc32.dll"
25.4159 +\end{verbatim}
25.4160 +
25.4161 +\noindent
25.4162 +should be defined in the GLPK configuration file `\verb|config.h|'.
25.4163 +
25.4164 +Data sources can be created via the Administrative Tools from the
25.4165 +Control Panel.
25.4166 +
25.4167 +\bigskip
25.4168 +
25.4169 +To choose the ODBC table driver its name in the table statement should
25.4170 +be specified as \verb|'ODBC'| or \verb|'iODBC'|.
25.4171 +
25.4172 +The argument list is specified as follows.
25.4173 +
25.4174 +The first argument is the connection string passed to the ODBC library,
25.4175 +for example:
25.4176 +
25.4177 +\verb|'DSN=glpk;UID=user;PWD=password'|, or
25.4178 +
25.4179 +\verb|'DRIVER=MySQL;DATABASE=glpkdb;UID=user;PWD=password'|.
25.4180 +
25.4181 +Different parts of the string are separated by semicolons. Each part
25.4182 +consists of a pair {\it fieldname} and {\it value} separated by the
25.4183 +equal sign. Allowable fieldnames depend on the ODBC library. Typically
25.4184 +the following fieldnames are allowed:
25.4185 +
25.4186 +\verb|DATABASE | database;
25.4187 +
25.4188 +\verb|DRIVER | ODBC driver;
25.4189 +
25.4190 +\verb|DSN | name of a data source;
25.4191 +
25.4192 +\verb|FILEDSN | name of a file data source;
25.4193 +
25.4194 +\verb|PWD | user password;
25.4195 +
25.4196 +\verb|SERVER | database;
25.4197 +
25.4198 +\verb|UID | user name.
25.4199 +
25.4200 +The second argument and all following are considered to be SQL
25.4201 +statements
25.4202 +
25.4203 +SQL statements may be spread over multiple arguments. If the last
25.4204 +character of an argument is a semicolon this indicates the end of
25.4205 +a SQL statement.
25.4206 +
25.4207 +The arguments of a SQL statement are concatenated separated by space.
25.4208 +The eventual trailing semicolon will be removed.
25.4209 +
25.4210 +All but the last SQL statement will be executed directly.
25.4211 +
25.4212 +For IN-table the last SQL statement can be a SELECT command starting
25.4213 +with the capitalized letters \verb|'SELECT '|. If the string does not
25.4214 +start with \verb|'SELECT '| it is considered to be a table name and a
25.4215 +SELECT statement is automatically generated.
25.4216 +
25.4217 +For OUT-table the last SQL statement can contain one or multiple
25.4218 +question marks. If it contains a question mark it is considered a
25.4219 +template for the write routine. Otherwise the string is considered a
25.4220 +table name and an INSERT template is automatically generated.
25.4221 +
25.4222 +The writing routine uses the template with the question marks and
25.4223 +replaces the first question mark by the first output parameter, the
25.4224 +second question mark by the second output parameter and so forth. Then
25.4225 +the SQL command is issued.
25.4226 +
25.4227 +The following is an example of the output table statement:
25.4228 +
25.4229 +\begin{small}
25.4230 +\begin{verbatim}
25.4231 +table ta { l in LOCATIONS } OUT
25.4232 + 'ODBC'
25.4233 + 'DSN=glpkdb;UID=glpkuser;PWD=glpkpassword'
25.4234 + 'DROP TABLE IF EXISTS result;'
25.4235 + 'CREATE TABLE result ( ID INT, LOC VARCHAR(255), QUAN DOUBLE );'
25.4236 + 'INSERT INTO result 'VALUES ( 4, ?, ? )' :
25.4237 + l ~ LOC, quantity[l] ~ QUAN;
25.4238 +\end{verbatim}
25.4239 +\end{small}
25.4240 +
25.4241 +\noindent
25.4242 +Alternatively it could be written as follows:
25.4243 +
25.4244 +\begin{small}
25.4245 +\begin{verbatim}
25.4246 +table ta { l in LOCATIONS } OUT
25.4247 + 'ODBC'
25.4248 + 'DSN=glpkdb;UID=glpkuser;PWD=glpkpassword'
25.4249 + 'DROP TABLE IF EXISTS result;'
25.4250 + 'CREATE TABLE result ( ID INT, LOC VARCHAR(255), QUAN DOUBLE );'
25.4251 + 'result' :
25.4252 + l ~ LOC, quantity[l] ~ QUAN, 4 ~ ID;
25.4253 +\end{verbatim}
25.4254 +\end{small}
25.4255 +
25.4256 +Using templates with `\verb|?|' supports not only INSERT, but also
25.4257 +UPDATE, DELETE, etc. For example:
25.4258 +
25.4259 +\begin{small}
25.4260 +\begin{verbatim}
25.4261 +table ta { l in LOCATIONS } OUT
25.4262 + 'ODBC'
25.4263 + 'DSN=glpkdb;UID=glpkuser;PWD=glpkpassword'
25.4264 + 'UPDATE result SET DATE = ' & date & ' WHERE ID = 4;'
25.4265 + 'UPDATE result SET QUAN = ? WHERE LOC = ? AND ID = 4' :
25.4266 + quantity[l], l;
25.4267 +\end{verbatim}
25.4268 +\end{small}
25.4269 +
25.4270 +\subsection{MySQL table driver}
25.4271 +
25.4272 +The MySQL table driver allows connecting to MySQL databases.
25.4273 +
25.4274 +\paragraph{Debian GNU/Linux.}
25.4275 +Under Debian GNU/Linux the MySQL table\linebreak driver uses the MySQL
25.4276 +package,\footnote{For download development files see
25.4277 +{\tt<http://dev.mysql.com/downloads/mysql/>}.} which should be installed
25.4278 +before building the GLPK package. The installation can be effected with
25.4279 +the following command:
25.4280 +
25.4281 +\begin{verbatim}
25.4282 +sudo apt-get install libmysqlclient15-dev
25.4283 +\end{verbatim}
25.4284 +
25.4285 +Note that on configuring the GLPK package to enable using the MySQL
25.4286 +library the option `\verb|--enable-mysql|' should be passed to the
25.4287 +configure script.
25.4288 +
25.4289 +\paragraph{Microsoft Windows.}
25.4290 +Under Microsoft Windows the MySQL table driver also uses the MySQL
25.4291 +library. To enable this feature the symbol:
25.4292 +
25.4293 +\begin{verbatim}
25.4294 +#define MYSQL_DLNAME "libmysql.dll"
25.4295 +\end{verbatim}
25.4296 +
25.4297 +\noindent
25.4298 +should be defined in the GLPK configuration file `\verb|config.h|'.
25.4299 +
25.4300 +\bigskip
25.4301 +
25.4302 +To choose the MySQL table driver its name in the table statement should
25.4303 +be specified as \verb|'MySQL'|.
25.4304 +
25.4305 +The argument list is specified as follows.
25.4306 +
25.4307 +The first argument specifies how to connect the data base in the DSN
25.4308 +style, for example:
25.4309 +
25.4310 +\verb|'Database=glpk;UID=glpk;PWD=gnu'|.
25.4311 +
25.4312 +Different parts of the string are separated by semicolons. Each part
25.4313 +consists of a pair {\it fieldname} and {\it value} separated by the
25.4314 +equal sign. The following fieldnames are allowed:
25.4315 +
25.4316 +\verb|Server | server running the database (defaulting to localhost);
25.4317 +
25.4318 +\verb|Database | name of the database;
25.4319 +
25.4320 +\verb|UID | user name;
25.4321 +
25.4322 +\verb|PWD | user password;
25.4323 +
25.4324 +\verb|Port | port used by the server (defaulting to 3306).
25.4325 +
25.4326 +The second argument and all following are considered to be SQL
25.4327 +statements
25.4328 +
25.4329 +SQL statements may be spread over multiple arguments. If the last
25.4330 +character of an argument is a semicolon this indicates the end of
25.4331 +a SQL statement.
25.4332 +
25.4333 +The arguments of a SQL statement are concatenated separated by space.
25.4334 +The eventual trailing semicolon will be removed.
25.4335 +
25.4336 +All but the last SQL statement will be executed directly.
25.4337 +
25.4338 +For IN-table the last SQL statement can be a SELECT command starting
25.4339 +with the capitalized letters \verb|'SELECT '|. If the string does not
25.4340 +start with \verb|'SELECT '| it is considered to be a table name and a
25.4341 +SELECT statement is automatically generated.
25.4342 +
25.4343 +For OUT-table the last SQL statement can contain one or multiple
25.4344 +question marks. If it contains a question mark it is considered a
25.4345 +template for the write routine. Otherwise the string is considered a
25.4346 +table name and an INSERT template is automatically generated.
25.4347 +
25.4348 +The writing routine uses the template with the question marks and
25.4349 +replaces the first question mark by the first output parameter, the
25.4350 +second question mark by the second output parameter and so forth. Then
25.4351 +the SQL command is issued.
25.4352 +
25.4353 +The following is an example of the output table statement:
25.4354 +
25.4355 +\begin{small}
25.4356 +\begin{verbatim}
25.4357 +table ta { l in LOCATIONS } OUT
25.4358 + 'MySQL'
25.4359 + 'Database=glpkdb;UID=glpkuser;PWD=glpkpassword'
25.4360 + 'DROP TABLE IF EXISTS result;'
25.4361 + 'CREATE TABLE result ( ID INT, LOC VARCHAR(255), QUAN DOUBLE );'
25.4362 + 'INSERT INTO result VALUES ( 4, ?, ? )' :
25.4363 + l ~ LOC, quantity[l] ~ QUAN;
25.4364 +\end{verbatim}
25.4365 +\end{small}
25.4366 +
25.4367 +\noindent
25.4368 +Alternatively it could be written as follows:
25.4369 +
25.4370 +\begin{small}
25.4371 +\begin{verbatim}
25.4372 +table ta { l in LOCATIONS } OUT
25.4373 + 'MySQL'
25.4374 + 'Database=glpkdb;UID=glpkuser;PWD=glpkpassword'
25.4375 + 'DROP TABLE IF EXISTS result;'
25.4376 + 'CREATE TABLE result ( ID INT, LOC VARCHAR(255), QUAN DOUBLE );'
25.4377 + 'result' :
25.4378 + l ~ LOC, quantity[l] ~ QUAN, 4 ~ ID;
25.4379 +\end{verbatim}
25.4380 +\end{small}
25.4381 +
25.4382 +Using templates with `\verb|?|' supports not only INSERT, but also
25.4383 +UPDATE, DELETE, etc. For example:
25.4384 +
25.4385 +\begin{small}
25.4386 +\begin{verbatim}
25.4387 +table ta { l in LOCATIONS } OUT
25.4388 + 'MySQL'
25.4389 + 'Database=glpkdb;UID=glpkuser;PWD=glpkpassword'
25.4390 + 'UPDATE result SET DATE = ' & date & ' WHERE ID = 4;'
25.4391 + 'UPDATE result SET QUAN = ? WHERE LOC = ? AND ID = 4' :
25.4392 + quantity[l], l;
25.4393 +\end{verbatim}
25.4394 +\end{small}
25.4395 +
25.4396 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
25.4397 +
25.4398 +\newpage
25.4399 +
25.4400 +\section{Solving models with glpsol}
25.4401 +
25.4402 +The GLPK package\footnote{{\tt http://www.gnu.org/software/glpk/}}
25.4403 +includes the program {\tt glpsol}, which is a stand-alone LP/MIP solver.
25.4404 +This program can be launched from the command line or from the shell to
25.4405 +solve models written in the GNU MathProg modeling language.
25.4406 +
25.4407 +In order to tell the solver that the input file contains a model
25.4408 +description, you need to specify the option \verb|--model| in the
25.4409 +command line. For example:
25.4410 +
25.4411 +\medskip
25.4412 +
25.4413 +\verb| glpsol --model foo.mod|
25.4414 +
25.4415 +\medskip
25.4416 +
25.4417 +Sometimes it is necessary to use the data section placed in a separate
25.4418 +file, in which case you may use the following command:
25.4419 +
25.4420 +\medskip
25.4421 +
25.4422 +\verb| glpsol --model foo.mod --data foo.dat|
25.4423 +
25.4424 +\medskip
25.4425 +
25.4426 +\noindent Note that if the model file also contains the data section,
25.4427 +that section is ignored.
25.4428 +
25.4429 +If the model description contains some display and/or printf statements,
25.4430 +by default the output is sent to the terminal. In order to redirect the
25.4431 +output to a file you may use the following command:
25.4432 +
25.4433 +\medskip
25.4434 +
25.4435 +\verb| glpsol --model foo.mod --display foo.out|
25.4436 +
25.4437 +\medskip
25.4438 +
25.4439 +If you need to look at the problem, which has been generated by the
25.4440 +model translator, you may use the option \verb|--wlp| as follows:
25.4441 +
25.4442 +\medskip
25.4443 +
25.4444 +\verb| glpsol --model foo.mod --wlp foo.lp|
25.4445 +
25.4446 +\medskip
25.4447 +
25.4448 +\noindent in which case the problem data is written to file
25.4449 +\verb|foo.lp| in CPLEX LP format suitable for visual analysis.
25.4450 +
25.4451 +Sometimes it is needed merely to check the model description not
25.4452 +solving the generated problem instance. In this case you may specify
25.4453 +the option \verb|--check|, for example:
25.4454 +
25.4455 +\medskip
25.4456 +
25.4457 +\verb| glpsol --check --model foo.mod --wlp foo.lp|
25.4458 +
25.4459 +\medskip
25.4460 +
25.4461 +In order to write a numeric solution obtained by the solver you may use
25.4462 +the following command:
25.4463 +
25.4464 +\medskip
25.4465 +
25.4466 +\verb| glpsol --model foo.mod --output foo.sol|
25.4467 +
25.4468 +\medskip
25.4469 +
25.4470 +\noindent in which case the solution is written to file \verb|foo.sol|
25.4471 +in a plain text format.
25.4472 +
25.4473 +The complete list of the \verb|glpsol| options can be found in the
25.4474 +reference manual included in the GLPK distribution.
25.4475 +
25.4476 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
25.4477 +
25.4478 +\newpage
25.4479 +
25.4480 +\section{Example model description}
25.4481 +
25.4482 +\subsection{Model description written in MathProg}
25.4483 +
25.4484 +Below here is a complete example of the model description written in
25.4485 +the GNU MathProg modeling language.
25.4486 +
25.4487 +\begin{small}
25.4488 +\begin{verbatim}
25.4489 +# A TRANSPORTATION PROBLEM
25.4490 +#
25.4491 +# This problem finds a least cost shipping schedule that meets
25.4492 +# requirements at markets and supplies at factories.
25.4493 +#
25.4494 +# References:
25.4495 +# Dantzig G B, "Linear Programming and Extensions."
25.4496 +# Princeton University Press, Princeton, New Jersey, 1963,
25.4497 +# Chapter 3-3.
25.4498 +
25.4499 +set I;
25.4500 +/* canning plants */
25.4501 +
25.4502 +set J;
25.4503 +/* markets */
25.4504 +
25.4505 +param a{i in I};
25.4506 +/* capacity of plant i in cases */
25.4507 +
25.4508 +param b{j in J};
25.4509 +/* demand at market j in cases */
25.4510 +
25.4511 +param d{i in I, j in J};
25.4512 +/* distance in thousands of miles */
25.4513 +
25.4514 +param f;
25.4515 +/* freight in dollars per case per thousand miles */
25.4516 +
25.4517 +param c{i in I, j in J} := f * d[i,j] / 1000;
25.4518 +/* transport cost in thousands of dollars per case */
25.4519 +
25.4520 +var x{i in I, j in J} >= 0;
25.4521 +/* shipment quantities in cases */
25.4522 +
25.4523 +minimize cost: sum{i in I, j in J} c[i,j] * x[i,j];
25.4524 +/* total transportation costs in thousands of dollars */
25.4525 +
25.4526 +s.t. supply{i in I}: sum{j in J} x[i,j] <= a[i];
25.4527 +/* observe supply limit at plant i */
25.4528 +
25.4529 +s.t. demand{j in J}: sum{i in I} x[i,j] >= b[j];
25.4530 +/* satisfy demand at market j */
25.4531 +
25.4532 +data;
25.4533 +
25.4534 +set I := Seattle San-Diego;
25.4535 +
25.4536 +set J := New-York Chicago Topeka;
25.4537 +
25.4538 +param a := Seattle 350
25.4539 + San-Diego 600;
25.4540 +
25.4541 +param b := New-York 325
25.4542 + Chicago 300
25.4543 + Topeka 275;
25.4544 +
25.4545 +param d : New-York Chicago Topeka :=
25.4546 + Seattle 2.5 1.7 1.8
25.4547 + San-Diego 2.5 1.8 1.4 ;
25.4548 +
25.4549 +param f := 90;
25.4550 +
25.4551 +end;
25.4552 +\end{verbatim}
25.4553 +\end{small}
25.4554 +
25.4555 +\subsection{Generated LP problem instance}
25.4556 +
25.4557 +Below here is the result of the translation of the example model
25.4558 +produced by the solver \verb|glpsol| and written in CPLEX LP format
25.4559 +with the option \verb|--wlp|.
25.4560 +
25.4561 +\begin{small}
25.4562 +\begin{verbatim}
25.4563 +\* Problem: transp *\
25.4564 +
25.4565 +Minimize
25.4566 + cost: + 0.225 x(Seattle,New~York) + 0.153 x(Seattle,Chicago)
25.4567 + + 0.162 x(Seattle,Topeka) + 0.225 x(San~Diego,New~York)
25.4568 + + 0.162 x(San~Diego,Chicago) + 0.126 x(San~Diego,Topeka)
25.4569 +
25.4570 +Subject To
25.4571 + supply(Seattle): + x(Seattle,New~York) + x(Seattle,Chicago)
25.4572 + + x(Seattle,Topeka) <= 350
25.4573 + supply(San~Diego): + x(San~Diego,New~York) + x(San~Diego,Chicago)
25.4574 + + x(San~Diego,Topeka) <= 600
25.4575 + demand(New~York): + x(Seattle,New~York) + x(San~Diego,New~York) >= 325
25.4576 + demand(Chicago): + x(Seattle,Chicago) + x(San~Diego,Chicago) >= 300
25.4577 + demand(Topeka): + x(Seattle,Topeka) + x(San~Diego,Topeka) >= 275
25.4578 +
25.4579 +End
25.4580 +\end{verbatim}
25.4581 +\end{small}
25.4582 +
25.4583 +\subsection{Optimal LP solution}
25.4584 +
25.4585 +Below here is the optimal solution of the generated LP problem instance
25.4586 +found by the solver \verb|glpsol| and written in plain text format
25.4587 +with the option \verb|--output|.
25.4588 +
25.4589 +\newpage
25.4590 +
25.4591 +\begin{small}
25.4592 +\begin{verbatim}
25.4593 +Problem: transp
25.4594 +Rows: 6
25.4595 +Columns: 6
25.4596 +Non-zeros: 18
25.4597 +Status: OPTIMAL
25.4598 +Objective: cost = 153.675 (MINimum)
25.4599 +
25.4600 +No. Row name St Activity Lower bound Upper bound Marginal
25.4601 +--- ------------ -- ------------ ------------ ------------ ------------
25.4602 + 1 cost B 153.675
25.4603 + 2 supply[Seattle]
25.4604 + B 300 350
25.4605 + 3 supply[San-Diego]
25.4606 + NU 600 600 < eps
25.4607 + 4 demand[New-York]
25.4608 + NL 325 325 0.225
25.4609 + 5 demand[Chicago]
25.4610 + NL 300 300 0.153
25.4611 + 6 demand[Topeka]
25.4612 + NL 275 275 0.126
25.4613 +
25.4614 +No. Column name St Activity Lower bound Upper bound Marginal
25.4615 +--- ------------ -- ------------ ------------ ------------ ------------
25.4616 + 1 x[Seattle,New-York]
25.4617 + B 0 0
25.4618 + 2 x[Seattle,Chicago]
25.4619 + B 300 0
25.4620 + 3 x[Seattle,Topeka]
25.4621 + NL 0 0 0.036
25.4622 + 4 x[San-Diego,New-York]
25.4623 + B 325 0
25.4624 + 5 x[San-Diego,Chicago]
25.4625 + NL 0 0 0.009
25.4626 + 6 x[San-Diego,Topeka]
25.4627 + B 275 0
25.4628 +
25.4629 +End of output
25.4630 +\end{verbatim}
25.4631 +\end{small}
25.4632 +
25.4633 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
25.4634 +
25.4635 +\newpage
25.4636 +
25.4637 +\setcounter{secnumdepth}{-1}
25.4638 +
25.4639 +\section{Acknowledgment}
25.4640 +
25.4641 +The authors would like to thank the following people, who kindly read,
25.4642 +commented, and corrected the draft of this document:
25.4643 +
25.4644 +\medskip
25.4645 +
25.4646 +\noindent Juan Carlos Borras \verb|<borras@cs.helsinki.fi>|
25.4647 +
25.4648 +\medskip
25.4649 +
25.4650 +\noindent Harley Mackenzie \verb|<hjm@bigpond.com>|
25.4651 +
25.4652 +\medskip
25.4653 +
25.4654 +\noindent Robbie Morrison \verb|<robbie@actrix.co.nz>|
25.4655 +
25.4656 +\end{document}
26.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
26.2 +++ b/doc/graphs.tex Mon Dec 06 13:09:21 2010 +0100
26.3 @@ -0,0 +1,3935 @@
26.4 +%* graphs.tex *%
26.5 +
26.6 +%***********************************************************************
26.7 +% This code is part of GLPK (GNU Linear Programming Kit).
26.8 +%
26.9 +% Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
26.10 +% 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
26.11 +% Moscow Aviation Institute, Moscow, Russia. All rights reserved.
26.12 +% E-mail: <mao@gnu.org>.
26.13 +%
26.14 +% GLPK is free software: you can redistribute it and/or modify it
26.15 +% under the terms of the GNU General Public License as published by
26.16 +% the Free Software Foundation, either version 3 of the License, or
26.17 +% (at your option) any later version.
26.18 +%
26.19 +% GLPK is distributed in the hope that it will be useful, but WITHOUT
26.20 +% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
26.21 +% or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
26.22 +% License for more details.
26.23 +%
26.24 +% You should have received a copy of the GNU General Public License
26.25 +% along with GLPK. If not, see <http://www.gnu.org/licenses/>.
26.26 +%***********************************************************************
26.27 +
26.28 +\documentclass[11pt]{report}
26.29 +\usepackage{amssymb}
26.30 +\usepackage[dvipdfm,linktocpage,colorlinks,linkcolor=blue,
26.31 +urlcolor=blue]{hyperref}
26.32 +\usepackage[all]{xy}
26.33 +
26.34 +\renewcommand\contentsname{\sf\bfseries Contents}
26.35 +\renewcommand\chaptername{\sf\bfseries Chapter}
26.36 +\renewcommand\appendixname{\sf\bfseries Appendix}
26.37 +
26.38 +\begin{document}
26.39 +
26.40 +\thispagestyle{empty}
26.41 +
26.42 +\begin{center}
26.43 +
26.44 +\vspace*{1in}
26.45 +
26.46 +\begin{huge}
26.47 +\sf\bfseries GNU Linear Programming Kit
26.48 +\end{huge}
26.49 +
26.50 +\vspace{0.5in}
26.51 +
26.52 +\begin{LARGE}
26.53 +\sf Graph and Network Routines
26.54 +\end{LARGE}
26.55 +
26.56 +\vspace{0.5in}
26.57 +
26.58 +\begin{LARGE}
26.59 +\sf for GLPK Version 4.45
26.60 +\end{LARGE}
26.61 +
26.62 +\vspace{0.5in}
26.63 +\begin{Large}
26.64 +\sf (DRAFT, December 2010)
26.65 +\end{Large}
26.66 +\end{center}
26.67 +
26.68 +\newpage
26.69 +
26.70 +\vspace*{1in}
26.71 +
26.72 +\vfill
26.73 +
26.74 +\noindent
26.75 +The GLPK package is part of the GNU Project released under the aegis of
26.76 +GNU.
26.77 +
26.78 +\medskip \noindent
26.79 +Copyright \copyright{} 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
26.80 +2008, 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
26.81 +Moscow Aviation Institute, Moscow, Russia. All rights reserved.
26.82 +
26.83 +\medskip \noindent
26.84 +Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
26.85 +02110-1301, USA.
26.86 +
26.87 +\medskip \noindent
26.88 +Permission is granted to make and distribute verbatim copies of this
26.89 +manual provided the copyright notice and this permission notice are
26.90 +preserved on all copies.
26.91 +
26.92 +\medskip \noindent
26.93 +Permission is granted to copy and distribute modified versions of this
26.94 +manual under the conditions for verbatim copying, provided also that the
26.95 +entire resulting derived work is distributed under the terms of
26.96 +a permission notice identical to this one.
26.97 +
26.98 +\medskip \noindent
26.99 +Permission is granted to copy and distribute translations of this manual
26.100 +into another language, under the above conditions for modified versions.
26.101 +
26.102 +\tableofcontents
26.103 +
26.104 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
26.105 +
26.106 +\chapter{Basic Graph API Routines}
26.107 +
26.108 +\section{Graph program object}
26.109 +
26.110 +In GLPK the base program object used to represent graphs and networks
26.111 +is a directed graph (digraph).
26.112 +
26.113 +Formally, {\it digraph} (or simply, {\it graph}) is a pair $G=(V,A)$,
26.114 +where $V$ is a set of {\it vertices}, and $A$ is a set
26.115 +{\it arcs}.\footnote{$A$ may be a multiset.} Each arc $a\in A$ is an
26.116 +ordered pair of vertices $a=(x,y)$, where $x\in V$ is called {\it tail
26.117 +vertex} of arc $a$, and $y\in V$ is called its {\it head vertex}.
26.118 +
26.119 +Representation of a graph in the program includes three structs defined
26.120 +by typedef in the header \verb|glpk.h|:
26.121 +
26.122 +\medskip
26.123 +
26.124 +$\bullet$ \verb|glp_graph|, which represents the graph in a whole,
26.125 +
26.126 +$\bullet$ \verb|glp_vertex|, which represents a vertex of the graph, and
26.127 +
26.128 +$\bullet$ \verb|glp_arc|, which represents an arc of the graph.
26.129 +
26.130 +\medskip
26.131 +
26.132 +All these three structs are ``semi-opaque'', i.e. the application
26.133 +program can directly access their fields through pointers, however,
26.134 +changing the fields directly is not allowed---all changes should be
26.135 +performed only with appropriate GLPK API routines.
26.136 +
26.137 +\newpage
26.138 +
26.139 +\newenvironment{comment}
26.140 +{\addtolength{\leftskip}{17pt}\noindent}
26.141 +{\par\addtolength{\leftskip}{-17pt}}
26.142 +
26.143 +\noindent
26.144 +{\bf glp\_graph.} The struct \verb|glp_graph| has the following
26.145 +fields available to the application program:
26.146 +
26.147 +\medskip
26.148 +
26.149 +\noindent
26.150 +\verb|char *name;|
26.151 +
26.152 +\begin{comment}Symbolic name assigned to the graph. It is a pointer to
26.153 +a null terminated character string of length from 1 to 255 characters.
26.154 +If no name is assigned to the graph, this field contains \verb|NULL|.
26.155 +\end{comment}
26.156 +
26.157 +\medskip
26.158 +
26.159 +\noindent
26.160 +\verb|int nv;|
26.161 +
26.162 +\begin{comment}The number of vertices in the graph, $nv\geq 0$.
26.163 +\end{comment}
26.164 +
26.165 +\medskip
26.166 +
26.167 +\noindent
26.168 +\verb|int na;|
26.169 +
26.170 +\begin{comment}The number of arcs in the graph, $na\geq 0$.
26.171 +\end{comment}
26.172 +
26.173 +\medskip
26.174 +
26.175 +\noindent
26.176 +\verb|glp_vertex **v;|
26.177 +
26.178 +\begin{comment}Pointer to an array containing the list of vertices.
26.179 +Element $v[0]$ is not used. Element $v[i]$, $1\leq i\leq nv$, is a
26.180 +pointer to $i$-th vertex of the graph. Note that on adding new vertices
26.181 +to the graph the field $v$ may be altered due to reallocation. However,
26.182 +pointers $v[i]$ are not changed while corresponding vertices exist in
26.183 +the graph.
26.184 +\end{comment}
26.185 +
26.186 +\medskip
26.187 +
26.188 +\noindent
26.189 +\verb|int v_size;|
26.190 +
26.191 +\begin{comment}Size of vertex data blocks, in bytes,
26.192 +$0\leq v\_size\leq 256$. (See also the field \verb|data| in the struct
26.193 +\verb|glp_vertex|.)
26.194 +\end{comment}
26.195 +
26.196 +\medskip
26.197 +
26.198 +\noindent
26.199 +\verb|int a_size;|
26.200 +
26.201 +\begin{comment}Size of arc data blocks, in bytes,
26.202 +$0\leq v\_size\leq 256$. (See also the field \verb|data| in the struct
26.203 +\verb|glp_arc|.)
26.204 +\end{comment}
26.205 +
26.206 +\bigskip
26.207 +
26.208 +\noindent
26.209 +{\bf glp\_vertex.} The struct \verb|glp_vertex| has the following
26.210 +fields available to the application program:
26.211 +
26.212 +\medskip
26.213 +
26.214 +\noindent
26.215 +\verb|int i;|
26.216 +
26.217 +\begin{comment}Ordinal number of the vertex, $1\leq i\leq nv$. Note
26.218 +that element $v[i]$ in the struct \verb|glp_graph| points to the vertex,
26.219 +whose ordinal number is $i$.
26.220 +\end{comment}
26.221 +
26.222 +\medskip
26.223 +
26.224 +\noindent
26.225 +\verb|char *name;|
26.226 +
26.227 +\begin{comment}Symbolic name assigned to the vertex. It is a pointer to
26.228 +a null terminated character string of length from 1 to 255 characters.
26.229 +If no name is assigned to the vertex, this field contains \verb|NULL|.
26.230 +\end{comment}
26.231 +
26.232 +\medskip
26.233 +
26.234 +\noindent
26.235 +\verb|void *data;|
26.236 +
26.237 +\begin{comment}Pointer to a data block associated with the vertex. This
26.238 +data block is automatically allocated on creating a new vertex and freed
26.239 +on deleting the vertex. If $v\_size=0$, the block is not allocated, and
26.240 +this field contains \verb|NULL|.
26.241 +\end{comment}
26.242 +
26.243 +\medskip
26.244 +
26.245 +\noindent
26.246 +\verb|void *temp;|
26.247 +
26.248 +\begin{comment}Working pointer, which may be used freely for any
26.249 +purposes. The application program can change this field directly.
26.250 +\end{comment}
26.251 +
26.252 +\medskip
26.253 +
26.254 +\noindent
26.255 +\verb|glp_arc *in;|
26.256 +
26.257 +\begin{comment}Pointer to the (unordered) list of incoming arcs. If the
26.258 +vertex has no incoming arcs, this field contains \verb|NULL|.
26.259 +\end{comment}
26.260 +
26.261 +\medskip
26.262 +
26.263 +\noindent
26.264 +\verb|glp_arc *out;|
26.265 +
26.266 +\begin{comment}Pointer to the (unordered) list of outgoing arcs. If the
26.267 +vertex has no outgoing arcs, this field contains \verb|NULL|.
26.268 +\end{comment}
26.269 +
26.270 +\bigskip
26.271 +
26.272 +\noindent
26.273 +{\bf glp\_arc.} The struct \verb|glp_arc| has the following fields
26.274 +available to the application program:
26.275 +
26.276 +\medskip
26.277 +
26.278 +\noindent
26.279 +\verb|glp_vertex *tail;|
26.280 +
26.281 +\begin{comment}Pointer to a vertex, which is tail endpoint of the arc.
26.282 +\end{comment}
26.283 +
26.284 +\medskip
26.285 +
26.286 +\noindent
26.287 +\verb|glp_vertex *head;|
26.288 +
26.289 +\begin{comment}Pointer to a vertex, which is head endpoint of the arc.
26.290 +\end{comment}
26.291 +
26.292 +\medskip
26.293 +
26.294 +\noindent
26.295 +\verb|void *data;|
26.296 +
26.297 +\begin{comment}Pointer to a data block associated with the arc. This
26.298 +data block is automatically allocated on creating a new arc and freed on
26.299 +deleting the arc. If $v\_size=0$, the block is not allocated, and this
26.300 +field contains \verb|NULL|.
26.301 +\end{comment}
26.302 +
26.303 +\medskip
26.304 +
26.305 +\noindent
26.306 +\verb|void *temp;|
26.307 +
26.308 +\begin{comment}Working pointer, which may be used freely for any
26.309 +purposes. The application program can change this field directly.
26.310 +\end{comment}
26.311 +
26.312 +\medskip
26.313 +
26.314 +\noindent
26.315 +\verb|glp_arc *t_next;|
26.316 +
26.317 +\begin{comment}Pointer to another arc, which has the same tail endpoint
26.318 +as this one. \verb|NULL| in this field indicates the end of the list of
26.319 +outgoing arcs.
26.320 +\end{comment}
26.321 +
26.322 +\medskip
26.323 +
26.324 +\noindent
26.325 +\verb|glp_arc *h_next;|
26.326 +
26.327 +\begin{comment}Pointer to another arc, which has the same head endpoint
26.328 +as this one. \verb|NULL| in this field indicates the end of the list of
26.329 +incoming arcs.
26.330 +\end{comment}
26.331 +
26.332 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
26.333 +
26.334 +\newpage
26.335 +
26.336 +\section{Graph creating and modifying routines}
26.337 +
26.338 +\subsection{glp\_create\_graph---create graph}
26.339 +
26.340 +\subsubsection*{Synopsis}
26.341 +
26.342 +\begin{verbatim}
26.343 +glp_graph *glp_create_graph(int v_size, int a_size);
26.344 +\end{verbatim}
26.345 +
26.346 +\subsubsection*{Description}
26.347 +
26.348 +The routine \verb|glp_create_graph| creates a new graph, which
26.349 +initially is\linebreak empty, i.e. has no vertices and arcs.
26.350 +
26.351 +The parameter \verb|v_size| specifies the size of vertex data blocks,
26.352 +in bytes, $0\leq v\_size\leq 256$.
26.353 +
26.354 +The parameter \verb|a_size| specifies the size of arc data blocks, in
26.355 +bytes, $0\leq a\_size\leq 256$.
26.356 +
26.357 +\subsubsection*{Returns}
26.358 +
26.359 +The routine returns a pointer to the graph created.
26.360 +
26.361 +\subsection{glp\_set\_graph\_name---assign (change) graph name}
26.362 +
26.363 +\subsubsection*{Synopsis}
26.364 +
26.365 +\begin{verbatim}
26.366 +void glp_set_graph_name(glp_graph *G, const char *name);
26.367 +\end{verbatim}
26.368 +
26.369 +\subsubsection*{Description}
26.370 +
26.371 +The routine \verb|glp_set_graph_name| assigns a symbolic name specified
26.372 +by the character string \verb|name| (1 to 255 chars) to the graph.
26.373 +
26.374 +If the parameter \verb|name| is \verb|NULL| or an empty string, the
26.375 +routine erases the existing symbolic name of the graph.
26.376 +
26.377 +\newpage
26.378 +
26.379 +\subsection{glp\_add\_vertices---add new vertices to graph}
26.380 +
26.381 +\subsubsection*{Synopsis}
26.382 +
26.383 +\begin{verbatim}
26.384 +int glp_add_vertices(glp_graph *G, int nadd);
26.385 +\end{verbatim}
26.386 +
26.387 +\subsubsection*{Description}
26.388 +
26.389 +The routine \verb|glp_add_vertices| adds \verb|nadd| vertices to the
26.390 +specified graph. New vertices are always added to the end of the vertex
26.391 +list, so ordinal numbers of existing vertices remain unchanged. Note
26.392 +that this operation may change the field \verb|v| in the struct
26.393 +\verb|glp_graph| (pointer to the vertex array) due to reallocation.
26.394 +
26.395 +Being added each new vertex is isolated, i.e. has no incident arcs.
26.396 +
26.397 +If the size of vertex data blocks specified on creating the graph is
26.398 +non-zero, the routine also allocates a memory block of that size for
26.399 +each new vertex added, fills it by binary zeros, and stores a pointer to
26.400 +it in the field \verb|data| of the struct \verb|glp_vertex|. Otherwise,
26.401 +if the block size is zero, the field \verb|data| is set to \verb|NULL|.
26.402 +
26.403 +\subsubsection*{Returns}
26.404 +
26.405 +The routine \verb|glp_add_vertices| returns the ordinal number of the
26.406 +first new vertex added to the graph.
26.407 +
26.408 +\subsection{glp\_set\_vertex\_name---assign (change) vertex name}
26.409 +
26.410 +\subsubsection*{Synopsis}
26.411 +
26.412 +\begin{verbatim}
26.413 +void glp_set_vertex_name(glp_graph *G, int i, const char *name);
26.414 +\end{verbatim}
26.415 +
26.416 +\subsubsection*{Description}
26.417 +
26.418 +The routine \verb|glp_set_vertex_name| assigns a given symbolic name
26.419 +(1 up to 255 characters) to \verb|i|-th vertex of the specified graph.
26.420 +
26.421 +If the parameter \verb|name| is \verb|NULL| or empty string, the
26.422 +routine erases an existing name of \verb|i|-th vertex.
26.423 +
26.424 +\newpage
26.425 +
26.426 +\subsection{glp\_add\_arc---add new arc to graph}
26.427 +
26.428 +\subsubsection*{Synopsis}
26.429 +
26.430 +\begin{verbatim}
26.431 +glp_arc *glp_add_arc(glp_graph *G, int i, int j);
26.432 +\end{verbatim}
26.433 +
26.434 +\subsubsection*{Description}
26.435 +
26.436 +The routine \verb|glp_add_arc| adds one new arc to the specified graph.
26.437 +
26.438 +The parameters \verb|i| and \verb|j| specify the ordinal numbers of,
26.439 +resp., tail and head endpoints (vertices) of the arc. Note that
26.440 +self-loops and multiple arcs are allowed.
26.441 +
26.442 +If the size of arc data blocks specified on creating the graph is
26.443 +non-zero, the routine also allocates a memory block of that size, fills
26.444 +it by binary zeros, and stores a pointer to it in the field \verb|data|
26.445 +of the struct \verb|glp_arc|. Otherwise, if the block size is zero, the
26.446 +field \verb|data| is set to \verb|NULL|.
26.447 +
26.448 +\subsection{glp\_del\_vertices---delete vertices from graph}
26.449 +
26.450 +\subsubsection*{Synopsis}
26.451 +
26.452 +\begin{verbatim}
26.453 +void glp_del_vertices(glp_graph *G, int ndel, const int num[]);
26.454 +\end{verbatim}
26.455 +
26.456 +\subsubsection*{Description}
26.457 +
26.458 +The routine \verb|glp_del_vertices| deletes vertices along with all
26.459 +incident arcs from the specified graph. Ordinal numbers of vertices to
26.460 +be deleted should be placed in locations \verb|num[1]|, \dots,
26.461 +\verb|num[ndel]|, \verb|ndel| $>0$.
26.462 +
26.463 +Note that deleting vertices involves changing ordinal numbers of other
26.464 +vertices remaining in the graph. New ordinal numbers of the remaining
26.465 +vertices are assigned under the assumption that the original order of
26.466 +vertices is not changed.
26.467 +
26.468 +\subsection{glp\_del\_arc---delete arc from graph}
26.469 +
26.470 +\subsubsection*{Synopsis}
26.471 +
26.472 +\begin{verbatim}
26.473 +void glp_del_arc(glp_graph *G, glp_arc *a);
26.474 +\end{verbatim}
26.475 +
26.476 +\subsubsection*{Description}
26.477 +
26.478 +The routine \verb|glp_del_arc| deletes an arc from the specified graph.
26.479 +The arc to be deleted must exist.
26.480 +
26.481 +\subsection{glp\_erase\_graph---erase graph content}
26.482 +
26.483 +\subsubsection*{Synopsis}
26.484 +
26.485 +\begin{verbatim}
26.486 +void glp_erase_graph(glp_graph *G, int v_size, int a_size);
26.487 +\end{verbatim}
26.488 +
26.489 +\subsubsection*{Description}
26.490 +
26.491 +The routine \verb|glp_erase_graph| erases the content of the specified
26.492 +graph. The effect of this operation is the same as if the graph would be
26.493 +deleted with the routine \verb|glp_delete_graph| and then created anew
26.494 +with the routine \verb|glp_create_graph|, with exception that the handle
26.495 +(pointer) to the graph remains valid.
26.496 +
26.497 +The parameters \verb|v_size| and \verb|a_size| have the same meaning as
26.498 +for the routine \verb|glp_create_graph|.
26.499 +
26.500 +\subsection{glp\_delete\_graph---delete graph}
26.501 +
26.502 +\subsubsection*{Synopsis}
26.503 +
26.504 +\begin{verbatim}
26.505 +void glp_delete_graph(glp_graph *G);
26.506 +\end{verbatim}
26.507 +
26.508 +\subsubsection*{Description}
26.509 +
26.510 +The routine \verb|glp_delete_graph| deletes the specified graph and
26.511 +frees all the memory allocated to this program object.
26.512 +
26.513 +\newpage
26.514 +
26.515 +\section{Graph searching routines}
26.516 +
26.517 +\subsection{glp\_create\_v\_index---create vertex name index}
26.518 +
26.519 +\subsubsection*{Synopsis}
26.520 +
26.521 +\begin{verbatim}
26.522 +void glp_create_v_index(glp_graph *G);
26.523 +\end{verbatim}
26.524 +
26.525 +\subsubsection*{Description}
26.526 +
26.527 +The routine \verb|glp_create_v_index| creates the name index for the
26.528 +specified graph. The name index is an auxiliary data structure, which
26.529 +is intended to quickly (i.e. for logarithmic time) find vertices by
26.530 +their names.
26.531 +
26.532 +This routine can be called at any time. If the name index already
26.533 +exists, the routine does nothing.
26.534 +
26.535 +\subsection{glp\_find\_vertex---find vertex by its name}
26.536 +
26.537 +\subsubsection*{Synopsis}
26.538 +
26.539 +\begin{verbatim}
26.540 +int glp_find_vertex(glp_graph *G, const char *name);
26.541 +\end{verbatim}
26.542 +
26.543 +\subsubsection*{Returns}
26.544 +
26.545 +The routine \verb|glp_find_vertex| returns the ordinal number of
26.546 +a vertex, which is assigned (by the routine \verb|glp_set_vertex_name|)
26.547 +the specified symbolic \verb|name|. If no such vertex exists, the
26.548 +routine returns 0.
26.549 +
26.550 +\subsection{glp\_delete\_v\_index---delete vertex name index}
26.551 +
26.552 +\subsubsection*{Synopsis}
26.553 +
26.554 +\begin{verbatim}
26.555 +void glp_delete_v_index(glp_graph *G);
26.556 +\end{verbatim}
26.557 +
26.558 +\subsubsection*{Description}
26.559 +
26.560 +The routine \verb|glp_delete_v_index| deletes the name index previously
26.561 +created by the routine \verb|glp_create_v_index| and frees the memory
26.562 +allocated to this auxiliary data structure.
26.563 +
26.564 +This routine can be called at any time. If the name index does not
26.565 +exist, the routine does nothing.
26.566 +
26.567 +\newpage
26.568 +
26.569 +\section{Graph reading/writing routines}
26.570 +
26.571 +\subsection{glp\_read\_graph---read graph from plain text file}
26.572 +
26.573 +\subsubsection*{Synopsis}
26.574 +
26.575 +\begin{verbatim}
26.576 +int glp_read_graph(glp_graph *G, const char *fname);
26.577 +\end{verbatim}
26.578 +
26.579 +\subsubsection*{Description}
26.580 +
26.581 +The routine \verb|glp_read_graph| reads a graph from a plain text file,
26.582 +whose name is specified by the parameter \verb|fname|. Note that before
26.583 +reading data the current content of the graph object is completely
26.584 +erased with the routine \verb|glp_erase_graph|.
26.585 +
26.586 +For the file format see description of the routine
26.587 +\verb|glp_write_graph|.
26.588 +
26.589 +\subsubsection*{Returns}
26.590 +
26.591 +If the operation was successful, the routine returns zero. Otherwise
26.592 +it prints an error message and returns non-zero.
26.593 +
26.594 +\subsection{glp\_write\_graph---write graph to plain text file}
26.595 +
26.596 +\subsubsection*{Synopsis}
26.597 +
26.598 +\begin{verbatim}
26.599 +int glp_write_graph(glp_graph *G, const char *fname);
26.600 +\end{verbatim}
26.601 +
26.602 +\subsubsection*{Description}
26.603 +
26.604 +The routine \verb|glp_write_graph| writes the graph to a plain text
26.605 +file, whose name is specified by the parameter \verb|fname|.
26.606 +
26.607 +\subsubsection*{Returns}
26.608 +
26.609 +If the operation was successful, the routine returns zero. Otherwise
26.610 +it prints an error message and returns non-zero.
26.611 +
26.612 +\subsubsection*{File format}
26.613 +
26.614 +The file created by the routine \verb|glp_write_graph| is a plain text
26.615 +file, which contains the following information:
26.616 +
26.617 +\begin{verbatim}
26.618 + nv na
26.619 + i[1] j[1]
26.620 + i[2] j[2]
26.621 + . . .
26.622 + i[na] j[na]
26.623 +\end{verbatim}
26.624 +
26.625 +\noindent
26.626 +where:
26.627 +
26.628 +\noindent
26.629 +\verb|nv| is the number of vertices (nodes);
26.630 +
26.631 +\noindent
26.632 +\verb|na| is the number of arcs;
26.633 +
26.634 +\noindent
26.635 +\verb|i[k]|, $k=1,\dots,na$, is the index of tail vertex of arc $k$;
26.636 +
26.637 +\noindent
26.638 +\verb|j[k]|, $k=1,\dots,na$, is the index of head vertex of arc $k$.
26.639 +
26.640 +\subsection{glp\_read\_ccdata---read graph from text file in DIMACS
26.641 +clique/coloring format}
26.642 +
26.643 +\subsubsection*{Synopsis}
26.644 +
26.645 +\begin{verbatim}
26.646 +int glp_read_ccdata(glp_graph *G, int v_wgt,
26.647 + const char *fname);
26.648 +\end{verbatim}
26.649 +
26.650 +\subsubsection*{Description}
26.651 +
26.652 +The routine {\it glp\_read\_ccdata} reads a graph from a text file in
26.653 +DIMACS clique/coloring format. (Though this format is originally
26.654 +designed to represent data for the minimal vertex coloring and maximal
26.655 +clique problems, it may be used to represent general undirected and
26.656 +directed graphs, because the routine allows reading self-loops and
26.657 +multiple edges/arcs keeping the order of vertices specified for each
26.658 +edge/arc of the graph.)
26.659 +
26.660 +The parameter $G$ specifies the graph object to be read in. Note that
26.661 +before reading data the current content of the graph object is
26.662 +completely erased with the routine {\it glp\_erase\_graph}.
26.663 +
26.664 +The parameter {\it v\_wgt} specifies an offset of the field of type
26.665 +{\bf double} in the vertex data block, to which the routine stores the
26.666 +vertex weight. If {\it v\_wgt} $<0$, the vertex weights are not stored.
26.667 +
26.668 +The character string {\it fname} specifies the name of a text file to
26.669 +be read in. (If the file name ends with the suffix `\verb|.gz|', the
26.670 +file is assumed to be compressed, in which case the routine decompresses
26.671 +it ``on the fly''.)
26.672 +
26.673 +\subsubsection*{Returns}
26.674 +
26.675 +If the operation was successful, the routine returns zero. Otherwise,
26.676 +it prints an error message and returns non-zero.
26.677 +
26.678 +\subsubsection*{DIMACS clique/coloring format\footnote{This material is
26.679 +based on the paper ``Clique and Coloring Problems Graph Format'', which
26.680 +is publically available at
26.681 +{\tt http://dimacs.rutgers.edu/Challenges/}.}}
26.682 +
26.683 +The DIMACS input file is a plain ASCII text file. It contains
26.684 +{\it lines} of several types described below. A line is terminated with
26.685 +an end-of-line character. Fields in each line are separated by at least
26.686 +one blank space. Each line begins with a one-character designator to
26.687 +identify the line type.
26.688 +
26.689 +Note that DIMACS requires all numerical quantities to be integers in
26.690 +the range $[-2^{31},2^{31}-1]$ while GLPK allows the quantities to be
26.691 +floating-point numbers.
26.692 +
26.693 +\paragraph{Comment lines.} Comment lines give human-readable information
26.694 +about the file and are ignored by programs. Comment lines can appear
26.695 +anywhere in the file. Each comment line begins with a lower-case
26.696 +character \verb|c|.
26.697 +
26.698 +\begin{verbatim}
26.699 + c This is a comment line
26.700 +\end{verbatim}
26.701 +
26.702 +\paragraph{Problem line.} There is one problem line per data file. The
26.703 +problem line must appear before any node or edge descriptor lines. It
26.704 +has the following format:
26.705 +
26.706 +\begin{verbatim}
26.707 + p edge NODES EDGES
26.708 +\end{verbatim}
26.709 +
26.710 +\noindent
26.711 +The lower-case letter \verb|p| signifies that this is a problem line.
26.712 +The four-character problem designator \verb|edge| identifies the file
26.713 +as containing data for the minimal vertex coloring or maximal clique
26.714 +problem. The \verb|NODES| field contains an integer value specifying
26.715 +the number of vertices in the graph. The \verb|EDGES| field contains an
26.716 +integer value specifying the number of edges (arcs) in the graph.
26.717 +
26.718 +\paragraph{Vertex descriptors.} These lines give the weight assigned to
26.719 +a vertex of the graph. There is one vertex descriptor line for each
26.720 +vertex, with the following format. Vertices without a descriptor take on
26.721 +a default value of 1.
26.722 +
26.723 +\begin{verbatim}
26.724 + n ID VALUE
26.725 +\end{verbatim}
26.726 +
26.727 +\noindent
26.728 +The lower-case character \verb|n| signifies that this is a vertex
26.729 +descriptor line. The \verb|ID| field gives a vertex identification
26.730 +number, an integer between 1 and $n$, where $n$ is the number of
26.731 +vertices in the graph. The \verb|VALUE| field gives a vertex weight,
26.732 +which can either positive or negative (or zero).
26.733 +
26.734 +\paragraph{Edge descriptors.} There is one edge descriptor line for
26.735 +each edge (arc) of the graph, each with the following format:
26.736 +
26.737 +\begin{verbatim}
26.738 + e I J
26.739 +\end{verbatim}
26.740 +
26.741 +\noindent
26.742 +The lower-case character \verb|e| signifies that this is an edge
26.743 +descriptor line. For an edge (arc) $(i,j)$ the fields \verb|I| and
26.744 +\verb|J| specify its endpoints.
26.745 +
26.746 +\paragraph{Example.} The following example of an undirected graph:
26.747 +
26.748 +\bigskip
26.749 +
26.750 +\noindent\hfil
26.751 +\xymatrix %@C=32pt
26.752 +{&{v_1}\ar@{-}[ldd]\ar@{-}[dd]\ar@{-}[rd]\ar@{-}[rr]&&{v_2}\ar@{-}[ld]
26.753 +\ar@{-}[dd]\ar@{-}[rdd]&\\
26.754 +&&{v_7}\ar@{-}[ld]\ar@{-}[rd]&&\\
26.755 +{v_6}\ar@{-}[r]\ar@{-}[rdd]&{v_{10}}\ar@{-}[rr]\ar@{-}[rd]\ar@{-}[dd]&&
26.756 +{v_8}\ar@{-}[ld]\ar@{-}[dd]\ar@{-}[r]&{v_3}\ar@{-}[ldd]\\
26.757 +&&{v_9}\ar@{-}[ld]\ar@{-}[rd]&&\\
26.758 +&{v_5}\ar@{-}[rr]&&{v_4}&\\
26.759 +}
26.760 +
26.761 +\bigskip
26.762 +
26.763 +\noindent
26.764 +might be coded in DIMACS clique/coloring format as follows:
26.765 +
26.766 +\begin{footnotesize}
26.767 +\begin{verbatim}
26.768 +c sample.col
26.769 +c
26.770 +c This is an example of the vertex coloring problem data
26.771 +c in DIMACS format.
26.772 +c
26.773 +p edge 10 21
26.774 +c
26.775 +e 1 2
26.776 +e 1 6
26.777 +e 1 7
26.778 +e 1 10
26.779 +e 2 3
26.780 +e 2 7
26.781 +e 2 8
26.782 +e 3 4
26.783 +e 3 8
26.784 +e 4 5
26.785 +e 4 8
26.786 +e 4 9
26.787 +e 5 6
26.788 +e 5 9
26.789 +e 5 10
26.790 +e 6 10
26.791 +e 7 8
26.792 +e 7 10
26.793 +e 8 9
26.794 +e 8 10
26.795 +e 9 10
26.796 +c
26.797 +c eof
26.798 +\end{verbatim}
26.799 +\end{footnotesize}
26.800 +
26.801 +\subsection{glp\_write\_ccdata---write graph to text file in DIMACS
26.802 +clique/coloring format}
26.803 +
26.804 +\subsubsection*{Synopsis}
26.805 +
26.806 +\begin{verbatim}
26.807 +int glp_write_ccdata(glp_graph *G, int v_wgt,
26.808 + const char *fname);
26.809 +\end{verbatim}
26.810 +
26.811 +\subsection*{Description}
26.812 +
26.813 +The routine {\it glp\_write\_ccdata} writes the graph object specified
26.814 +by the parameter $G$ to a text file in DIMACS clique/coloring format.
26.815 +(Though this format is originally designed to represent data for the
26.816 +minimal vertex coloring and maximal clique problems, it may be used to
26.817 +represent general undirected and directed graphs, because the routine
26.818 +allows writing self-loops and multiple edges/arcs keeping the order of
26.819 +vertices specified for each edge/arc of the graph.)
26.820 +
26.821 +The parameter {\it v\_wgt} specifies an offset of the field of type
26.822 +{\bf double} in the vertex data block, which contains the vertex weight.
26.823 +If {\it v\_wgt} $<0$, it is assumed that the weight of each vertex is 1.
26.824 +
26.825 +The character string {\it fname} specifies a name of the text file to be
26.826 +written out. (If the file name ends with suffix `\verb|.gz|', the file
26.827 +is assumed to be compressed, in which case the routine performs
26.828 +automatic compression on writing it.)
26.829 +
26.830 +\subsubsection*{Returns}
26.831 +
26.832 +If the operation was successful, the routine returns zero. Otherwise,
26.833 +it prints an error message and returns non-zero.
26.834 +
26.835 +\newpage
26.836 +
26.837 +\section{Graph analysis routines}
26.838 +
26.839 +\subsection{glp\_weak\_comp---find all weakly connected components of
26.840 +graph}
26.841 +
26.842 +\subsubsection*{Synopsis}
26.843 +
26.844 +\begin{verbatim}
26.845 +int glp_weak_comp(glp_graph *G, int v_num);
26.846 +\end{verbatim}
26.847 +
26.848 +\subsubsection*{Description}
26.849 +
26.850 +The routine \verb|glp_weak_comp| finds all weakly connected components
26.851 +of the specified graph.
26.852 +
26.853 +The parameter \verb|v_num| specifies an offset of the field of type
26.854 +\verb|int| in the vertex data block, to which the routine stores the
26.855 +number of a weakly connected component containing that vertex. If
26.856 +\verb|v_num| $<0$, no component numbers are stored.
26.857 +
26.858 +The components are numbered in arbitrary order from 1 to \verb|nc|,
26.859 +where \verb|nc| is the total number of components found,
26.860 +$0\leq$ \verb|nc| $\leq|V|$.
26.861 +
26.862 +\subsubsection*{Returns}
26.863 +
26.864 +The routine returns \verb|nc|, the total number of components found.
26.865 +
26.866 +\subsection{glp\_strong\_comp---find all strongly connected components
26.867 +of graph}
26.868 +
26.869 +\subsubsection*{Synopsis}
26.870 +
26.871 +\begin{verbatim}
26.872 +int glp_strong_comp(glp_graph *G, int v_num);
26.873 +\end{verbatim}
26.874 +
26.875 +\subsubsection*{Description}
26.876 +
26.877 +The routine \verb|glp_strong_comp| finds all strongly connected
26.878 +components of the specified graph.
26.879 +
26.880 +The parameter \verb|v_num| specifies an offset of the field of type
26.881 +\verb|int| in the vertex data block, to which the routine stores the
26.882 +number of a strongly connected component containing that vertex. If
26.883 +\verb|v_num| $<0$, no component numbers are stored.
26.884 +
26.885 +The components are numbered in arbitrary order from 1 to \verb|nc|,
26.886 +where \verb|nc| is the total number of components found,
26.887 +$0\leq$ \verb|nc| $\leq|V|$. However, the component numbering has the
26.888 +property that for every arc $(i\rightarrow j)$ in the graph the
26.889 +condition $num(i)\geq num(j)$ holds.
26.890 +
26.891 +\subsubsection*{Returns}
26.892 +
26.893 +The routine returns \verb|nc|, the total number of components found.
26.894 +
26.895 +\subsubsection*{References}
26.896 +
26.897 +I.~S.~Duff, J.~K.~Reid, Algorithm 529: Permutations to block triangular
26.898 +form, ACM Trans. on Math. Softw. 4 (1978), 189-92.
26.899 +
26.900 +\subsubsection*{Example}
26.901 +
26.902 +The following program reads a graph from a plain text file
26.903 +`\verb|graph.txt|' and finds all its strongly connected components.
26.904 +
26.905 +\begin{footnotesize}
26.906 +\begin{verbatim}
26.907 +#include <stddef.h>
26.908 +#include <stdio.h>
26.909 +#include <stdlib.h>
26.910 +#include <glpk.h>
26.911 +
26.912 +typedef struct { int num; } v_data;
26.913 +
26.914 +#define vertex(v) ((v_data *)((v)->data))
26.915 +
26.916 +int main(void)
26.917 +{ glp_graph *G;
26.918 + int i, nc;
26.919 + G = glp_create_graph(sizeof(v_data), 0);
26.920 + glp_read_graph(G, "graph.txt");
26.921 + nc = glp_strong_comp(G, offsetof(v_data, num));
26.922 + printf("nc = %d\n", nc);
26.923 + for (i = 1; i <= G->nv; i++)
26.924 + printf("num[%d] = %d\n", i, vertex(G->v[i])->num);
26.925 + glp_delete_graph(G);
26.926 + return 0;
26.927 +}
26.928 +\end{verbatim}
26.929 +\end{footnotesize}
26.930 +
26.931 +\noindent
26.932 +If the file `\verb|graph.txt|' contains the graph shown below:
26.933 +
26.934 +\bigskip
26.935 +
26.936 +\noindent\hfil
26.937 +\xymatrix
26.938 +{1\ar[r]&2\ar[r]&3\ar[r]\ar[dd]&4\ar[dd]\\
26.939 +5\ar[u]&6\ar[l]\\
26.940 +7\ar[u]&&8\ar[lu]\ar[ll]\ar[r]&9\ar[r]&10\ar[r]\ar[d]&11\ar[d]\\
26.941 +12\ar[u]\ar[rru]\ar@/_/[rr]&&13\ar[ll]\ar[u]\ar[rr]&&14\ar[lu]&15\ar[l]
26.942 +\\
26.943 +}
26.944 +
26.945 +\bigskip\bigskip
26.946 +
26.947 +\noindent
26.948 +the program output may look like follows:
26.949 +
26.950 +\begin{footnotesize}
26.951 +\begin{verbatim}
26.952 +Reading graph from `graph.txt'...
26.953 +Graph has 15 vertices and 30 arcs
26.954 +31 lines were read
26.955 +nc = 4
26.956 +num[1] = 3
26.957 +num[2] = 3
26.958 +num[3] = 3
26.959 +num[4] = 2
26.960 +num[5] = 3
26.961 +num[6] = 3
26.962 +num[7] = 3
26.963 +num[8] = 3
26.964 +num[9] = 1
26.965 +num[10] = 1
26.966 +num[11] = 1
26.967 +num[12] = 4
26.968 +num[13] = 4
26.969 +num[14] = 1
26.970 +num[15] = 1
26.971 +\end{verbatim}
26.972 +\end{footnotesize}
26.973 +
26.974 +\subsection{glp\_top\_sort---topological sorting of acyclic digraph}
26.975 +
26.976 +\subsubsection*{Synopsis}
26.977 +
26.978 +\begin{verbatim}
26.979 +int glp_top_sort(glp_graph *G, int v_num);
26.980 +\end{verbatim}
26.981 +
26.982 +\subsubsection*{Description}
26.983 +
26.984 +The routine \verb|glp_top_sort| performs topological sorting of
26.985 +vertices of the specified acyclic digraph.
26.986 +
26.987 +The parameter \verb|v_num| specifies an offset of the field of type
26.988 +\verb|int| in the vertex data block, to which the routine stores the
26.989 +vertex number assigned. If \verb|v_num| $<0$, vertex numbers are not
26.990 +stored.
26.991 +
26.992 +The vertices are numbered from 1 to $n$, where $n$ is the total number
26.993 +of vertices in the graph. The vertex numbering has the property that
26.994 +for every arc $(i\rightarrow j)$ in the graph the condition
26.995 +$num(i)<num(j)$ holds. Special case $num(i)=0$ means that vertex $i$ is
26.996 +not assigned a number, because the graph is {\it not} acyclic.
26.997 +
26.998 +\subsubsection*{Returns}
26.999 +
26.1000 +If the graph is acyclic and therefore all the vertices have been
26.1001 +assigned numbers, the routine \verb|glp_top_sort| returns zero.
26.1002 +Otherwise, if the graph is not acyclic, the routine returns the number
26.1003 +of vertices which have not been numbered, i.e. for which $num(i)=0$.
26.1004 +
26.1005 +\subsubsection*{Example}
26.1006 +
26.1007 +The following program reads a digraph from a plain text file
26.1008 +`\verb|graph.txt|' and performs topological sorting of its vertices.
26.1009 +
26.1010 +\begin{footnotesize}
26.1011 +\begin{verbatim}
26.1012 +#include <stddef.h>
26.1013 +#include <stdio.h>
26.1014 +#include <stdlib.h>
26.1015 +#include <glpk.h>
26.1016 +
26.1017 +typedef struct { int num; } v_data;
26.1018 +
26.1019 +#define vertex(v) ((v_data *)((v)->data))
26.1020 +
26.1021 +int main(void)
26.1022 +{ glp_graph *G;
26.1023 + int i, cnt;
26.1024 + G = glp_create_graph(sizeof(v_data), 0);
26.1025 + glp_read_graph(G, "graph.txt");
26.1026 + cnt = glp_top_sort(G, offsetof(v_data, num));
26.1027 + printf("cnt = %d\n", cnt);
26.1028 + for (i = 1; i <= G->nv; i++)
26.1029 + printf("num[%d] = %d\n", i, vertex(G->v[i])->num);
26.1030 + glp_delete_graph(G);
26.1031 + return 0;
26.1032 +}
26.1033 +\end{verbatim}
26.1034 +\end{footnotesize}
26.1035 +
26.1036 +\noindent
26.1037 +If the file `\verb|graph.txt|' contains the graph shown below:
26.1038 +
26.1039 +\bigskip
26.1040 +
26.1041 +\noindent\hfil
26.1042 +\xymatrix @=20pt
26.1043 +{
26.1044 +1\ar[rrr]&&&2\ar[r]\ar[rddd]&3\ar[rd]&&&&\\
26.1045 +&&&4\ar[ru]&&5\ar[r]&6\ar[rd]\ar[dd]&&\\
26.1046 +7\ar[r]&8\ar[r]&9\ar[ruu]\ar[ru]\ar[r]\ar[rd]&10\ar[rr]\ar[rru]&&
26.1047 +11\ar[ru]&&12\ar[r]&13\\
26.1048 +&&&14\ar[r]&15\ar[rrru]\ar[rr]&&16\ar[rru]\ar[rr]&&17\\
26.1049 +}
26.1050 +
26.1051 +\bigskip\bigskip
26.1052 +
26.1053 +\noindent
26.1054 +the program output may look like follows:
26.1055 +
26.1056 +\begin{footnotesize}
26.1057 +\begin{verbatim}
26.1058 +Reading graph from `graph.txt'...
26.1059 +Graph has 17 vertices and 23 arcs
26.1060 +24 lines were read
26.1061 +cnt = 0
26.1062 +num[1] = 8
26.1063 +num[2] = 9
26.1064 +num[3] = 10
26.1065 +num[4] = 4
26.1066 +num[5] = 11
26.1067 +num[6] = 12
26.1068 +num[7] = 1
26.1069 +num[8] = 2
26.1070 +num[9] = 3
26.1071 +num[10] = 5
26.1072 +num[11] = 6
26.1073 +num[12] = 14
26.1074 +num[13] = 16
26.1075 +num[14] = 7
26.1076 +num[15] = 13
26.1077 +num[16] = 15
26.1078 +num[17] = 17
26.1079 +\end{verbatim}
26.1080 +\end{footnotesize}
26.1081 +
26.1082 +\noindent
26.1083 +The output corresponds to the following vertex numbering:
26.1084 +
26.1085 +\bigskip
26.1086 +
26.1087 +\noindent\hfil
26.1088 +\xymatrix @=20pt
26.1089 +{
26.1090 +8\ar[rrr]&&&9\ar[r]\ar[rddd]&10\ar[rd]&&&&\\
26.1091 +&&&4\ar[ru]&&11\ar[r]&12\ar[rd]\ar[dd]&&\\
26.1092 +1\ar[r]&2\ar[r]&3\ar[ruu]\ar[ru]\ar[r]\ar[rd]&5\ar[rr]\ar[rru]&&
26.1093 +6\ar[ru]&&14\ar[r]&16\\
26.1094 +&&&7\ar[r]&13\ar[rrru]\ar[rr]&&15\ar[rru]\ar[rr]&&17\\
26.1095 +}
26.1096 +
26.1097 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
26.1098 +
26.1099 +\chapter{Network optimization API routines}
26.1100 +
26.1101 +\section{Minimum cost flow problem}
26.1102 +
26.1103 +\subsection{Background}
26.1104 +
26.1105 +The {\it minimum cost flow problem} (MCFP) is stated as follows. Let
26.1106 +there be given a directed graph (flow network) $G=(V,A)$, where $V$ is
26.1107 +a set of vertices (nodes), and $A\subseteq V\times V$ is a set of arcs.
26.1108 +Let for each node $i\in V$ there be given a quantity $b_i$ having the
26.1109 +following meaning:
26.1110 +
26.1111 +if $b_i>0$, then $|b_i|$ is a {\it supply} at node $i$, which shows
26.1112 +how many flow units are {\it generated} at node $i$ (or, equivalently,
26.1113 +entering the network through node $i$ from the outside);
26.1114 +
26.1115 +if $b_i<0$, then $|b_i|$ is a {\it demand} at node $i$, which shows how
26.1116 +many flow units are {\it lost} at node $i$ (or, equivalently, leaving
26.1117 +the network through node $i$ to the outside);
26.1118 +
26.1119 +if $b_i=0$, then $i$ is a {\it transshipment} node, at which the flow
26.1120 +is conserved, i.e. neither generated nor lost.
26.1121 +
26.1122 +Let also for each arc $a=(i,j)\in A$ there be given the following three
26.1123 +quantities:
26.1124 +
26.1125 +$l_{ij}$, a (non-negative) lower bound to the flow through arc $(i,j)$;
26.1126 +
26.1127 +$u_{ij}$, an upper bound to the flow through arc $(i,j)$, which is the
26.1128 +{\it arc capacity};
26.1129 +
26.1130 +$c_{ij}$, a per-unit cost of the flow through arc $(i,j)$.
26.1131 +
26.1132 +The problem is to find flows $x_{ij}$ through every arc of the network,
26.1133 +which satisfy the specified bounds and the conservation constraints at
26.1134 +all nodes, and minimize the total flow cost. Here the conservation
26.1135 +constraint at a node means that the total flow entering this node
26.1136 +through its incoming arcs plus the supply at this node must be equal to
26.1137 +the total flow leaving this node through its outgoing arcs plus the
26.1138 +demand at this node.
26.1139 +
26.1140 +An example of the minimum cost flow problem is shown on Fig.~1.
26.1141 +
26.1142 +\bigskip
26.1143 +
26.1144 +\noindent\hfil
26.1145 +\xymatrix @C=48pt
26.1146 +{_{20}\ar@{~>}[d]&
26.1147 +v_2\ar[r]|{_{0,10,\$2}}\ar[dd]|{_{0,9,\$3}}&
26.1148 +v_3\ar[dd]|{_{2,12,\$1}}\ar[r]|{_{0,18,\$0}}&
26.1149 +v_8\ar[rd]|{_{0,20,\$9}}&\\
26.1150 +v_1\ar[ru]|{_{0,14,\$0}}\ar[rd]|{_{0,23,\$0}}&&&
26.1151 +v_6\ar[d]|{_{0,7,\$0}}\ar[u]|{_{4,8,\$0}}&
26.1152 +v_9\ar@{~>}[d]\\
26.1153 +&v_4\ar[r]|{_{0,26,\$0}}&
26.1154 +v_5\ar[luu]|{_{0,11,\$1}}\ar[ru]|{_{0,25,\$5}}\ar[r]|{_{0,4,\$7}}&
26.1155 +v_7\ar[ru]|{_{0,15,\$3}}&_{20}\\
26.1156 +}
26.1157 +
26.1158 +\medskip
26.1159 +
26.1160 +\noindent\hfil
26.1161 +\begin{tabular}{ccc}
26.1162 +\xymatrix @C=48pt{v_i\ar[r]|{\ l,u,\$c\ }&v_j\\}&
26.1163 +\xymatrix{\hbox{\footnotesize supply}\ar@{~>}[r]&v_i\\}&
26.1164 +\xymatrix{v_i\ar@{~>}[r]&\hbox{\footnotesize demand}\\}\\
26.1165 +\end{tabular}
26.1166 +
26.1167 +\bigskip
26.1168 +
26.1169 +\noindent\hfil
26.1170 +Fig.~1. An example of the minimum cost flow problem.
26.1171 +
26.1172 +\bigskip
26.1173 +
26.1174 +The minimum cost flow problem can be naturally formulated as the
26.1175 +following LP problem:
26.1176 +
26.1177 +\medskip
26.1178 +
26.1179 +\noindent
26.1180 +\hspace{.5in}minimize
26.1181 +$$z=\sum_{(i,j)\in A}c_{ij}x_{ij}\eqno(1)$$
26.1182 +\hspace{.5in}subject to
26.1183 +$$\sum_{(i,j)\in A}x_{ij}-\sum_{(j,i)\in A}x_{ji}=b_i\ \ \ \hbox
26.1184 +{for all}\ i\in V\eqno(2)$$
26.1185 +$$l_{ij}\leq x_{ij}\leq u_{ij}\ \ \ \hbox{for all}\ (i,j)\in A
26.1186 +\eqno(3)$$
26.1187 +
26.1188 +\newpage
26.1189 +
26.1190 +\subsection{glp\_read\_mincost---read minimum cost flow problem\\data
26.1191 +in DIMACS format}
26.1192 +
26.1193 +\subsubsection*{Synopsis}
26.1194 +
26.1195 +\begin{verbatim}
26.1196 +int glp_read_mincost(glp_graph *G, int v_rhs, int a_low,
26.1197 + int a_cap, int a_cost, const char *fname);
26.1198 +\end{verbatim}
26.1199 +
26.1200 +\subsubsection*{Description}
26.1201 +
26.1202 +The routine \verb|glp_read_mincost| reads the minimum cost flow problem
26.1203 +data from a text file in DIMACS format.
26.1204 +
26.1205 +The parameter \verb|G| specifies the graph object, to which the problem
26.1206 +data have to be stored. Note that before reading data the current
26.1207 +content of the graph object is completely erased with the routine
26.1208 +\verb|glp_erase_graph|.
26.1209 +
26.1210 +The parameter \verb|v_rhs| specifies an offset of the field of type
26.1211 +\verb|double| in the vertex data block, to which the routine stores
26.1212 +$b_i$, the supply/demand value. If \verb|v_rhs| $<0$, the value is not
26.1213 +stored.
26.1214 +
26.1215 +The parameter \verb|a_low| specifies an offset of the field of type
26.1216 +\verb|double| in the arc data block, to which the routine stores
26.1217 +$l_{ij}$, the lower bound to the arc flow. If \verb|a_low| $<0$, the
26.1218 +lower bound is not stored.
26.1219 +
26.1220 +The parameter \verb|a_cap| specifies an offset of the field of type
26.1221 +\verb|double| in the arc data block, to which the routine stores
26.1222 +$u_{ij}$, the upper bound to the arc flow (the arc capacity). If
26.1223 +\verb|a_cap| $<0$, the upper bound is not stored.
26.1224 +
26.1225 +The parameter \verb|a_cost| specifies an offset of the field of type
26.1226 +\verb|double| in the arc data block, to which the routine stores
26.1227 +$c_{ij}$, the per-unit cost of the arc flow. If \verb|a_cost| $<0$, the
26.1228 +cost is not stored.
26.1229 +
26.1230 +The character string \verb|fname| specifies the name of a text file to
26.1231 +be read in. (If the file name name ends with the suffix `\verb|.gz|',
26.1232 +the file is assumed to be compressed, in which case the routine
26.1233 +decompresses it ``on the fly''.)
26.1234 +
26.1235 +\subsubsection*{Returns}
26.1236 +
26.1237 +If the operation was successful, the routine returns zero. Otherwise,
26.1238 +it prints an error message and returns non-zero.
26.1239 +
26.1240 +\newpage
26.1241 +
26.1242 +\subsubsection*{Example}
26.1243 +
26.1244 +\begin{footnotesize}
26.1245 +\begin{verbatim}
26.1246 +typedef struct
26.1247 +{ /* vertex data block */
26.1248 + ...
26.1249 + double rhs;
26.1250 + ...
26.1251 +} v_data;
26.1252 +
26.1253 +typedef struct
26.1254 +{ /* arc data block */
26.1255 + ...
26.1256 + double low, cap, cost;
26.1257 + ...
26.1258 +} a_data;
26.1259 +
26.1260 +int main(void)
26.1261 +{ glp_graph *G;
26.1262 + int ret;
26.1263 + G = glp_create_graph(sizeof(v_data), sizeof(a_data));
26.1264 + ret = glp_read_mincost(G, offsetof(v_data, rhs),
26.1265 + offsetof(a_data, low), offsetof(a_data, cap),
26.1266 + offsetof(a_data, cost), "sample.min");
26.1267 + if (ret != 0) goto ...
26.1268 + ...
26.1269 +}
26.1270 +\end{verbatim}
26.1271 +\end{footnotesize}
26.1272 +
26.1273 +\subsubsection*{DIMACS minimum cost flow problem format\footnote{This
26.1274 +material is based on the paper ``The First DIMACS International
26.1275 +Algorithm Implementation Challenge: Problem Definitions and
26.1276 +Specifications'', which is publically available at
26.1277 +{\tt http://dimacs.rutgers.edu/Challenges/}.}}
26.1278 +\label{subsecmincost}
26.1279 +
26.1280 +The DIMACS input file is a plain ASCII text file. It contains
26.1281 +{\it lines} of several types described below. A line is terminated with
26.1282 +an end-of-line character. Fields in each line are separated by at least
26.1283 +one blank space. Each line begins with a one-character designator to
26.1284 +identify the line type.
26.1285 +
26.1286 +Note that DIMACS requires all numerical quantities to be integers in
26.1287 +the range $[-2^{31},\ 2^{31}-1]$ while GLPK allows the quantities to be
26.1288 +floating-point numbers.
26.1289 +
26.1290 +\newpage
26.1291 +
26.1292 +\paragraph{Comment lines.} Comment lines give human-readable information
26.1293 +about the file and are ignored by programs. Comment lines can appear
26.1294 +anywhere in the file. Each comment line begins with a lower-case
26.1295 +character \verb|c|.
26.1296 +
26.1297 +\begin{verbatim}
26.1298 + c This is a comment line
26.1299 +\end{verbatim}
26.1300 +
26.1301 +\paragraph{Problem line.} There is one problem line per data file. The
26.1302 +problem line must appear before any node or arc descriptor lines. It has
26.1303 +the following format:
26.1304 +
26.1305 +\begin{verbatim}
26.1306 + p min NODES ARCS
26.1307 +\end{verbatim}
26.1308 +
26.1309 +\noindent
26.1310 +The lower-case character \verb|p| signifies that this is a problem line.
26.1311 +The three-character problem designator \verb|min| identifies the file as
26.1312 +containing specification information for the minimum cost flow problem.
26.1313 +The \verb|NODES| field contains an integer value specifying the number
26.1314 +of nodes in the network. The \verb|ARCS| field contains an integer value
26.1315 +specifying the number of arcs in the network.
26.1316 +
26.1317 +\paragraph{Node descriptors.} All node descriptor lines must appear
26.1318 +before all arc descriptor lines. The node descriptor lines describe
26.1319 +supply and demand nodes, but not transshipment nodes. That is, only
26.1320 +nodes with non-zero node supply/demand values appear. There is one node
26.1321 +descriptor line for each such node, with the following format:
26.1322 +
26.1323 +\begin{verbatim}
26.1324 + n ID FLOW
26.1325 +\end{verbatim}
26.1326 +
26.1327 +\noindent
26.1328 +The lower-case character \verb|n| signifies that this is a node
26.1329 +descriptor line. The \verb|ID| field gives a node identification number,
26.1330 +an integer between 1 and \verb|NODES|. The \verb|FLOW| field gives the
26.1331 +amount of supply (if positive) or demand (if negative) at node
26.1332 +\verb|ID|.
26.1333 +
26.1334 +\paragraph{Arc descriptors.} There is one arc descriptor line for each
26.1335 +arc in the network. Arc descriptor lines are of the following format:
26.1336 +
26.1337 +\begin{verbatim}
26.1338 + a SRC DST LOW CAP COST
26.1339 +\end{verbatim}
26.1340 +
26.1341 +\noindent
26.1342 +The lower-case character \verb|a| signifies that this is an arc
26.1343 +descriptor line. For a directed arc $(i,j)$ the \verb|SRC| field gives
26.1344 +the identification number $i$ for the tail endpoint, and the \verb|DST|
26.1345 +field gives the identification number $j$ for the head endpoint.
26.1346 +Identification numbers are integers between 1 and \verb|NODES|. The
26.1347 +\verb|LOW| field specifies the minimum amount of flow that can be sent
26.1348 +along arc $(i,j)$, and the \verb|CAP| field gives the maximum amount of
26.1349 +flow that can be sent along arc $(i,j)$ in a feasible flow. The
26.1350 +\verb|COST| field contains the per-unit cost of flow sent along arc
26.1351 +$(i,j)$.
26.1352 +
26.1353 +\paragraph{Example.} Below here is an example of the data file in
26.1354 +DIMACS format corresponding to the minimum cost flow problem shown on
26.1355 +Fig~1.
26.1356 +
26.1357 +\begin{footnotesize}
26.1358 +\begin{verbatim}
26.1359 +c sample.min
26.1360 +c
26.1361 +c This is an example of the minimum cost flow problem data
26.1362 +c in DIMACS format.
26.1363 +c
26.1364 +p min 9 14
26.1365 +c
26.1366 +n 1 20
26.1367 +n 9 -20
26.1368 +c
26.1369 +a 1 2 0 14 0
26.1370 +a 1 4 0 23 0
26.1371 +a 2 3 0 10 2
26.1372 +a 2 4 0 9 3
26.1373 +a 3 5 2 12 1
26.1374 +a 3 8 0 18 0
26.1375 +a 4 5 0 26 0
26.1376 +a 5 2 0 11 1
26.1377 +a 5 6 0 25 5
26.1378 +a 5 7 0 4 7
26.1379 +a 6 7 0 7 0
26.1380 +a 6 8 4 8 0
26.1381 +a 7 9 0 15 3
26.1382 +a 8 9 0 20 9
26.1383 +c
26.1384 +c eof
26.1385 +\end{verbatim}
26.1386 +\end{footnotesize}
26.1387 +
26.1388 +\newpage
26.1389 +
26.1390 +\subsection{glp\_write\_mincost---write minimum cost flow problem\\data
26.1391 +in DIMACS format}
26.1392 +
26.1393 +\subsubsection*{Synopsis}
26.1394 +
26.1395 +\begin{verbatim}
26.1396 +int glp_write_mincost(glp_graph *G, int v_rhs, int a_low,
26.1397 + int a_cap, int a_cost, const char *fname);
26.1398 +\end{verbatim}
26.1399 +
26.1400 +\subsubsection*{Description}
26.1401 +
26.1402 +The routine \verb|glp_write_mincost| writes the minimum cost flow
26.1403 +problem data to a text file in DIMACS format.
26.1404 +
26.1405 +The parameter \verb|G| is the graph (network) program object, which
26.1406 +specifies the minimum cost flow problem instance.
26.1407 +
26.1408 +The parameter \verb|v_rhs| specifies an offset of the field of type
26.1409 +\verb|double| in the vertex data block, which contains $b_i$, the
26.1410 +supply/demand value. If \verb|v_rhs| $<0$, it is assumed that $b_i=0$
26.1411 +for all nodes.
26.1412 +
26.1413 +The parameter \verb|a_low| specifies an offset of the field of type
26.1414 +\verb|double| in the arc data block, which contains $l_{ij}$, the lower
26.1415 +bound to the arc flow. If \verb|a_low| $<0$, it is assumed that
26.1416 +$l_{ij}=0$ for all arcs.
26.1417 +
26.1418 +The parameter \verb|a_cap| specifies an offset of the field of type
26.1419 +\verb|double| in the arc data block, which contains $u_{ij}$, the upper
26.1420 +bound to the arc flow (the arc capacity). If the upper bound is
26.1421 +specified as \verb|DBL_MAX|, it is assumed that $u_{ij}=\infty$, i.e.
26.1422 +the arc is uncapacitated. If \verb|a_cap| $<0$, it is assumed that
26.1423 +$u_{ij}=1$ for all arcs.
26.1424 +
26.1425 +The parameter \verb|a_cost| specifies an offset of the field of type
26.1426 +\verb|double| in the arc data block, which contains $c_{ij}$, the
26.1427 +per-unit cost of the arc flow. If \verb|a_cost| $<0$, it is assumed that
26.1428 +$c_{ij}=0$ for all arcs.
26.1429 +
26.1430 +The character string \verb|fname| specifies a name of the text file to
26.1431 +be written out. (If the file name ends with suffix `\verb|.gz|', the
26.1432 +file is assumed to be compressed, in which case the routine performs
26.1433 +automatic compression on writing it.)
26.1434 +
26.1435 +\subsubsection*{Returns}
26.1436 +
26.1437 +If the operation was successful, the routine returns zero. Otherwise,
26.1438 +it prints an error message and returns non-zero.
26.1439 +
26.1440 +\newpage
26.1441 +
26.1442 +\subsection{glp\_mincost\_lp---convert minimum cost flow problem\\to LP}
26.1443 +
26.1444 +\subsubsection*{Synopsis}
26.1445 +
26.1446 +\begin{verbatim}
26.1447 +void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names,
26.1448 + int v_rhs, int a_low, int a_cap, int a_cost);
26.1449 +\end{verbatim}
26.1450 +
26.1451 +\subsubsection*{Description}
26.1452 +
26.1453 +The routine \verb|glp_mincost_lp| builds LP problem (1)---(3), which
26.1454 +corresponds to the specified minimum cost flow problem.
26.1455 +
26.1456 +The parameter \verb|lp| is the resultant LP problem object to be built.
26.1457 +Note that on entry its current content is erased with the routine
26.1458 +\verb|glp_erase_prob|.
26.1459 +
26.1460 +The parameter \verb|G| is the graph (network) program object, which
26.1461 +specifies the minimum cost flow problem instance.
26.1462 +
26.1463 +The parameter \verb|names| is a flag. If it is \verb|GLP_ON|, the
26.1464 +routine uses symbolic names of the graph object components to assign
26.1465 +symbolic names to the LP problem object components. If the flag is
26.1466 +\verb|GLP_OFF|, no symbolic names are assigned.
26.1467 +
26.1468 +The parameter \verb|v_rhs| specifies an offset of the field of type
26.1469 +\verb|double| in the vertex data block, which contains $b_i$, the
26.1470 +supply/demand value. If \verb|v_rhs| $<0$, it is assumed that $b_i=0$
26.1471 +for all nodes.
26.1472 +
26.1473 +The parameter \verb|a_low| specifies an offset of the field of type
26.1474 +\verb|double| in the arc data block, which contains $l_{ij}$, the lower
26.1475 +bound to the arc flow. If \verb|a_low| $<0$, it is assumed that
26.1476 +$l_{ij}=0$ for all arcs.
26.1477 +
26.1478 +The parameter \verb|a_cap| specifies an offset of the field of type
26.1479 +\verb|double| in the arc data block, which contains $u_{ij}$, the upper
26.1480 +bound to the arc flow (the arc capacity). If the upper bound is
26.1481 +specified as \verb|DBL_MAX|, it is assumed that $u_{ij}=\infty$, i.e.
26.1482 +the arc is uncapacitated. If \verb|a_cap| $<0$, it is assumed that
26.1483 +$u_{ij}=1$ for all arcs.
26.1484 +
26.1485 +The parameter \verb|a_cost| specifies an offset of the field of type
26.1486 +\verb|double| in the arc data block, which contains $c_{ij}$, the
26.1487 +per-unit cost of the arc flow. If \verb|a_cost| $<0$, it is assumed that
26.1488 +$c_{ij}=0$ for all arcs.
26.1489 +
26.1490 +\subsubsection*{Example}
26.1491 +
26.1492 +The example program below reads the minimum cost problem instance in
26.1493 +DIMACS format from file `\verb|sample.min|', converts the instance to
26.1494 +LP, and then writes the resultant LP in CPLEX format to file
26.1495 +`\verb|mincost.lp|'.
26.1496 +
26.1497 +\newpage
26.1498 +
26.1499 +\begin{footnotesize}
26.1500 +\begin{verbatim}
26.1501 +#include <stddef.h>
26.1502 +#include <glpk.h>
26.1503 +
26.1504 +typedef struct { double rhs; } v_data;
26.1505 +typedef struct { double low, cap, cost; } a_data;
26.1506 +
26.1507 +int main(void)
26.1508 +{ glp_graph *G;
26.1509 + glp_prob *lp;
26.1510 + G = glp_create_graph(sizeof(v_data), sizeof(a_data));
26.1511 + glp_read_mincost(G, offsetof(v_data, rhs),
26.1512 + offsetof(a_data, low), offsetof(a_data, cap),
26.1513 + offsetof(a_data, cost), "sample.min");
26.1514 + lp = glp_create_prob();
26.1515 + glp_mincost_lp(lp, G, GLP_ON, offsetof(v_data, rhs),
26.1516 + offsetof(a_data, low), offsetof(a_data, cap),
26.1517 + offsetof(a_data, cost));
26.1518 + glp_delete_graph(G);
26.1519 + glp_write_lp(lp, NULL, "mincost.lp");
26.1520 + glp_delete_prob(lp);
26.1521 + return 0;
26.1522 +}
26.1523 +\end{verbatim}
26.1524 +\end{footnotesize}
26.1525 +
26.1526 +If `\verb|sample.min|' is the example data file from the subsection
26.1527 +describing the routine \verb|glp_read_mincost|, file `\verb|mincost.lp|'
26.1528 +may look like follows:
26.1529 +
26.1530 +\begin{footnotesize}
26.1531 +\begin{verbatim}
26.1532 +Minimize
26.1533 + obj: + 3 x(2,4) + 2 x(2,3) + x(3,5) + 7 x(5,7) + 5 x(5,6)
26.1534 + + x(5,2) + 3 x(7,9) + 9 x(8,9)
26.1535 +
26.1536 +Subject To
26.1537 + r_1: + x(1,2) + x(1,4) = 20
26.1538 + r_2: - x(5,2) + x(2,3) + x(2,4) - x(1,2) = 0
26.1539 + r_3: + x(3,5) + x(3,8) - x(2,3) = 0
26.1540 + r_4: + x(4,5) - x(2,4) - x(1,4) = 0
26.1541 + r_5: + x(5,2) + x(5,6) + x(5,7) - x(4,5) - x(3,5) = 0
26.1542 + r_6: + x(6,7) + x(6,8) - x(5,6) = 0
26.1543 + r_7: + x(7,9) - x(6,7) - x(5,7) = 0
26.1544 + r_8: + x(8,9) - x(6,8) - x(3,8) = 0
26.1545 + r_9: - x(8,9) - x(7,9) = -20
26.1546 +
26.1547 +Bounds
26.1548 + 0 <= x(1,4) <= 23
26.1549 + 0 <= x(1,2) <= 14
26.1550 + 0 <= x(2,4) <= 9
26.1551 + 0 <= x(2,3) <= 10
26.1552 + 0 <= x(3,8) <= 18
26.1553 + 2 <= x(3,5) <= 12
26.1554 + 0 <= x(4,5) <= 26
26.1555 + 0 <= x(5,7) <= 4
26.1556 + 0 <= x(5,6) <= 25
26.1557 + 0 <= x(5,2) <= 11
26.1558 + 4 <= x(6,8) <= 8
26.1559 + 0 <= x(6,7) <= 7
26.1560 + 0 <= x(7,9) <= 15
26.1561 + 0 <= x(8,9) <= 20
26.1562 +
26.1563 +End
26.1564 +\end{verbatim}
26.1565 +\end{footnotesize}
26.1566 +
26.1567 +\subsection{glp\_mincost\_okalg---solve minimum cost flow problem with
26.1568 +out-of-kilter algorithm}
26.1569 +
26.1570 +\subsubsection*{Synopsis}
26.1571 +
26.1572 +\begin{verbatim}
26.1573 +int glp_mincost_okalg(glp_graph *G, int v_rhs, int a_low,
26.1574 + int a_cap, int a_cost, double *sol, int a_x, int v_pi);
26.1575 +\end{verbatim}
26.1576 +
26.1577 +\subsubsection*{Description}
26.1578 +
26.1579 +The routine \verb|glp_mincost_okalg| finds optimal solution to the
26.1580 +minimum cost flow problem with the out-of-kilter
26.1581 +algorithm.\footnote{GLPK implementation of the out-of-kilter algorithm
26.1582 +is based on the following book: L.~R.~Ford,~Jr., and D.~R.~Fulkerson,
26.1583 +``Flows in Networks,'' The RAND Corp., Report R-375-PR (August 1962),
26.1584 +Chap. III ``Minimal Cost Flow Problems,'' pp.~113-26.} Note that this
26.1585 +routine requires all the problem data to be integer-valued.
26.1586 +
26.1587 +The parameter \verb|G| is a graph (network) program object which
26.1588 +specifies the minimum cost flow problem instance to be solved.
26.1589 +
26.1590 +The parameter \verb|v_rhs| specifies an offset of the field of type
26.1591 +\verb|double| in the vertex data block, which contains $b_i$, the
26.1592 +supply/demand value. This value must be integer in the range
26.1593 +[$-$\verb|INT_MAX|, $+$\verb|INT_MAX|]. If \verb|v_rhs| $<0$, it is
26.1594 +assumed that $b_i=0$ for all nodes.
26.1595 +
26.1596 +The parameter \verb|a_low| specifies an offset of the field of type
26.1597 +\verb|double| in the arc data block, which contains $l_{ij}$, the lower
26.1598 +bound to the arc flow. This bound must be integer in the range
26.1599 +[$0$, \verb|INT_MAX|]. If \verb|a_low| $<0$, it is assumed that
26.1600 +$l_{ij}=0$ for all arcs.
26.1601 +
26.1602 +The parameter \verb|a_cap| specifies an offset of the field of type
26.1603 +\verb|double| in the arc data block, which contains $u_{ij}$, the upper
26.1604 +bound to the arc flow (the arc capacity). This bound must be integer in
26.1605 +the range [$l_{ij}$, \verb|INT_MAX|]. If \verb|a_cap| $<0$, it is
26.1606 +assumed that $u_{ij}=1$ for all arcs.
26.1607 +
26.1608 +The parameter \verb|a_cost| specifies an offset of the field of type
26.1609 +\verb|double| in the arc data block, which contains $c_{ij}$, the
26.1610 +per-unit cost of the arc flow. This value must be integer in the range
26.1611 +[$-$\verb|INT_MAX|, $+$\verb|INT_MAX|]. If \verb|a_cost| $<0$, it is
26.1612 +assumed that $c_{ij}=0$ for all arcs.
26.1613 +
26.1614 +The parameter \verb|sol| specifies a location, to which the routine
26.1615 +stores the objective value (that is, the total cost) found. If
26.1616 +\verb|sol| is NULL, the objective value is not stored.
26.1617 +
26.1618 +The parameter \verb|a_x| specifies an offset of the field of type
26.1619 +\verb|double| in the arc data block, to which the routine stores
26.1620 +$x_{ij}$, the arc flow found. If \verb|a_x| $<0$, the arc flow value is
26.1621 +not stored.
26.1622 +
26.1623 +The parameter \verb|v_pi| specifies an offset of the field of type
26.1624 +\verb|double| in the vertex data block, to which the routine stores
26.1625 +$\pi_i$, the node potential, which is the Lagrange multiplier for the
26.1626 +corresponding flow conservation equality constraint (see (2) in
26.1627 +Subsection ``Background''). If necessary, the application program may
26.1628 +use the node potentials to compute $\lambda_{ij}$, reduced costs of the
26.1629 +arc flows $x_{ij}$, which are the Lagrange multipliers for the arc flow
26.1630 +bound constraints (see (3) ibid.), using the following formula:
26.1631 +$$\lambda_{ij}=c_{ij}-(\pi_i-\pi_j),$$
26.1632 +where $c_{ij}$ is the per-unit cost for arc $(i,j)$.
26.1633 +
26.1634 +Note that all solution components (the objective value, arc flows, and
26.1635 +node potentials) computed by the routine are always integer-valued.
26.1636 +
26.1637 +\subsubsection*{Returns}
26.1638 +
26.1639 +\def\arraystretch{1}
26.1640 +
26.1641 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
26.1642 +0 & Optimal solution found.\\
26.1643 +\verb|GLP_ENOPFS| & No (primal) feasible solution exists.\\
26.1644 +\verb|GLP_EDATA| & Unable to start the search, because some problem
26.1645 +data are either not integer-valued or out of range. This code is also
26.1646 +returned if the total supply, which is the sum of $b_i$ over all source
26.1647 +nodes (nodes with $b_i>0$), exceeds \verb|INT_MAX|.\\
26.1648 +\end{tabular}
26.1649 +
26.1650 +\noindent
26.1651 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
26.1652 +\verb|GLP_ERANGE| & The search was prematurely terminated because of
26.1653 +integer overflow.\\
26.1654 +\verb|GLP_EFAIL| & An error has been detected in the program logic.
26.1655 +(If this code is returned for your problem instance, please report to
26.1656 +\verb|<bug-glpk@gnu.org>|.)\\
26.1657 +\end{tabular}
26.1658 +
26.1659 +\subsubsection*{Comments}
26.1660 +
26.1661 +By design the out-of-kilter algorithm is applicable only to networks,
26.1662 +where $b_i=0$ for {\it all} nodes, i.e. actually this algorithm finds a
26.1663 +minimal cost {\it circulation}. Due to this requirement the routine
26.1664 +\verb|glp_mincost_okalg| converts the original network to a network
26.1665 +suitable for the out-of-kilter algorithm in the following
26.1666 +way:\footnote{The conversion is performed internally and does not change
26.1667 +the original network program object passed to the routine.}
26.1668 +
26.1669 +1) it adds two auxiliary nodes $s$ and $t$;
26.1670 +
26.1671 +2) for each original node $i$ with $b_i>0$ the routine adds auxiliary
26.1672 +supply arc $(s\rightarrow i)$, flow $x_{si}$ through which is costless
26.1673 +($c_{si}=0$) and fixed to $+b_i$ ($l_{si}=u_{si}=+b_i$);
26.1674 +
26.1675 +3) for each original node $i$ with $b_i<0$ the routine adds auxiliary
26.1676 +demand arc $(i\rightarrow t)$, flow $x_{it}$ through which is costless
26.1677 +($c_{it}=0$) and fixed to $-b_i$ ($l_{it}=u_{it}=-b_i$);
26.1678 +
26.1679 +4) finally, the routine adds auxiliary feedback arc $(t\rightarrow s)$,
26.1680 +flow $x_{ts}$ through which is also costless ($c_{ts}=0$) and fixed to
26.1681 +$F$ ($l_{ts}=u_{ts}=F$), where $\displaystyle F=\sum_{b_i>0}b_i$ is the
26.1682 +total supply.
26.1683 +
26.1684 +\subsubsection*{Example}
26.1685 +
26.1686 +The example program below reads the minimum cost problem instance in
26.1687 +DIMACS format from file `\verb|sample.min|', solves it by using the
26.1688 +routine \verb|glp_mincost_okalg|, and writes the solution found to the
26.1689 +standard output.
26.1690 +
26.1691 +\begin{footnotesize}
26.1692 +\begin{verbatim}
26.1693 +#include <stddef.h>
26.1694 +#include <stdio.h>
26.1695 +#include <stdlib.h>
26.1696 +#include <glpk.h>
26.1697 +
26.1698 +typedef struct { double rhs, pi; } v_data;
26.1699 +typedef struct { double low, cap, cost, x; } a_data;
26.1700 +
26.1701 +#define node(v) ((v_data *)((v)->data))
26.1702 +#define arc(a) ((a_data *)((a)->data))
26.1703 +
26.1704 +int main(void)
26.1705 +{ glp_graph *G;
26.1706 + glp_vertex *v, *w;
26.1707 + glp_arc *a;
26.1708 + int i, ret;
26.1709 + double sol;
26.1710 + G = glp_create_graph(sizeof(v_data), sizeof(a_data));
26.1711 + glp_read_mincost(G, offsetof(v_data, rhs),
26.1712 + offsetof(a_data, low), offsetof(a_data, cap),
26.1713 + offsetof(a_data, cost), "sample.min");
26.1714 + ret = glp_mincost_okalg(G, offsetof(v_data, rhs),
26.1715 + offsetof(a_data, low), offsetof(a_data, cap),
26.1716 + offsetof(a_data, cost), &sol, offsetof(a_data, x),
26.1717 + offsetof(v_data, pi));
26.1718 + printf("ret = %d; sol = %5g\n", ret, sol);
26.1719 + for (i = 1; i <= G->nv; i++)
26.1720 + { v = G->v[i];
26.1721 + printf("node %d: pi = %5g\n", i, node(v)->pi);
26.1722 + for (a = v->out; a != NULL; a = a->t_next)
26.1723 + { w = a->head;
26.1724 + printf("arc %d->%d: x = %5g; lambda = %5g\n",
26.1725 + v->i, w->i, arc(a)->x,
26.1726 + arc(a)->cost - (node(v)->pi - node(w)->pi));
26.1727 + }
26.1728 + }
26.1729 + glp_delete_graph(G);
26.1730 + return 0;
26.1731 +}
26.1732 +\end{verbatim}
26.1733 +\end{footnotesize}
26.1734 +
26.1735 +If `\verb|sample.min|' is the example data file from the subsection
26.1736 +describing the routine \verb|glp_read_mincost|, the output may look like
26.1737 +follows:
26.1738 +
26.1739 +\begin{footnotesize}
26.1740 +\begin{verbatim}
26.1741 +Reading min-cost flow problem data from `sample.min'...
26.1742 +Flow network has 9 nodes and 14 arcs
26.1743 +24 lines were read
26.1744 +ret = 0; sol = 213
26.1745 +node 1: pi = -12
26.1746 +arc 1->4: x = 13; lambda = 0
26.1747 +arc 1->2: x = 7; lambda = 0
26.1748 +node 2: pi = -12
26.1749 +arc 2->4: x = 0; lambda = 3
26.1750 +arc 2->3: x = 7; lambda = 0
26.1751 +node 3: pi = -14
26.1752 +arc 3->8: x = 5; lambda = 0
26.1753 +arc 3->5: x = 2; lambda = 3
26.1754 +node 4: pi = -12
26.1755 +arc 4->5: x = 13; lambda = 0
26.1756 +node 5: pi = -12
26.1757 +arc 5->7: x = 4; lambda = -1
26.1758 +arc 5->6: x = 11; lambda = 0
26.1759 +arc 5->2: x = 0; lambda = 1
26.1760 +node 6: pi = -17
26.1761 +arc 6->8: x = 4; lambda = 3
26.1762 +arc 6->7: x = 7; lambda = -3
26.1763 +node 7: pi = -20
26.1764 +arc 7->9: x = 11; lambda = 0
26.1765 +node 8: pi = -14
26.1766 +arc 8->9: x = 9; lambda = 0
26.1767 +node 9: pi = -23
26.1768 +\end{verbatim}
26.1769 +\end{footnotesize}
26.1770 +
26.1771 +\subsection{glp\_netgen---Klingman's network problem generator}
26.1772 +
26.1773 +\subsubsection*{Synopsis}
26.1774 +
26.1775 +\begin{verbatim}
26.1776 +int glp_netgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
26.1777 + const int parm[1+15]);
26.1778 +\end{verbatim}
26.1779 +
26.1780 +\subsubsection*{Description}
26.1781 +
26.1782 +The routine \verb|glp_netgen| is a GLPK version of the network problem
26.1783 +generator developed by Dr.~Darwin~Klingman.\footnote{D.~Klingman,
26.1784 +A.~Napier, and J.~Stutz. NETGEN: A program for generating large scale
26.1785 +capacitated assignment, transportation, and minimum cost flow networks.
26.1786 +Management Science 20 (1974), 814-20.} It can create capacitated and
26.1787 +uncapacitated minimum cost flow (or transshipment), transportation, and
26.1788 +assignment problems.
26.1789 +
26.1790 +The parameter \verb|G| specifies the graph object, to which the
26.1791 +generated problem data have to be stored. Note that on entry the graph
26.1792 +object is erased with the routine \verb|glp_erase_graph|.
26.1793 +
26.1794 +The parameter \verb|v_rhs| specifies an offset of the field of type
26.1795 +\verb|double| in the vertex data block, to which the routine stores the
26.1796 +supply or demand value. If \verb|v_rhs| $<0$, the value is not stored.
26.1797 +
26.1798 +The parameter \verb|a_cap| specifies an offset of the field of type
26.1799 +\verb|double| in the arc data block, to which the routine stores the
26.1800 +arc capacity. If \verb|a_cap| $<0$, the capacity is not stored.
26.1801 +
26.1802 +The parameter \verb|a_cost| specifies an offset of the field of type
26.1803 +\verb|double| in the arc data block, to which the routine stores the
26.1804 +per-unit cost if the arc flow. If \verb|a_cost| $<0$, the cost is not
26.1805 +stored.
26.1806 +
26.1807 +The array \verb|parm| contains description of the network to be
26.1808 +generated:
26.1809 +
26.1810 +\begin{tabular}{@{}lll@{}}
26.1811 +\verb|parm[0] |& ¬ used\\
26.1812 +\verb|parm[1] |&\verb|iseed |&8-digit positive random number seed\\
26.1813 +\verb|parm[2] |&\verb|nprob |&8-digit problem id number\\
26.1814 +\verb|parm[3] |&\verb|nodes |&total number of nodes\\
26.1815 +\verb|parm[4] |&\verb|nsorc |&total number of source nodes\\
26.1816 +&&(including transshipment nodes)\\
26.1817 +\verb|parm[5] |&\verb|nsink |&total number of sink nodes\\
26.1818 +&&(including transshipment nodes)\\
26.1819 +\verb|parm[6] |&\verb|iarcs |&number of arc\\
26.1820 +\verb|parm[7] |&\verb|mincst|&minimum cost for arcs\\
26.1821 +\verb|parm[8] |&\verb|maxcst|&maximum cost for arcs\\
26.1822 +\verb|parm[9] |&\verb|itsup |&total supply\\
26.1823 +\end{tabular}
26.1824 +
26.1825 +\begin{tabular}{@{}lll@{}}
26.1826 +\verb|parm[10]|&\verb|ntsorc|&number of transshipment source nodes\\
26.1827 +\verb|parm[11]|&\verb|ntsink|&number of transshipment sink nodes\\
26.1828 +\verb|parm[12]|&\verb|iphic |&percentage of skeleton arcs to be given
26.1829 +the maxi-\\&&mum cost\\
26.1830 +\verb|parm[13]|&\verb|ipcap |&percentage of arcs to be capacitated\\
26.1831 +\verb|parm[14]|&\verb|mincap|&minimum upper bound for capacitated arcs\\
26.1832 +\verb|parm[15]|&\verb|maxcap|&maximum upper bound for capacitated arcs\\
26.1833 +\end{tabular}
26.1834 +
26.1835 +\subsubsection*{Notes}
26.1836 +
26.1837 +\noindent\indent
26.1838 +1. The routine generates a transportation problem if:
26.1839 +$${\tt nsorc}+{\tt nsink}={\tt nodes},
26.1840 +\ {\tt ntsorc}=0,\ \mbox{and}\ {\tt ntsink}=0.$$
26.1841 +
26.1842 +2. The routine generates an assignment problem if the requirements for
26.1843 +a transportation problem are met and:
26.1844 +$${\tt nsorc}={\tt nsink}\ \mbox{and}\ {\tt itsup}={\tt nsorc}.$$
26.1845 +
26.1846 +3. The routine always generates connected graphs. So, if the number of
26.1847 +requested arcs has been reached and the generated instance is not fully
26.1848 +connected, the routine generates a few remaining arcs to ensure
26.1849 +connectedness. Thus, the actual number of arcs generated by the routine
26.1850 +may be greater than the requested number of arcs.
26.1851 +
26.1852 +\subsubsection*{Returns}
26.1853 +
26.1854 +If the instance was successfully generated, the routine
26.1855 +\verb|glp_netgen| returns zero; otherwise, if specified parameters are
26.1856 +inconsistent, the routine returns a non-zero error code.
26.1857 +
26.1858 +\subsection{glp\_gridgen---grid-like network problem generator}
26.1859 +
26.1860 +\subsubsection*{Synopsis}
26.1861 +
26.1862 +\begin{verbatim}
26.1863 +int glp_gridgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
26.1864 + const int parm[1+14]);
26.1865 +\end{verbatim}
26.1866 +
26.1867 +\subsubsection*{Description}
26.1868 +
26.1869 +The routine \verb|glp_gridgen| is a GLPK version of the grid-like
26.1870 +network problem generator developed by Yusin Lee and Jim
26.1871 +Orlin.\footnote{Y.~Lee and J.~Orlin. GRIDGEN generator., 1991. The
26.1872 +original code is publically available from
26.1873 +{\tt<ftp://dimacs.rutgers.edu/pub/netflow/generators/network/gridgen>}.}
26.1874 +
26.1875 +The parameter \verb|G| specifies the graph object, to which the
26.1876 +generated problem data have to be stored. Note that on entry the graph
26.1877 +object is erased with the routine \verb|glp_erase_graph|.
26.1878 +
26.1879 +The parameter \verb|v_rhs| specifies an offset of the field of type
26.1880 +\verb|double| in the vertex data block, to which the routine stores the
26.1881 +supply or demand value. If \verb|v_rhs| $<0$, the value is not stored.
26.1882 +
26.1883 +The parameter \verb|a_cap| specifies an offset of the field of type
26.1884 +\verb|double| in the arc data block, to which the routine stores the
26.1885 +arc capacity. If \verb|a_cap| $<0$, the capacity is not stored.
26.1886 +
26.1887 +The parameter \verb|a_cost| specifies an offset of the field of type
26.1888 +\verb|double| in the arc data block, to which the routine stores the
26.1889 +per-unit cost if the arc flow. If \verb|a_cost| $<0$, the cost is not
26.1890 +stored.
26.1891 +
26.1892 +The array \verb|parm| contains parameters of the network to be
26.1893 +generated:
26.1894 +
26.1895 +\begin{tabular}{@{}ll@{}}
26.1896 +\verb|parm[0] |¬ used\\
26.1897 +\verb|parm[1] |&two-ways arcs indicator:\\
26.1898 + &1 --- if links in both direction should be generated\\
26.1899 + &0 --- otherwise\\
26.1900 +\verb|parm[2] |&random number seed (a positive integer)\\
26.1901 +\verb|parm[3] |&number of nodes (the number of nodes generated might
26.1902 +be\\&slightly different to make the network a grid)\\
26.1903 +\verb|parm[4] |&grid width\\
26.1904 +\verb|parm[5] |&number of sources\\
26.1905 +\verb|parm[6] |&number of sinks\\
26.1906 +\verb|parm[7] |&average degree\\
26.1907 +\verb|parm[8] |&total flow\\
26.1908 +\verb|parm[9] |&distribution of arc costs:\\
26.1909 + &1 --- uniform\\
26.1910 + &2 --- exponential\\
26.1911 +\verb|parm[10]|&lower bound for arc cost (uniform)\\
26.1912 + &$100\lambda$ (exponential)\\
26.1913 +\verb|parm[11]|&upper bound for arc cost (uniform)\\
26.1914 + ¬ used (exponential)\\
26.1915 +\verb|parm[12]|&distribution of arc capacities:\\
26.1916 + &1 --- uniform\\
26.1917 + &2 --- exponential\\
26.1918 +\verb|parm[13]|&lower bound for arc capacity (uniform)\\
26.1919 + &$100\lambda$ (exponential)\\
26.1920 +\verb|parm[14]|&upper bound for arc capacity (uniform)\\
26.1921 + ¬ used (exponential)\\
26.1922 +\end{tabular}
26.1923 +
26.1924 +\subsubsection*{Returns}
26.1925 +
26.1926 +If the instance was successfully generated, the routine
26.1927 +\verb|glp_gridgen| returns zero; otherwise, if specified parameters are
26.1928 +inconsistent, the routine returns a non-zero error code.
26.1929 +
26.1930 +\subsubsection*{Comments\footnote{This material is based on comments
26.1931 +to the original version of GRIDGEN.}}
26.1932 +
26.1933 +This network generator generates a grid-like network plus a super node.
26.1934 +In additional to the arcs connecting the nodes in the grid, there is an
26.1935 +arc from each supply node to the super node and from the super node to
26.1936 +each demand node to guarantee feasiblity. These arcs have very high
26.1937 +costs and very big capacities.
26.1938 +
26.1939 +The idea of this network generator is as follows: First, a grid of
26.1940 +$n_1\times n_2$ is generated. For example, $5\times 3$. The nodes are
26.1941 +numbered as 1 to 15, and the supernode is numbered as $n_1\times n_2+1$.
26.1942 +Then arcs between adjacent nodes are generated. For these arcs, the user
26.1943 +is allowed to specify either to generate two-way arcs or one-way arcs.
26.1944 +If two-way arcs are to be generated, two arcs, one in each direction,
26.1945 +will be generated between each adjacent node pairs. Otherwise, only one
26.1946 +arc will be generated. If this is the case, the arcs will be generated
26.1947 +in alterntive directions as shown below.
26.1948 +
26.1949 +\bigskip
26.1950 +
26.1951 +\noindent\hfil
26.1952 +\xymatrix
26.1953 +{1\ar[r]\ar[d]&2\ar[r]&3\ar[r]\ar[d]&4\ar[r]&5\ar[d]\\
26.1954 +6\ar[d]&7\ar[l]\ar[u]&8\ar[l]\ar[d]&9\ar[l]\ar[u]&10\ar[l]\ar[d]\\
26.1955 +11\ar[r]&12\ar[r]\ar[u]&13\ar[r]&14\ar[r]\ar[u]&15\\
26.1956 +}
26.1957 +
26.1958 +\bigskip
26.1959 +
26.1960 +Then the arcs between the super node and the source/sink nodes are added
26.1961 +as mentioned before. If the number of arcs still doesn't reach the
26.1962 +requirement, additional arcs will be added by uniformly picking random
26.1963 +node pairs. There is no checking to prevent multiple arcs between any
26.1964 +pair of nodes. However, there will be no self-arcs (arcs that poins back
26.1965 +to its tail node) in the network.
26.1966 +
26.1967 +The source and sink nodes are selected uniformly in the network, and
26.1968 +the imbalances of each source/sink node are also assigned by uniform
26.1969 +distribution.
26.1970 +
26.1971 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
26.1972 +
26.1973 +\newpage
26.1974 +
26.1975 +\section{Maximum flow problem}
26.1976 +
26.1977 +\subsection{Background}
26.1978 +
26.1979 +The {\it maximum flow problem} (MAXFLOW) is stated as follows. Let
26.1980 +there be given a directed graph (flow network) $G=(V,A)$, where $V$ is
26.1981 +a set of vertices (nodes), and $A\subseteq V\times V$ is a set of arcs.
26.1982 +Let also for each arc $a=(i,j)\in A$ there be given its capacity
26.1983 +$u_{ij}$. The problem is, for given {\it source} node $s\in V$ and
26.1984 +{\it sink} node $t\in V$, to find flows $x_{ij}$ through every arc of
26.1985 +the network, which satisfy the specified arc capacities and the
26.1986 +conservation constraints at all nodes, and maximize the total flow $F$
26.1987 +through the network from $s$ to $t$. Here the conservation constraint
26.1988 +at a node means that the total flow entering this node through its
26.1989 +incoming arcs (plus $F$, if it is the source node) must be equal to the
26.1990 +total flow leaving this node through its outgoing arcs (plus $F$, if it
26.1991 +is the sink node).
26.1992 +
26.1993 +An example of the maximum flow problem, where $s=v_1$ and $t=v_9$, is
26.1994 +shown on Fig.~2.
26.1995 +
26.1996 +\bigskip
26.1997 +
26.1998 +\noindent\hfil
26.1999 +\xymatrix @C=48pt
26.2000 +{_{F}\ar@{~>}[d]&
26.2001 +v_2\ar[r]|{_{10}}\ar[dd]|{_{9}}&
26.2002 +v_3\ar[dd]|{_{12}}\ar[r]|{_{18}}&
26.2003 +v_8\ar[rd]|{_{20}}&\\
26.2004 +v_1\ar[ru]|{_{14}}\ar[rd]|{_{23}}&&&
26.2005 +v_6\ar[d]|{_{7}}\ar[u]|{_{8}}&
26.2006 +v_9\ar@{~>}[d]\\
26.2007 +&v_4\ar[r]|{_{26}}&
26.2008 +v_5\ar[luu]|{_{11}}\ar[ru]|{_{25}}\ar[r]|{_{4}}&
26.2009 +v_7\ar[ru]|{_{15}}&_{F}\\
26.2010 +}
26.2011 +
26.2012 +\bigskip
26.2013 +
26.2014 +\noindent\hfil
26.2015 +Fig.~2. An example of the maximum flow problem.
26.2016 +
26.2017 +\bigskip
26.2018 +
26.2019 +The maximum flow problem can be naturally formulated as the following
26.2020 +LP problem:
26.2021 +
26.2022 +\medskip
26.2023 +
26.2024 +\noindent
26.2025 +\hspace{.5in}maximize
26.2026 +$$F\eqno(4)$$
26.2027 +\hspace{.5in}subject to
26.2028 +$$\sum_{(i,j)\in A}x_{ij}-\sum_{(j,i)\in A}x_{ji}=\left\{
26.2029 +\begin{array}{@{\ }rl}
26.2030 ++F,&\hbox{for}\ i=s\\
26.2031 + 0,&\hbox{for all}\ i\in V\backslash\{s,t\}\\
26.2032 +-F,&\hbox{for}\ i=t\\
26.2033 +\end{array}
26.2034 +\right.\eqno(5)
26.2035 +$$
26.2036 +$$0\leq x_{ij}\leq u_{ij}\ \ \ \hbox{for all}\ (i,j)\in A
26.2037 +\eqno(6)$$
26.2038 +
26.2039 +\medskip
26.2040 +
26.2041 +\noindent
26.2042 +where $F\geq 0$ is an additional variable playing the role of the
26.2043 +objective.
26.2044 +
26.2045 +\newpage
26.2046 +
26.2047 +Another LP formulation of the maximum flow problem, which does not
26.2048 +include the variable $F$, is the following:
26.2049 +
26.2050 +\medskip
26.2051 +
26.2052 +\noindent
26.2053 +\hspace{.5in}maximize
26.2054 +$$z=\sum_{(s,j)\in A}x_{sj}-\sum_{(j,s)\in A}x_{js}\ (=F)\eqno(7)$$
26.2055 +\hspace{.5in}subject to
26.2056 +$$\sum_{(i,j)\in A}x_{ij}-\sum_{(j,i)\in A}x_{ji}\left\{
26.2057 +\begin{array}{@{\ }rl}
26.2058 +\geq 0,&\hbox{for}\ i=s\\
26.2059 +=0,&\hbox{for all}\ i\in V\backslash\{s,t\}\\
26.2060 +\leq 0,&\hbox{for}\ i=t\\
26.2061 +\end{array}
26.2062 +\right.\eqno(8)
26.2063 +$$
26.2064 +$$0\leq x_{ij}\leq u_{ij}\ \ \ \hbox{for all}\ (i,j)\in A
26.2065 +\eqno(9)$$
26.2066 +
26.2067 +\subsection{glp\_read\_maxflow---read maximum flow problem data\\in
26.2068 +DIMACS format}
26.2069 +
26.2070 +\subsubsection*{Synopsis}
26.2071 +
26.2072 +\begin{verbatim}
26.2073 +int glp_read_maxflow(glp_graph *G, int *s, int *t, int a_cap,
26.2074 + const char *fname);
26.2075 +\end{verbatim}
26.2076 +
26.2077 +\subsubsection*{Description}
26.2078 +
26.2079 +The routine \verb|glp_read_maxflow| reads the maximum flow problem
26.2080 +data from a text file in DIMACS format.
26.2081 +
26.2082 +The parameter \verb|G| specifies the graph object, to which the problem
26.2083 +data have to be stored. Note that before reading data the current
26.2084 +content of the graph object is completely erased with the routine
26.2085 +\verb|glp_erase_graph|.
26.2086 +
26.2087 +The pointer \verb|s| specifies a location, to which the routine stores
26.2088 +the ordinal number of the source node. If \verb|s| is \verb|NULL|, the
26.2089 +source node number is not stored.
26.2090 +
26.2091 +The pointer \verb|t| specifies a location, to which the routine stores
26.2092 +the ordinal number of the sink node. If \verb|t| is \verb|NULL|, the
26.2093 +sink node number is not stored.
26.2094 +
26.2095 +The parameter \verb|a_cap| specifies an offset of the field of type
26.2096 +\verb|double| in the arc data block, to which the routine stores
26.2097 +$u_{ij}$, the arc capacity. If \verb|a_cap| $<0$, the arc capacity is
26.2098 +not stored.
26.2099 +
26.2100 +The character string \verb|fname| specifies the name of a text file to
26.2101 +be read in. (If the file name name ends with the suffix `\verb|.gz|',
26.2102 +the file is assumed to be compressed, in which case the routine
26.2103 +decompresses it ``on the fly''.)
26.2104 +
26.2105 +\subsubsection*{Returns}
26.2106 +
26.2107 +If the operation was successful, the routine returns zero. Otherwise,
26.2108 +it prints an error message and returns non-zero.
26.2109 +
26.2110 +\subsubsection*{Example}
26.2111 +
26.2112 +\begin{footnotesize}
26.2113 +\begin{verbatim}
26.2114 +typedef struct
26.2115 +{ /* arc data block */
26.2116 + ...
26.2117 + double cap;
26.2118 + ...
26.2119 +} a_data;
26.2120 +
26.2121 +int main(void)
26.2122 +{ glp_graph *G;
26.2123 + int s, t, ret;
26.2124 + G = glp_create_graph(..., sizeof(a_data));
26.2125 + ret = glp_read_maxflow(G, &s, &t, offsetof(a_data, cap),
26.2126 + "sample.max");
26.2127 + if (ret != 0) goto ...
26.2128 + ...
26.2129 +}
26.2130 +\end{verbatim}
26.2131 +\end{footnotesize}
26.2132 +
26.2133 +\subsubsection*{DIMACS maximum flow problem format\footnote{This
26.2134 +material is based on the paper ``The First DIMACS International
26.2135 +Algorithm Implementation Challenge: Problem Definitions and
26.2136 +Specifications'', which is publically available at
26.2137 +{\tt http://dimacs.rutgers.edu/Challenges/}.}}
26.2138 +\label{subsecmaxflow}
26.2139 +
26.2140 +The DIMACS input file is a plain ASCII text file. It contains
26.2141 +{\it lines} of several types described below. A line is terminated with
26.2142 +an end-of-line character. Fields in each line are separated by at least
26.2143 +one blank space. Each line begins with a one-character designator to
26.2144 +identify the line type.
26.2145 +
26.2146 +Note that DIMACS requires all numerical quantities to be integers in
26.2147 +the range $[-2^{31},\ 2^{31}-1]$ while GLPK allows the quantities to be
26.2148 +floating-point numbers.
26.2149 +
26.2150 +\paragraph{Comment lines.} Comment lines give human-readable information
26.2151 +about the file and are ignored by programs. Comment lines can appear
26.2152 +anywhere in the file. Each comment line begins with a lower-case
26.2153 +character \verb|c|.
26.2154 +
26.2155 +\begin{verbatim}
26.2156 + c This is a comment line
26.2157 +\end{verbatim}
26.2158 +
26.2159 +\newpage
26.2160 +
26.2161 +\paragraph{Problem line.} There is one problem line per data file. The
26.2162 +problem line must appear before any node or arc descriptor lines. It has
26.2163 +the following format:
26.2164 +
26.2165 +\begin{verbatim}
26.2166 + p max NODES ARCS
26.2167 +\end{verbatim}
26.2168 +
26.2169 +\noindent
26.2170 +The lower-case character \verb|p| signifies that this is a problem line.
26.2171 +The three-character problem designator \verb|max| identifies the file as
26.2172 +containing specification information for the maximum flow problem. The
26.2173 +\verb|NODES| field contains an integer value specifying the number of
26.2174 +nodes in the network. The \verb|ARCS| field contains an integer value
26.2175 +specifying the number of arcs in the network.
26.2176 +
26.2177 +\paragraph{Node descriptors.} Two node descriptor lines for the source
26.2178 +and sink nodes must appear before all arc descriptor lines. They may
26.2179 +appear in either order, each with the following format:
26.2180 +
26.2181 +\begin{verbatim}
26.2182 + n ID WHICH
26.2183 +\end{verbatim}
26.2184 +
26.2185 +\noindent
26.2186 +The lower-case character \verb|n| signifies that this a node descriptor
26.2187 +line. The \verb|ID| field gives a node identification number, an integer
26.2188 +between 1 and \verb|NODES|. The \verb|WHICH| field gives either a
26.2189 +lower-case \verb|s| or \verb|t|, designating the source and sink,
26.2190 +respectively.
26.2191 +
26.2192 +\paragraph{Arc descriptors.} There is one arc descriptor line for each
26.2193 +arc in the network. Arc descriptor lines are of the following format:
26.2194 +
26.2195 +\begin{verbatim}
26.2196 + a SRC DST CAP
26.2197 +\end{verbatim}
26.2198 +
26.2199 +\noindent
26.2200 +The lower-case character \verb|a| signifies that this is an arc
26.2201 +descriptor line. For a directed arc $(i,j)$ the \verb|SRC| field gives
26.2202 +the identification number $i$ for the tail endpoint, and the \verb|DST|
26.2203 +field gives the identification number $j$ for the head endpoint.
26.2204 +Identification numbers are integers between 1 and \verb|NODES|. The
26.2205 +\verb|CAP| field gives the arc capacity, i.e. maximum amount of flow
26.2206 +that can be sent along arc $(i,j)$ in a feasible flow.
26.2207 +
26.2208 +\paragraph{Example.} Below here is an example of the data file in
26.2209 +DIMACS format corresponding to the maximum flow problem shown on Fig~2.
26.2210 +
26.2211 +\newpage
26.2212 +
26.2213 +\begin{footnotesize}
26.2214 +\begin{verbatim}
26.2215 +c sample.max
26.2216 +c
26.2217 +c This is an example of the maximum flow problem data
26.2218 +c in DIMACS format.
26.2219 +c
26.2220 +p max 9 14
26.2221 +c
26.2222 +n 1 s
26.2223 +n 9 t
26.2224 +c
26.2225 +a 1 2 14
26.2226 +a 1 4 23
26.2227 +a 2 3 10
26.2228 +a 2 4 9
26.2229 +a 3 5 12
26.2230 +a 3 8 18
26.2231 +a 4 5 26
26.2232 +a 5 2 11
26.2233 +a 5 6 25
26.2234 +a 5 7 4
26.2235 +a 6 7 7
26.2236 +a 6 8 8
26.2237 +a 7 9 15
26.2238 +a 8 9 20
26.2239 +c
26.2240 +c eof
26.2241 +\end{verbatim}
26.2242 +\end{footnotesize}
26.2243 +
26.2244 +\subsection{glp\_write\_maxflow---write maximum flow problem data\\
26.2245 +in DIMACS format}
26.2246 +
26.2247 +\subsubsection*{Synopsis}
26.2248 +
26.2249 +\begin{verbatim}
26.2250 +int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
26.2251 + const char *fname);
26.2252 +\end{verbatim}
26.2253 +
26.2254 +\subsubsection*{Description}
26.2255 +
26.2256 +The routine \verb|glp_write_maxflow| writes the maximum flow problem
26.2257 +data to a text file in DIMACS format.
26.2258 +
26.2259 +The parameter \verb|G| is the graph (network) program object, which
26.2260 +specifies the maximum flow problem instance.
26.2261 +
26.2262 +The parameter \verb|s| specifies the ordinal number of the source node.
26.2263 +
26.2264 +The parameter \verb|t| specifies the ordinal number of the sink node.
26.2265 +
26.2266 +The parameter \verb|a_cap| specifies an offset of the field of type
26.2267 +\verb|double| in the arc data block, which contains $u_{ij}$, the upper
26.2268 +bound to the arc flow (the arc capacity). If the upper bound is
26.2269 +specified as \verb|DBL_MAX|, it is assumed that $u_{ij}=\infty$, i.e.
26.2270 +the arc is uncapacitated. If \verb|a_cap| $<0$, it is assumed that
26.2271 +$u_{ij}=1$ for all arcs.
26.2272 +
26.2273 +The character string \verb|fname| specifies a name of the text file to
26.2274 +be written out. (If the file name ends with suffix `\verb|.gz|', the
26.2275 +file is assumed to be compressed, in which case the routine performs
26.2276 +automatic compression on writing it.)
26.2277 +
26.2278 +\subsubsection*{Returns}
26.2279 +
26.2280 +If the operation was successful, the routine returns zero. Otherwise,
26.2281 +it prints an error message and returns non-zero.
26.2282 +
26.2283 +\subsection{glp\_maxflow\_lp---convert maximum flow problem to LP}
26.2284 +
26.2285 +\subsubsection*{Synopsis}
26.2286 +
26.2287 +\begin{verbatim}
26.2288 +void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names,
26.2289 + int s, int t, int a_cap);
26.2290 +\end{verbatim}
26.2291 +
26.2292 +\subsubsection*{Description}
26.2293 +
26.2294 +The routine \verb|glp_maxflow_lp| builds LP problem (7)---(9), which
26.2295 +corresponds to the specified maximum flow problem.
26.2296 +
26.2297 +The parameter \verb|lp| is the resultant LP problem object to be built.
26.2298 +Note that on entry its current content is erased with the routine
26.2299 +\verb|glp_erase_prob|.
26.2300 +
26.2301 +The parameter \verb|G| is the graph (network) program object, which
26.2302 +specifies the maximum flow problem instance.
26.2303 +
26.2304 +The parameter \verb|names| is a flag. If it is \verb|GLP_ON|, the
26.2305 +routine uses symbolic names of the graph object components to assign
26.2306 +symbolic names to the LP problem object components. If the flag is
26.2307 +\verb|GLP_OFF|, no symbolic names are assigned.
26.2308 +
26.2309 +The parameter \verb|s| specifies the ordinal number of the source node.
26.2310 +
26.2311 +The parameter \verb|t| specifies the ordinal number of the sink node.
26.2312 +
26.2313 +The parameter \verb|a_cap| specifies an offset of the field of type
26.2314 +\verb|double| in the arc data block, which contains $u_{ij}$, the upper
26.2315 +bound to the arc flow (the arc capacity). If the upper bound is
26.2316 +specified as \verb|DBL_MAX|, it is assumed that $u_{ij}=\infty$, i.e.
26.2317 +the arc is uncapacitated. If \verb|a_cap| $<0$, it is assumed that
26.2318 +$u_{ij}=1$ for all arcs.
26.2319 +
26.2320 +\subsubsection*{Example}
26.2321 +
26.2322 +The example program below reads the maximum flow problem in DIMACS
26.2323 +format from file `\verb|sample.max|', converts the instance to LP, and
26.2324 +then writes the resultant LP in CPLEX format to file
26.2325 +`\verb|maxflow.lp|'.
26.2326 +
26.2327 +\begin{footnotesize}
26.2328 +\begin{verbatim}
26.2329 +#include <stddef.h>
26.2330 +#include <glpk.h>
26.2331 +
26.2332 +int main(void)
26.2333 +{ glp_graph *G;
26.2334 + glp_prob *lp;
26.2335 + int s, t;
26.2336 + G = glp_create_graph(0, sizeof(double));
26.2337 + glp_read_maxflow(G, &s, &t, 0, "sample.max");
26.2338 + lp = glp_create_prob();
26.2339 + glp_maxflow_lp(lp, G, GLP_ON, s, t, 0);
26.2340 + glp_delete_graph(G);
26.2341 + glp_write_lp(lp, NULL, "maxflow.lp");
26.2342 + glp_delete_prob(lp);
26.2343 + return 0;
26.2344 +}
26.2345 +\end{verbatim}
26.2346 +\end{footnotesize}
26.2347 +
26.2348 +If `\verb|sample.max|' is the example data file from the previous
26.2349 +subsection, the output `\verb|maxflow.lp|' may look like follows:
26.2350 +
26.2351 +\begin{footnotesize}
26.2352 +\begin{verbatim}
26.2353 +Maximize
26.2354 + obj: + x(1,4) + x(1,2)
26.2355 +
26.2356 +Subject To
26.2357 + r_1: + x(1,2) + x(1,4) >= 0
26.2358 + r_2: - x(5,2) + x(2,3) + x(2,4) - x(1,2) = 0
26.2359 + r_3: + x(3,5) + x(3,8) - x(2,3) = 0
26.2360 + r_4: + x(4,5) - x(2,4) - x(1,4) = 0
26.2361 + r_5: + x(5,2) + x(5,6) + x(5,7) - x(4,5) - x(3,5) = 0
26.2362 + r_6: + x(6,7) + x(6,8) - x(5,6) = 0
26.2363 + r_7: + x(7,9) - x(6,7) - x(5,7) = 0
26.2364 + r_8: + x(8,9) - x(6,8) - x(3,8) = 0
26.2365 + r_9: - x(8,9) - x(7,9) <= 0
26.2366 +
26.2367 +Bounds
26.2368 + 0 <= x(1,4) <= 23
26.2369 + 0 <= x(1,2) <= 14
26.2370 + 0 <= x(2,4) <= 9
26.2371 + 0 <= x(2,3) <= 10
26.2372 + 0 <= x(3,8) <= 18
26.2373 + 0 <= x(3,5) <= 12
26.2374 + 0 <= x(4,5) <= 26
26.2375 + 0 <= x(5,7) <= 4
26.2376 + 0 <= x(5,6) <= 25
26.2377 + 0 <= x(5,2) <= 11
26.2378 + 0 <= x(6,8) <= 8
26.2379 + 0 <= x(6,7) <= 7
26.2380 + 0 <= x(7,9) <= 15
26.2381 + 0 <= x(8,9) <= 20
26.2382 +
26.2383 +End
26.2384 +\end{verbatim}
26.2385 +\end{footnotesize}
26.2386 +
26.2387 +\subsection{glp\_maxflow\_ffalg---solve maximum flow problem with
26.2388 +Ford-Fulkerson algorithm}
26.2389 +
26.2390 +\subsubsection*{Synopsis}
26.2391 +
26.2392 +\begin{verbatim}
26.2393 +int glp_maxflow_ffalg(glp_graph *G, int s, int t, int a_cap,
26.2394 + double *sol, int a_x, int v_cut);
26.2395 +\end{verbatim}
26.2396 +
26.2397 +\subsubsection*{Description}
26.2398 +
26.2399 +The routine \verb|glp_mincost_ffalg| finds optimal solution to the
26.2400 +maximum flow problem with the Ford-Fulkerson algorithm.\footnote{GLPK
26.2401 +implementation of the Ford-Fulkerson algorithm is based on the following
26.2402 +book: L.~R.~Ford,~Jr., and D.~R.~Fulkerson, ``Flows in Networks,'' The
26.2403 +RAND Corp., Report\linebreak R-375-PR (August 1962), Chap. I
26.2404 +``Static Maximal Flow,'' pp.~30-33.} Note that this routine requires all
26.2405 +the problem data to be integer-valued.
26.2406 +
26.2407 +The parameter \verb|G| is a graph (network) program object which
26.2408 +specifies the maximum flow problem instance to be solved.
26.2409 +
26.2410 +The parameter $s$ specifies the ordinal number of the source node.
26.2411 +
26.2412 +The parameter $t$ specifies the ordinal number of the sink node.
26.2413 +
26.2414 +The parameter \verb|a_cap| specifies an offset of the field of type
26.2415 +\verb|double| in the arc data block, which contains $u_{ij}$, the upper
26.2416 +bound to the arc flow (the arc capacity). This bound must be integer in
26.2417 +the range [0, \verb|INT_MAX|]. If \verb|a_cap| $<0$, it is assumed that
26.2418 +$u_{ij}=1$ for all arcs.
26.2419 +
26.2420 +The parameter \verb|sol| specifies a location, to which the routine
26.2421 +stores the objective value (that is, the total flow from $s$ to $t$)
26.2422 +found. If \verb|sol| is NULL, the objective value is not stored.
26.2423 +
26.2424 +The parameter \verb|a_x| specifies an offset of the field of type
26.2425 +\verb|double| in the arc data block, to which the routine stores
26.2426 +$x_{ij}$, the arc flow found. If \verb|a_x| $<0$, the arc flow values
26.2427 +are not stored.
26.2428 +
26.2429 +The parameter \verb|v_cut| specifies an offset of the field of type
26.2430 +\verb|int| in the vertex data block, to which the routine stores node
26.2431 +flags corresponding to the optimal solution found: if the node flag is
26.2432 +1, the node is labelled, and if the node flag is 0, the node is
26.2433 +unlabelled. The calling program may use these node flags to determine
26.2434 +the {\it minimal cut}, which is a subset of arcs whose one endpoint is
26.2435 +labelled and other is not. If \verb|v_cut| $<0$, the node flags are not
26.2436 +stored.
26.2437 +
26.2438 +Note that all solution components (the objective value and arc flows)
26.2439 +computed by the routine are always integer-valued.
26.2440 +
26.2441 +\subsubsection*{Returns}
26.2442 +
26.2443 +\def\arraystretch{1}
26.2444 +
26.2445 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
26.2446 +0 & Optimal solution found.\\
26.2447 +\verb|GLP_EDATA| & Unable to start the search, because some problem
26.2448 +data are either not integer-valued or out of range.\\
26.2449 +\end{tabular}
26.2450 +
26.2451 +\subsubsection*{Example}
26.2452 +
26.2453 +The example program shown below reads the maximum flow problem instance
26.2454 +in DIMACS format from file `\verb|sample.max|', solves it using the
26.2455 +routine \verb|glp_maxflow_ffalg|, and write the solution found to the
26.2456 +standard output.
26.2457 +
26.2458 +\begin{footnotesize}
26.2459 +\begin{verbatim}
26.2460 +#include <stddef.h>
26.2461 +#include <stdio.h>
26.2462 +#include <stdlib.h>
26.2463 +#include <glpk.h>
26.2464 +
26.2465 +typedef struct { int cut; } v_data;
26.2466 +typedef struct { double cap, x; } a_data;
26.2467 +
26.2468 +#define node(v) ((v_data *)((v)->data))
26.2469 +#define arc(a) ((a_data *)((a)->data))
26.2470 +
26.2471 +int main(void)
26.2472 +{ glp_graph *G;
26.2473 + glp_vertex *v, *w;
26.2474 + glp_arc *a;
26.2475 + int i, s, t, ret;
26.2476 + double sol;
26.2477 + G = glp_create_graph(sizeof(v_data), sizeof(a_data));
26.2478 + glp_read_maxflow(G, &s, &t, offsetof(a_data, cap),
26.2479 + "sample.max");
26.2480 + ret = glp_maxflow_ffalg(G, s, t, offsetof(a_data, cap),
26.2481 + &sol, offsetof(a_data, x), offsetof(v_data, cut));
26.2482 + printf("ret = %d; sol = %5g\n", ret, sol);
26.2483 + for (i = 1; i <= G->nv; i++)
26.2484 + { v = G->v[i];
26.2485 + for (a = v->out; a != NULL; a = a->t_next)
26.2486 + { w = a->head;
26.2487 + printf("x[%d->%d] = %5g (%d)\n", v->i, w->i,
26.2488 + arc(a)->x, node(v)->cut ^ node(w)->cut);
26.2489 + }
26.2490 + }
26.2491 + glp_delete_graph(G);
26.2492 + return 0;
26.2493 +}
26.2494 +\end{verbatim}
26.2495 +\end{footnotesize}
26.2496 +
26.2497 +If `\verb|sample.max|' is the example data file from the subsection
26.2498 +describing the routine \verb|glp_read_maxflow|, the output may look like
26.2499 +follows:
26.2500 +
26.2501 +\begin{footnotesize}
26.2502 +\begin{verbatim}
26.2503 +Reading maximum flow problem data from `sample.max'...
26.2504 +Flow network has 9 nodes and 14 arcs
26.2505 +24 lines were read
26.2506 +ret = 0; sol = 29
26.2507 +x[1->4] = 19 (0)
26.2508 +x[1->2] = 10 (0)
26.2509 +x[2->4] = 0 (0)
26.2510 +x[2->3] = 10 (1)
26.2511 +x[3->8] = 10 (0)
26.2512 +x[3->5] = 0 (1)
26.2513 +x[4->5] = 19 (0)
26.2514 +x[5->7] = 4 (1)
26.2515 +x[5->6] = 15 (0)
26.2516 +x[5->2] = 0 (0)
26.2517 +x[6->8] = 8 (1)
26.2518 +x[6->7] = 7 (1)
26.2519 +x[7->9] = 11 (0)
26.2520 +x[8->9] = 18 (0)
26.2521 +\end{verbatim}
26.2522 +\end{footnotesize}
26.2523 +
26.2524 +\newpage
26.2525 +
26.2526 +\subsection{glp\_rmfgen---Goldfarb's maximum flow problem generator}
26.2527 +
26.2528 +\subsubsection*{Synopsis}
26.2529 +
26.2530 +\begin{verbatim}
26.2531 +int glp_rmfgen(glp_graph *G, int *s, int *t, int a_cap,
26.2532 + const int parm[1+5]);
26.2533 +\end{verbatim}
26.2534 +
26.2535 +\subsubsection*{Description}
26.2536 +
26.2537 +The routine \verb|glp_rmfgen| is a GLPK version of the maximum flow
26.2538 +problem generator developed by D.~Goldfarb and
26.2539 +M.~Grigoriadis.\footnote{D.~Goldfarb and M.~D.~Grigoriadis,
26.2540 +``A computational comparison of the Dinic and network simplex methods
26.2541 +for maximum flow.'' Annals of Op. Res. 13 (1988),
26.2542 +pp.~83-123.}$^{,}$\footnote{U.~Derigs and W.~Meier, ``Implementing
26.2543 +Goldberg's max-flow algorithm: A computational investigation.''
26.2544 +Zeitschrift f\"ur Operations Research 33 (1989),
26.2545 +pp.~383-403.}$^{,}$\footnote{The original code of RMFGEN implemented by
26.2546 +Tamas Badics is publically available from
26.2547 +{\tt <ftp://dimacs.rutgers.edu/pub/netflow/generators/network/genrmf>}.}
26.2548 +
26.2549 +The parameter \verb|G| specifies the graph object, to which the
26.2550 +generated problem data have to be stored. Note that on entry the graph
26.2551 +object is erased with the routine \verb|glp_erase_graph|.
26.2552 +
26.2553 +The pointers \verb|s| and \verb|t| specify locations, to which the
26.2554 +routine stores the source and sink node numbers, respectively. If
26.2555 +\verb|s| or \verb|t| is \verb|NULL|, corresponding node number is not
26.2556 +stored.
26.2557 +
26.2558 +The parameter \verb|a_cap| specifies an offset of the field of type
26.2559 +\verb|double| in the arc data block, to which the routine stores the arc
26.2560 +capacity. If \verb|a_cap| $<0$, the capacity is not stored.
26.2561 +
26.2562 +The array \verb|parm| contains description of the network to be
26.2563 +generated:
26.2564 +
26.2565 +\begin{tabular}{@{}lll@{}}
26.2566 +\verb|parm[0]|& ¬ used\\
26.2567 +\verb|parm[1]|&\verb|seed|&random number seed (a positive integer)\\
26.2568 +\verb|parm[2]|&\verb|a |&frame size\\
26.2569 +\verb|parm[3]|&\verb|b |&depth\\
26.2570 +\verb|parm[4]|&\verb|c1 |&minimal arc capacity\\
26.2571 +\verb|parm[5]|&\verb|c2 |&maximal arc capacity\\
26.2572 +\end{tabular}
26.2573 +
26.2574 +\subsubsection*{Returns}
26.2575 +
26.2576 +If the instance was successfully generated, the routine
26.2577 +\verb|glp_netgen| returns zero; otherwise, if specified parameters are
26.2578 +inconsistent, the routine returns a non-zero error code.
26.2579 +
26.2580 +\newpage
26.2581 +
26.2582 +\subsubsection*{Comments\footnote{This material is based on comments
26.2583 +to the original version of RMFGEN.}}
26.2584 +
26.2585 +The generated network is as follows. It has $b$ pieces of frames of
26.2586 +size $a\times a$. (So alltogether the number of vertices is
26.2587 +$a\times a\times b$.)
26.2588 +
26.2589 +In each frame all the vertices are connected with their neighbours
26.2590 +(forth and back). In addition the vertices of a frame are connected
26.2591 +one to one with the vertices of next frame using a random permutation
26.2592 +of those vertices.
26.2593 +
26.2594 +The source is the lower left vertex of the first frame, the sink is
26.2595 +the upper right vertex of the $b$-th frame.
26.2596 +
26.2597 +\begin{verbatim}
26.2598 + t
26.2599 + +-------+
26.2600 + | .|
26.2601 + | . |
26.2602 + / | / |
26.2603 + +-------+/ -+ b
26.2604 + | | |/.
26.2605 + a | -v- |/
26.2606 + | | |/
26.2607 + +-------+ 1
26.2608 + s a
26.2609 +\end{verbatim}
26.2610 +
26.2611 +The capacities are randomly chosen integers from the range of
26.2612 +$[c_1,c_2]$ in the case of interconnecting edges, and $c_2\cdot a^2$
26.2613 +for the in-frame edges.
26.2614 +
26.2615 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
26.2616 +
26.2617 +\newpage
26.2618 +
26.2619 +\section{Assignment problem}
26.2620 +
26.2621 +\subsection{Background}
26.2622 +
26.2623 +Let there be given an undirected bipartite graph $G=(R\cup S,E)$, where
26.2624 +$R$ and $S$ are disjoint sets of vertices (nodes), and
26.2625 +$E\subseteq R\times S$ is a set of edges. Let also for each edge
26.2626 +$e=(i,j)\in E$ there be given its cost $c_{ij}$. A {\it matching}
26.2627 +(which in case of bipartite graph is also called {\it assignment})
26.2628 +$M\subseteq E$ in $G$ is a set of pairwise non-adjacent edges, that is,
26.2629 +no two edges in $M$ share a common vertex. A matching, which matches
26.2630 +all vertices of the graph, is called a {\it perfect matching}.
26.2631 +Obviously, a perfect matching in bipartite graph $G=(R\cup S,E)$
26.2632 +defines some bijection $R\leftrightarrow S$.
26.2633 +
26.2634 +The {\it assignment problem} has two different variants. In the first
26.2635 +variant the problem is to find matching (assignment) $M$, which
26.2636 +maximizes the sum:
26.2637 +$$\sum_{(i,j)\in M}c_{ij}\eqno(10)$$
26.2638 +(so this variant is also called the {\it maximum weighted bipartite
26.2639 +matching problem} or, if all $c_{ij}=1$, the {\it maximum cardinality
26.2640 +bipartite matching problem}). In the second, classic variant the
26.2641 +problem is to find {\it perfect} matching (assignment) $M$, which
26.2642 +minimizes or maximizes the sum (10).
26.2643 +
26.2644 +An example of the assignment problem, which is the maximum weighted
26.2645 +bipartite matching problem, is shown on Fig. 3.
26.2646 +
26.2647 +The maximum weighted bipartite matching problem can be naturally
26.2648 +formulated as the following LP problem:
26.2649 +
26.2650 +\medskip
26.2651 +
26.2652 +\noindent
26.2653 +\hspace{.5in}maximize
26.2654 +$$z=\sum_{(i,j)\in E}c_{ij}x_{ij}\eqno(11)$$
26.2655 +\hspace{.5in}subject to
26.2656 +$$\sum_{(i,j)\in E}x_{ij}\leq 1\ \ \ \hbox{for all}\ i\in R\eqno(12)$$
26.2657 +$$\sum_{(i,j)\in E}x_{ij}\leq 1\ \ \ \hbox{for all}\ j\in S\eqno(13)$$
26.2658 +$$\ \ \ \ \ \ \ \ 0\leq x_{ij}\leq 1\ \ \ \hbox{for all}\ (i,j)\in E
26.2659 +\eqno(14)$$
26.2660 +
26.2661 +\medskip
26.2662 +
26.2663 +\noindent
26.2664 +where $x_{ij}=1$ means that $(i,j)\in M$, and $x_{ij}=0$ means that
26.2665 +$(i,j)\notin M$.\footnote{The constraint matrix of LP formulation
26.2666 +(11)---(14) is totally unimodular, due to which $x_{ij}\in\{0,1\}$ for
26.2667 +any basic solution.}
26.2668 +
26.2669 +\newpage
26.2670 +
26.2671 +\bigskip
26.2672 +
26.2673 +\noindent\hfil
26.2674 +\xymatrix @C=48pt
26.2675 +{v_1\ar@{-}[rr]|{_{13}}\ar@{-}[rrd]|{_{21}}\ar@{-}[rrddd]|(.2){_{20}}&&
26.2676 +v_9\\
26.2677 +v_2\ar@{-}[rr]|{_{12}}\ar@{-}[rrdd]|(.3){_{8}}
26.2678 +\ar@{-}[rrddd]|(.4){_{26}}&&v_{10}\\
26.2679 +v_3\ar@{-}[rr]|(.2){_{22}}\ar@{-}[rrdd]|(.3){_{11}}&&v_{11}\\
26.2680 +v_4\ar@{-}[rruuu]|(.6){_{12}}\ar@{-}[rr]|(.2){_{36}}
26.2681 +\ar@{-}[rrdd]|(.7){_{25}}&&v_{12}\\
26.2682 +v_5\ar@{-}[rruu]|(.42){_{41}}\ar@{-}[rru]|(.4){_{40}}
26.2683 +\ar@{-}[rr]|(.75){_{11}}\ar@{-}[rrd]|(.6){_{4}}\ar@{-}[rrdd]|{_{8}}
26.2684 +\ar@{-}[rrddd]|{_{35}}\ar@{-}[rrdddd]|{_{32}}&&v_{13}\\
26.2685 +v_6\ar@{-}[rruuuuu]|(.7){_{13}}&&v_{14}\\
26.2686 +v_7\ar@{-}[rruuuuu]|(.15){_{19}}&&v_{15}\\
26.2687 +v_8\ar@{-}[rruuuuuu]|(.25){_{39}}\ar@{-}[rruuuuu]|(.65){_{15}}&&
26.2688 +v_{16}\\
26.2689 +&&v_{17}\\
26.2690 +}
26.2691 +
26.2692 +\bigskip
26.2693 +
26.2694 +\noindent\hfil
26.2695 +Fig.~3. An example of the assignment problem.
26.2696 +
26.2697 +\bigskip
26.2698 +
26.2699 +Similarly, the perfect assignment problem can be naturally formulated
26.2700 +as the following LP problem:
26.2701 +
26.2702 +\medskip
26.2703 +
26.2704 +\noindent
26.2705 +\hspace{.5in}minimize (or maximize)
26.2706 +$$z=\sum_{(i,j)\in E}c_{ij}x_{ij}\eqno(15)$$
26.2707 +\hspace{.5in}subject to
26.2708 +$$\sum_{(i,j)\in E}x_{ij}=1\ \ \ \hbox{for all}\ i\in R\eqno(16)$$
26.2709 +$$\sum_{(i,j)\in E}x_{ij}=1\ \ \ \hbox{for all}\ j\in S\eqno(17)$$
26.2710 +$$\ \ \ \ \ \ \ \ 0\leq x_{ij}\leq 1\ \ \ \hbox{for all}\ (i,j)\in E
26.2711 +\eqno(18)$$
26.2712 +
26.2713 +\medskip
26.2714 +
26.2715 +\noindent
26.2716 +where variables $x_{ij}$ have the same meaning as for (11)---(14)
26.2717 +above.
26.2718 +
26.2719 +\newpage
26.2720 +
26.2721 +In GLPK an undirected bipartite graph $G=(R\cup S,E)$ is represented as
26.2722 +directed graph $\overline{G}=(V,A)$, where $V=R\cup S$ and
26.2723 +$A=\{(i,j):(i,j)\in E\}$, i.e. every edge $(i,j)\in E$ in $G$
26.2724 +corresponds to arc $(i\rightarrow j)\in A$ in $\overline{G}$.
26.2725 +
26.2726 +\subsection{glp\_read\_asnprob---read assignment problem data in\\DIMACS
26.2727 +format}
26.2728 +
26.2729 +\subsubsection*{Synopsis}
26.2730 +
26.2731 +\begin{verbatim}
26.2732 +int glp_read_asnprob(glp_graph *G, int v_set, int a_cost,
26.2733 + const char *fname);
26.2734 +\end{verbatim}
26.2735 +
26.2736 +\subsubsection*{Description}
26.2737 +
26.2738 +The routine \verb|glp_read_asnprob| reads the assignment problem data
26.2739 +from a text file in DIMACS format.
26.2740 +
26.2741 +The parameter \verb|G| specifies the graph object, to which the problem
26.2742 +data have to be stored. Note that before reading data the current
26.2743 +content of the graph object is completely erased with the routine
26.2744 +\verb|glp_erase_graph|.
26.2745 +
26.2746 +The parameter \verb|v_set| specifies an offset of the field of type
26.2747 +\verb|int| in the vertex data block, to which the routine stores the
26.2748 +node set indicator:
26.2749 +
26.2750 +0 --- the node is in set $R$;
26.2751 +
26.2752 +1 --- the node is in set $S$.
26.2753 +
26.2754 +\noindent
26.2755 +If \verb|v_set| $<0$, the node set indicator is not stored.
26.2756 +
26.2757 +The parameter \verb|a_cost| specifies an offset of the field of type
26.2758 +\verb|double| in the arc data block, to which the routine stores the
26.2759 +edge cost $c_{ij}$. If \verb|a_cost| $<0$, the edge cost is not stored.
26.2760 +
26.2761 +The character string \verb|fname| specifies the name of a text file to
26.2762 +be read in. (If the file name name ends with the suffix `\verb|.gz|',
26.2763 +the file is assumed to be compressed, in which case the routine
26.2764 +decompresses it ``on the fly''.)
26.2765 +
26.2766 +\subsubsection*{Returns}
26.2767 +
26.2768 +If the operation was successful, the routine returns zero. Otherwise,
26.2769 +it prints an error message and returns non-zero.
26.2770 +
26.2771 +\newpage
26.2772 +
26.2773 +\subsubsection*{Example}
26.2774 +
26.2775 +\begin{footnotesize}
26.2776 +\begin{verbatim}
26.2777 +typedef struct
26.2778 +{ /* vertex data block */
26.2779 + ...
26.2780 + int set;
26.2781 + ...
26.2782 +} v_data;
26.2783 +
26.2784 +typedef struct
26.2785 +{ /* arc data block */
26.2786 + ...
26.2787 + double cost;
26.2788 + ...
26.2789 +} a_data;
26.2790 +
26.2791 +int main(void)
26.2792 +{ glp_graph *G;
26.2793 + int ret;
26.2794 + G = glp_create_graph(sizeof(v_data), sizeof(a_data));
26.2795 + ret = glp_read_asnprob(G, offsetof(v_data, set),
26.2796 + offsetof(a_data, cost), "sample.asn");
26.2797 + if (ret != 0) goto ...
26.2798 + ...
26.2799 +}
26.2800 +\end{verbatim}
26.2801 +\end{footnotesize}
26.2802 +
26.2803 +\subsubsection*{DIMACS assignment problem format\footnote{This
26.2804 +material is based on the paper ``The First DIMACS International
26.2805 +Algorithm Implementation Challenge: Problem Definitions and
26.2806 +Specifications'', which is publically available at
26.2807 +{\tt http://dimacs.rutgers.edu/Challenges/}.}}
26.2808 +\label{subsecasnprob}
26.2809 +
26.2810 +The DIMACS input file is a plain ASCII text file. It contains
26.2811 +{\it lines} of several types described below. A line is terminated with
26.2812 +an end-of-line character. Fields in each line are separated by at least
26.2813 +one blank space. Each line begins with a one-character designator to
26.2814 +identify the line type.
26.2815 +
26.2816 +Note that DIMACS requires all numerical quantities to be integers in
26.2817 +the range $[-2^{31},\ 2^{31}-1]$ while GLPK allows the quantities to be
26.2818 +floating-point numbers.
26.2819 +
26.2820 +\paragraph{Comment lines.} Comment lines give human-readable information
26.2821 +about the file and are ignored by programs. Comment lines can appear
26.2822 +anywhere in the file. Each comment line begins with a lower-case
26.2823 +character \verb|c|.
26.2824 +
26.2825 +\begin{verbatim}
26.2826 + c This is a comment line
26.2827 +\end{verbatim}
26.2828 +
26.2829 +\newpage
26.2830 +
26.2831 +\paragraph{Problem line.} There is one problem line per data file. The
26.2832 +problem line must appear before any node or arc descriptor lines. It has
26.2833 +the following format:
26.2834 +
26.2835 +\begin{verbatim}
26.2836 + p asn NODES EDGES
26.2837 +\end{verbatim}
26.2838 +
26.2839 +\noindent
26.2840 +The lower-case character \verb|p| signifies that this is a problem line.
26.2841 +The three-character problem designator \verb|asn| identifies the file as
26.2842 +containing specification information for the assignment problem.
26.2843 +The \verb|NODES| field contains an integer value specifying the total
26.2844 +number of nodes in the graph (i.e. in both sets $R$ and $S$). The
26.2845 +\verb|EDGES| field contains an integer value specifying the number of
26.2846 +edges in the graph.
26.2847 +
26.2848 +\paragraph{Node descriptors.} All node descriptor lines must appear
26.2849 +before all edge descriptor lines. The node descriptor lines lists the
26.2850 +nodes in set $R$ only, and all other nodes are assumed to be in set
26.2851 +$S$. There is one node descriptor line for each such node, with the
26.2852 +following format:
26.2853 +
26.2854 +\begin{verbatim}
26.2855 + n ID
26.2856 +\end{verbatim}
26.2857 +
26.2858 +\noindent
26.2859 +The lower-case character \verb|n| signifies that this is a node
26.2860 +descriptor line. The \verb|ID| field gives a node identification number,
26.2861 +an integer between 1 and \verb|NODES|.
26.2862 +
26.2863 +\paragraph{Edge descriptors.} There is one edge descriptor line for
26.2864 +each edge in the graph. Edge descriptor lines are of the following
26.2865 +format:
26.2866 +
26.2867 +\begin{verbatim}
26.2868 + a SRC DST COST
26.2869 +\end{verbatim}
26.2870 +
26.2871 +\noindent
26.2872 +The lower-case character \verb|a| signifies that this is an edge
26.2873 +descriptor line. For each edge $(i,j)$, where $i\in R$ and $j\in S$,
26.2874 +the \verb|SRC| field gives the identification number of vertex $i$, and
26.2875 +the \verb|DST| field gives the identification number of vertex $j$.
26.2876 +Identification numbers are integers between 1 and \verb|NODES|. The
26.2877 +\verb|COST| field contains the cost of edge $(i,j)$.
26.2878 +
26.2879 +\paragraph{Example.} Below here is an example of the data file in
26.2880 +DIMACS format corresponding to the assignment problem shown on Fig~3.
26.2881 +
26.2882 +\newpage
26.2883 +
26.2884 +\begin{footnotesize}
26.2885 +\begin{verbatim}
26.2886 +c sample.asn
26.2887 +c
26.2888 +c This is an example of the assignment problem data
26.2889 +c in DIMACS format.
26.2890 +c
26.2891 +p asn 17 22
26.2892 +c
26.2893 +n 1
26.2894 +n 2
26.2895 +n 3
26.2896 +n 4
26.2897 +n 5
26.2898 +n 6
26.2899 +n 7
26.2900 +n 8
26.2901 +c
26.2902 +a 1 9 13
26.2903 +a 1 10 21
26.2904 +a 1 12 20
26.2905 +a 2 10 12
26.2906 +a 2 12 8
26.2907 +a 2 13 26
26.2908 +a 3 11 22
26.2909 +a 3 13 11
26.2910 +a 4 9 12
26.2911 +a 4 12 36
26.2912 +a 4 14 25
26.2913 +a 5 11 41
26.2914 +a 5 12 40
26.2915 +a 5 13 11
26.2916 +a 5 14 4
26.2917 +a 5 15 8
26.2918 +a 5 16 35
26.2919 +a 5 17 32
26.2920 +a 6 9 13
26.2921 +a 7 10 19
26.2922 +a 8 10 39
26.2923 +a 8 11 15
26.2924 +c
26.2925 +c eof
26.2926 +\end{verbatim}
26.2927 +\end{footnotesize}
26.2928 +
26.2929 +\newpage
26.2930 +
26.2931 +\subsection{glp\_write\_asnprob---write assignment problem data in\\
26.2932 +DIMACS format}
26.2933 +
26.2934 +\subsubsection*{Synopsis}
26.2935 +
26.2936 +\begin{verbatim}
26.2937 +int glp_write_asnprob(glp_graph *G, int v_set, int a_cost,
26.2938 + const char *fname);
26.2939 +\end{verbatim}
26.2940 +
26.2941 +\subsubsection*{Description}
26.2942 +
26.2943 +The routine \verb|glp_write_asnprob| writes the assignment problem data
26.2944 +to a text file in DIMACS format.
26.2945 +
26.2946 +The parameter \verb|G| is the graph program object, which specifies the
26.2947 +assignment problem instance.
26.2948 +
26.2949 +The parameter \verb|v_set| specifies an offset of the field of type
26.2950 +\verb|int| in the vertex data block, which contains the node set
26.2951 +indicator:
26.2952 +
26.2953 +0 --- the node is in set $R$;
26.2954 +
26.2955 +1 --- the node is in set $S$.
26.2956 +
26.2957 +\noindent
26.2958 +If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
26.2959 +is in set $R$, and a node having no outgoing arcs is in set $S$.
26.2960 +
26.2961 +The parameter \verb|a_cost| specifies an offset of the field of type
26.2962 +\verb|double| in the arc data block, which contains $c_{ij}$, the edge
26.2963 +cost. If \verb|a_cost| $<0$, it is assumed that $c_{ij}=1$ for all
26.2964 +edges.
26.2965 +
26.2966 +The character string \verb|fname| specifies a name of the text file to
26.2967 +be written out. (If the file name ends with suffix `\verb|.gz|', the
26.2968 +file is assumed to be compressed, in which case the routine performs
26.2969 +automatic compression on writing it.)
26.2970 +
26.2971 +\subsubsection*{Note}
26.2972 +
26.2973 +The routine \verb|glp_write_asnprob| does not check that the specified
26.2974 +graph object correctly represents a bipartite graph. To make sure that
26.2975 +the problem data are correct, use the routine \verb|glp_check_asnprob|.
26.2976 +
26.2977 +\subsubsection*{Returns}
26.2978 +
26.2979 +If the operation was successful, the routine returns zero. Otherwise,
26.2980 +it prints an error message and returns non-zero.
26.2981 +
26.2982 +\newpage
26.2983 +
26.2984 +\subsection{glp\_check\_asnprob---check correctness of assignment
26.2985 +problem data}
26.2986 +
26.2987 +\subsubsection*{Synopsis}
26.2988 +
26.2989 +\begin{verbatim}
26.2990 +int glp_check_asnprob(glp_graph *G, int v_set);
26.2991 +\end{verbatim}
26.2992 +
26.2993 +\subsubsection*{Description}
26.2994 +
26.2995 +The routine \verb|glp_check_asnprob| checks that the specified graph
26.2996 +object \verb|G| correctly represents a bipartite graph.
26.2997 +
26.2998 +The parameter \verb|v_set| specifies an offset of the field of type
26.2999 +\verb|int| in the vertex data block, which contains the node set
26.3000 +indicator:
26.3001 +
26.3002 +0 --- the node is in set $R$;
26.3003 +
26.3004 +1 --- the node is in set $S$.
26.3005 +
26.3006 +\noindent
26.3007 +If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
26.3008 +is in set $R$, and a node having no outgoing arcs is in set $S$.
26.3009 +
26.3010 +\subsubsection*{Returns}
26.3011 +
26.3012 +The routine \verb|glp_check_asnprob| may return the following codes:
26.3013 +
26.3014 +0 --- the data are correct;
26.3015 +
26.3016 +1 --- the set indicator of some node is 0, however, that node has one
26.3017 +or more incoming arcs;
26.3018 +
26.3019 +2 --- the set indicator of some node is 1, however, that node has one
26.3020 +or more outgoing arcs;
26.3021 +
26.3022 +3 --- the set indicator of some node is invalid (neither 0 nor 1);
26.3023 +
26.3024 +4 --- some node has both incoming and outgoing arcs.
26.3025 +
26.3026 +\subsection{glp\_asnprob\_lp---convert assignment problem to LP}
26.3027 +
26.3028 +\subsubsection*{Synopsis}
26.3029 +
26.3030 +\begin{verbatim}
26.3031 +int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G,
26.3032 + int names, int v_set, int a_cost);
26.3033 +\end{verbatim}
26.3034 +
26.3035 +\subsubsection*{Description}
26.3036 +
26.3037 +The routine \verb|glp_asnprob_lp| builds LP problem, which corresponds
26.3038 +to the specified assignment problem.
26.3039 +
26.3040 +The parameter \verb|lp| is the resultant LP problem object to be built.
26.3041 +Note that on entry its current content is erased with the routine
26.3042 +\verb|glp_erase_prob|.
26.3043 +
26.3044 +The parameter \verb|form| defines which LP formulation should be used:
26.3045 +
26.3046 +\verb|GLP_ASN_MIN| --- perfect matching (15)---(18), minimization;
26.3047 +
26.3048 +\verb|GLP_ASN_MAX| --- perfect matching (15)---(18), maximization;
26.3049 +
26.3050 +\verb|GLP_ASN_MMP| --- maximum weighted matching (11)---(14).
26.3051 +
26.3052 +The parameter \verb|G| is the graph program object, which specifies the
26.3053 +assignment problem instance.
26.3054 +
26.3055 +The parameter \verb|names| is a flag. If it is \verb|GLP_ON|, the
26.3056 +routine uses symbolic names of the graph object components to assign
26.3057 +symbolic names to the LP problem object components. If the \verb|flag|
26.3058 +is \verb|GLP_OFF|, no symbolic names are assigned.
26.3059 +
26.3060 +The parameter \verb|v_set| specifies an offset of the field of type
26.3061 +\verb|int| in the vertex data block, which contains the node set
26.3062 +indicator:
26.3063 +
26.3064 +0 --- the node is in set $R$;
26.3065 +
26.3066 +1 --- the node is in set $S$.
26.3067 +
26.3068 +\noindent
26.3069 +If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
26.3070 +is in set $R$, and a node having no outgoing arcs is in set $S$.
26.3071 +
26.3072 +The parameter \verb|a_cost| specifies an offset of the field of type
26.3073 +\verb|double| in the arc data block, which contains $c_{ij}$, the edge
26.3074 +cost. If \verb|a_cost| $<0$, it is assumed that $c_{ij}=1$ for all
26.3075 +edges.
26.3076 +
26.3077 +\subsubsection*{Returns}
26.3078 +
26.3079 +If the LP problem has been successfully built, the routine
26.3080 +\verb|glp_asnprob_lp| returns zero, otherwise, non-zero (see the
26.3081 +routine \verb|glp_check_asnprob|).
26.3082 +
26.3083 +\subsubsection*{Example}
26.3084 +
26.3085 +The example program below reads the assignment problem instance in
26.3086 +DIMACS format from file `\verb|sample.asn|', converts the instance to
26.3087 +LP (11)---(14), and writes the resultant LP in CPLEX format to file
26.3088 +`\verb|matching.lp|'.
26.3089 +
26.3090 +\begin{footnotesize}
26.3091 +\begin{verbatim}
26.3092 +#include <stddef.h>
26.3093 +#include <glpk.h>
26.3094 +
26.3095 +typedef struct { int set; } v_data;
26.3096 +typedef struct { double cost; } a_data;
26.3097 +
26.3098 +int main(void)
26.3099 +{ glp_graph *G;
26.3100 + glp_prob *P;
26.3101 + G = glp_create_graph(sizeof(v_data), sizeof(a_data));
26.3102 + glp_read_asnprob(G, offsetof(v_data, set),
26.3103 + offsetof(a_data, cost), "sample.asn");
26.3104 + P = glp_create_prob();
26.3105 + glp_asnprob_lp(P, GLP_ASN_MMP, G, GLP_ON,
26.3106 + offsetof(v_data, set), offsetof(a_data, cost));
26.3107 + glp_delete_graph(G);
26.3108 + glp_write_lp(P, NULL, "matching.lp");
26.3109 + glp_delete_prob(P);
26.3110 + return 0;
26.3111 +}
26.3112 +\end{verbatim}
26.3113 +\end{footnotesize}
26.3114 +
26.3115 +If `\verb|sample.asn|' is the example data file from the subsection
26.3116 +describing the routine \verb|glp_read_asnprob|, file
26.3117 +`\verb|matching.lp|' may look like follows:
26.3118 +
26.3119 +\begin{footnotesize}
26.3120 +\begin{verbatim}
26.3121 +Maximize
26.3122 + obj: + 20 x(1,12) + 21 x(1,10) + 13 x(1,9) + 26 x(2,13) + 8 x(2,12)
26.3123 + + 12 x(2,10) + 11 x(3,13) + 22 x(3,11) + 25 x(4,14) + 36 x(4,12)
26.3124 + + 12 x(4,9) + 32 x(5,17) + 35 x(5,16) + 8 x(5,15) + 4 x(5,14)
26.3125 + + 11 x(5,13) + 40 x(5,12) + 41 x(5,11) + 13 x(6,9) + 19 x(7,10)
26.3126 + + 15 x(8,11) + 39 x(8,10)
26.3127 +
26.3128 +Subject To
26.3129 + r_1: + x(1,9) + x(1,10) + x(1,12) <= 1
26.3130 + r_2: + x(2,10) + x(2,12) + x(2,13) <= 1
26.3131 + r_3: + x(3,11) + x(3,13) <= 1
26.3132 + r_4: + x(4,9) + x(4,12) + x(4,14) <= 1
26.3133 + r_5: + x(5,11) + x(5,12) + x(5,13) + x(5,14) + x(5,15) + x(5,16)
26.3134 + + x(5,17) <= 1
26.3135 + r_6: + x(6,9) <= 1
26.3136 + r_7: + x(7,10) <= 1
26.3137 + r_8: + x(8,10) + x(8,11) <= 1
26.3138 + r_9: + x(6,9) + x(4,9) + x(1,9) <= 1
26.3139 + r_10: + x(8,10) + x(7,10) + x(2,10) + x(1,10) <= 1
26.3140 + r_11: + x(8,11) + x(5,11) + x(3,11) <= 1
26.3141 + r_12: + x(5,12) + x(4,12) + x(2,12) + x(1,12) <= 1
26.3142 + r_13: + x(5,13) + x(3,13) + x(2,13) <= 1
26.3143 + r_14: + x(5,14) + x(4,14) <= 1
26.3144 + r_15: + x(5,15) <= 1
26.3145 + r_16: + x(5,16) <= 1
26.3146 + r_17: + x(5,17) <= 1
26.3147 +
26.3148 +Bounds
26.3149 + 0 <= x(1,12) <= 1
26.3150 + 0 <= x(1,10) <= 1
26.3151 + 0 <= x(1,9) <= 1
26.3152 + 0 <= x(2,13) <= 1
26.3153 + 0 <= x(2,12) <= 1
26.3154 + 0 <= x(2,10) <= 1
26.3155 + 0 <= x(3,13) <= 1
26.3156 + 0 <= x(3,11) <= 1
26.3157 + 0 <= x(4,14) <= 1
26.3158 + 0 <= x(4,12) <= 1
26.3159 + 0 <= x(4,9) <= 1
26.3160 + 0 <= x(5,17) <= 1
26.3161 + 0 <= x(5,16) <= 1
26.3162 + 0 <= x(5,15) <= 1
26.3163 + 0 <= x(5,14) <= 1
26.3164 + 0 <= x(5,13) <= 1
26.3165 + 0 <= x(5,12) <= 1
26.3166 + 0 <= x(5,11) <= 1
26.3167 + 0 <= x(6,9) <= 1
26.3168 + 0 <= x(7,10) <= 1
26.3169 + 0 <= x(8,11) <= 1
26.3170 + 0 <= x(8,10) <= 1
26.3171 +
26.3172 +End
26.3173 +\end{verbatim}
26.3174 +\end{footnotesize}
26.3175 +
26.3176 +\subsection{glp\_asnprob\_okalg---solve assignment problem with
26.3177 +out-of-kilter algorithm}
26.3178 +
26.3179 +\subsubsection*{Synopsis}
26.3180 +
26.3181 +\begin{verbatim}
26.3182 +int glp_asnprob_okalg(int form, glp_graph *G, int v_set,
26.3183 + int a_cost, double *sol, int a_x);
26.3184 +\end{verbatim}
26.3185 +
26.3186 +\subsubsection*{Description}
26.3187 +
26.3188 +The routine \verb|glp_mincost_okalg| finds optimal solution to the
26.3189 +assignment problem with the out-of-kilter
26.3190 +algorithm.\footnote{GLPK implementation of the out-of-kilter algorithm
26.3191 +is based on the following book: L.~R.~Ford,~Jr., and D.~R.~Fulkerson,
26.3192 +``Flows in Networks,'' The RAND Corp., Report R-375-PR (August 1962),
26.3193 +Chap. III ``Minimal Cost Flow Problems,'' pp.~113-26.} Note that this
26.3194 +routine requires all the problem data to be integer-valued.
26.3195 +
26.3196 +The parameter \verb|form| defines which LP formulation should be used:
26.3197 +
26.3198 +\verb|GLP_ASN_MIN| --- perfect matching (15)---(18), minimization;
26.3199 +
26.3200 +\verb|GLP_ASN_MAX| --- perfect matching (15)---(18), maximization;
26.3201 +
26.3202 +\verb|GLP_ASN_MMP| --- maximum weighted matching (11)---(14).
26.3203 +
26.3204 +The parameter \verb|G| is the graph program object, which specifies the
26.3205 +assignment problem instance.
26.3206 +
26.3207 +The parameter \verb|v_set| specifies an offset of the field of type
26.3208 +\verb|int| in the vertex data block, which contains the node set
26.3209 +indicator:
26.3210 +
26.3211 +0 --- the node is in set $R$;
26.3212 +
26.3213 +1 --- the node is in set $S$.
26.3214 +
26.3215 +\newpage
26.3216 +
26.3217 +\noindent
26.3218 +If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
26.3219 +is in set $R$, and a node having no outgoing arcs is in set $S$.
26.3220 +
26.3221 +The parameter \verb|a_cost| specifies an offset of the field of type
26.3222 +\verb|double| in the arc data block, which contains $c_{ij}$, the edge
26.3223 +cost. This value must be integer in the range [\verb|-INT_MAX|,
26.3224 +\verb|+INT_MAX|]. If \verb|a_cost| $<0$, it is assumed that $c_{ij}=1$
26.3225 +for all edges.
26.3226 +
26.3227 +The parameter \verb|sol| specifies a location, to which the routine
26.3228 +stores the objective value (that is, the total cost) found.
26.3229 +If \verb|sol| is \verb|NULL|, the objective value is not stored.
26.3230 +
26.3231 +The parameter \verb|a_x| specifies an offset of the field of type
26.3232 +\verb|int| in the arc data block, to which the routine stores $x_{ij}$.
26.3233 +If \verb|a_x| $<0$, this value is not stored.
26.3234 +
26.3235 +\subsubsection*{Returns}
26.3236 +
26.3237 +\def\arraystretch{1}
26.3238 +
26.3239 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
26.3240 +0 & Optimal solution found.\\
26.3241 +\verb|GLP_ENOPFS| & No (primal) feasible solution exists.\\
26.3242 +\verb|GLP_EDATA| & Unable to start the search, because the assignment
26.3243 +problem data are either incorrect (this error is detected by the
26.3244 +routine \verb|glp_check_asnprob|), not integer-valued or out of range.\\
26.3245 +\verb|GLP_ERANGE| & The search was prematurely terminated because of
26.3246 +integer overflow.\\
26.3247 +\verb|GLP_EFAIL| & An error has been detected in the program logic.
26.3248 +(If this code is returned for your problem instance, please report to
26.3249 +\verb|<bug-glpk@gnu.org>|.)\\
26.3250 +\end{tabular}
26.3251 +
26.3252 +\subsubsection*{Comments}
26.3253 +
26.3254 +Since the out-of-kilter algorithm is designed to find a minimal cost
26.3255 +circulation, the routine \verb|glp_asnprob_okalg| converts the original
26.3256 +graph to a network suitable for this algorithm in the following
26.3257 +way:\footnote{The conversion is performed internally and does not change
26.3258 +the original graph program object passed to the routine.}
26.3259 +
26.3260 +1) it replaces each edge $(i,j)$ by arc $(i\rightarrow j)$,
26.3261 +flow $x_{ij}$ through which has zero lower bound ($l_{ij}=0$), unity
26.3262 +upper bound ($u_{ij}=1$), and per-unit cost $+c_{ij}$ (in case of
26.3263 +\verb|GLP_ASN_MIN|), or $-c_{ij}$ (in case of \verb|GLP_ASN_MAX| and
26.3264 +\verb|GLP_ASN_MMP|);
26.3265 +
26.3266 +2) then it adds one auxiliary feedback node $k$;
26.3267 +
26.3268 +\newpage
26.3269 +
26.3270 +3) for each original node $i\in R$ the routine adds auxiliary supply
26.3271 +arc $(k\rightarrow i)$, flow $x_{ki}$ through which is costless
26.3272 +($c_{ki}=0$) and either fixed at 1 ($l_{ki}=u_{ki}=1$, in case of
26.3273 +\verb|GLP_ASN_MIN| and \verb|GLP_ASN_MAX|) or has zero lower bound and
26.3274 +unity upper bound ($l_{ij}=0$, $u_{ij}=1$, in case of
26.3275 +\verb|GLP_ASN_MMP|);
26.3276 +
26.3277 +4) similarly, for each original node $j\in S$ the routine adds
26.3278 +auxiliary demand arc $(j\rightarrow k)$, flow $x_{jk}$ through which is
26.3279 +costless ($c_{jk}=0$) and either fixed at 1 ($l_{jk}=u_{jk}=1$, in case
26.3280 +of \verb|GLP_ASN_MIN| and \verb|GLP_ASN_MAX|) or has zero lower bound
26.3281 +and unity upper bound ($l_{jk}=0$, $u_{jk}=1$, in case of
26.3282 +\verb|GLP_ASN_MMP|).
26.3283 +
26.3284 +\subsubsection*{Example}
26.3285 +
26.3286 +The example program shown below reads the assignment problem instance
26.3287 +in DIMACS format from file `\verb|sample.asn|', solves it by using the
26.3288 +routine \verb|glp_asnprob_okalg|, and writes the solution found to the
26.3289 +standard output.
26.3290 +
26.3291 +\begin{footnotesize}
26.3292 +\begin{verbatim}
26.3293 +#include <stddef.h>
26.3294 +#include <stdio.h>
26.3295 +#include <stdlib.h>
26.3296 +#include <glpk.h>
26.3297 +
26.3298 +typedef struct { int set; } v_data;
26.3299 +typedef struct { double cost; int x; } e_data;
26.3300 +
26.3301 +#define node(v) ((v_data *)((v)->data))
26.3302 +#define edge(e) ((e_data *)((e)->data))
26.3303 +
26.3304 +int main(void)
26.3305 +{ glp_graph *G;
26.3306 + glp_vertex *v;
26.3307 + glp_arc *e;
26.3308 + int i, ret;
26.3309 + double sol;
26.3310 + G = glp_create_graph(sizeof(v_data), sizeof(e_data));
26.3311 + glp_read_asnprob(G, offsetof(v_data, set),
26.3312 + offsetof(e_data, cost), "sample.asn");
26.3313 + ret = glp_asnprob_okalg(GLP_ASN_MMP, G,
26.3314 + offsetof(v_data, set), offsetof(e_data, cost), &sol,
26.3315 + offsetof(e_data, x));
26.3316 + printf("ret = %d; sol = %5g\n", ret, sol);
26.3317 + for (i = 1; i <= G->nv; i++)
26.3318 + { v = G->v[i];
26.3319 + for (e = v->out; e != NULL; e = e->t_next)
26.3320 + printf("edge %2d %2d: x = %d; c = %g\n",
26.3321 + e->tail->i, e->head->i, edge(e)->x, edge(e)->cost);
26.3322 + }
26.3323 + glp_delete_graph(G);
26.3324 + return 0;
26.3325 +}
26.3326 +\end{verbatim}
26.3327 +\end{footnotesize}
26.3328 +
26.3329 +If `\verb|sample.asn|' is the example data file from the subsection
26.3330 +describing the routine \verb|glp_read_asnprob|, the output may look
26.3331 +like follows:
26.3332 +
26.3333 +\begin{footnotesize}
26.3334 +\begin{verbatim}
26.3335 +Reading assignment problem data from `sample.asn'...
26.3336 +Assignment problem has 8 + 9 = 17 nodes and 22 arcs
26.3337 +38 lines were read
26.3338 +ret = 0; sol = 180
26.3339 +edge 1 12: x = 1; c = 20
26.3340 +edge 1 10: x = 0; c = 21
26.3341 +edge 1 9: x = 0; c = 13
26.3342 +edge 2 13: x = 1; c = 26
26.3343 +edge 2 12: x = 0; c = 8
26.3344 +edge 2 10: x = 0; c = 12
26.3345 +edge 3 13: x = 0; c = 11
26.3346 +edge 3 11: x = 1; c = 22
26.3347 +edge 4 14: x = 1; c = 25
26.3348 +edge 4 12: x = 0; c = 36
26.3349 +edge 4 9: x = 0; c = 12
26.3350 +edge 5 17: x = 0; c = 32
26.3351 +edge 5 16: x = 1; c = 35
26.3352 +edge 5 15: x = 0; c = 8
26.3353 +edge 5 14: x = 0; c = 4
26.3354 +edge 5 13: x = 0; c = 11
26.3355 +edge 5 12: x = 0; c = 40
26.3356 +edge 5 11: x = 0; c = 41
26.3357 +edge 6 9: x = 1; c = 13
26.3358 +edge 7 10: x = 0; c = 19
26.3359 +edge 8 11: x = 0; c = 15
26.3360 +edge 8 10: x = 1; c = 39
26.3361 +\end{verbatim}
26.3362 +\end{footnotesize}
26.3363 +
26.3364 +\newpage
26.3365 +
26.3366 +\subsection{glp\_asnprob\_hall---find bipartite matching of maximum
26.3367 +cardinality}
26.3368 +
26.3369 +\subsubsection*{Synopsis}
26.3370 +
26.3371 +\begin{verbatim}
26.3372 +int glp_asnprob_hall(glp_graph *G, int v_set, int a_x);
26.3373 +\end{verbatim}
26.3374 +
26.3375 +\subsubsection*{Description}
26.3376 +
26.3377 +The routine \verb|glp_asnprob_hall| finds a matching of maximal
26.3378 +cardinality in the specified bipartite graph. It uses a version of the
26.3379 +Fortran routine \verb|MC21A| developed by
26.3380 +I.~S.~Duff\footnote{I.~S.~Duff, Algorithm 575: Permutations for
26.3381 +zero-free diagonal, ACM Trans. on Math. Softw. 7 (1981), pp.~387-390.},
26.3382 +which implements Hall's algorithm.\footnote{M.~Hall, ``An Algorithm for
26.3383 +Distinct Representatives,'' Am. Math. Monthly 63 (1956), pp.~716-717.}
26.3384 +
26.3385 +The parameter \verb|G| is a pointer to the graph program object.
26.3386 +
26.3387 +The parameter \verb|v_set| specifies an offset of the field of type
26.3388 +\verb|int| in the vertex data block, which contains the node set
26.3389 +indicator:
26.3390 +
26.3391 +0 --- the node is in set $R$;
26.3392 +
26.3393 +1 --- the node is in set $S$.
26.3394 +
26.3395 +\noindent
26.3396 +If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
26.3397 +is in set $R$, and a node having no outgoing arcs is in set $S$.
26.3398 +
26.3399 +The parameter \verb|a_x| specifies an offset of the field of type
26.3400 +\verb|int| in the arc data block, to which the routine stores $x_{ij}$.
26.3401 +If \verb|a_x| $<0$, this value is not stored.
26.3402 +
26.3403 +\subsubsection*{Returns}
26.3404 +
26.3405 +The routine \verb|glp_asnprob_hall| returns the cardinality of the
26.3406 +matching found. However, if the specified graph is incorrect (as
26.3407 +detected by the routine \verb|glp_check_asnprob|), this routine returns
26.3408 +a negative value.
26.3409 +
26.3410 +\subsubsection*{Comments}
26.3411 +
26.3412 +The same solution may be obtained with the routine
26.3413 +\verb|glp_asnprob_okalg| (for LP formulation \verb|GLP_ASN_MMP| and
26.3414 +all edge costs equal to 1). However, the routine \verb|glp_asnprob_hall|
26.3415 +is much faster.
26.3416 +
26.3417 +\newpage
26.3418 +
26.3419 +\subsubsection*{Example}
26.3420 +
26.3421 +The example program shown below reads the assignment problem instance
26.3422 +in DIMACS format from file `\verb|sample.asn|', finds a bipartite
26.3423 +matching of maximal cardinality by using the routine
26.3424 +\verb|glp_asnprob_hall|, and writes the solution found to the standard
26.3425 +output.
26.3426 +
26.3427 +\begin{footnotesize}
26.3428 +\begin{verbatim}
26.3429 +#include <stddef.h>
26.3430 +#include <stdio.h>
26.3431 +#include <stdlib.h>
26.3432 +#include <glpk.h>
26.3433 +
26.3434 +typedef struct { int set; } v_data;
26.3435 +typedef struct { int x; } e_data;
26.3436 +
26.3437 +#define node(v) ((v_data *)((v)->data))
26.3438 +#define edge(e) ((e_data *)((e)->data))
26.3439 +
26.3440 +int main(void)
26.3441 +{ glp_graph *G;
26.3442 + glp_vertex *v;
26.3443 + glp_arc *e;
26.3444 + int i, card;
26.3445 + G = glp_create_graph(sizeof(v_data), sizeof(e_data));
26.3446 + glp_read_asnprob(G, offsetof(v_data, set), -1,
26.3447 + "sample.asn");
26.3448 + card = glp_asnprob_hall(G, offsetof(v_data, set),
26.3449 + offsetof(e_data, x));
26.3450 + printf("card = %d\n", card);
26.3451 + for (i = 1; i <= G->nv; i++)
26.3452 + { v = G->v[i];
26.3453 + for (e = v->out; e != NULL; e = e->t_next)
26.3454 + printf("edge %2d %2d: x = %d\n",
26.3455 + e->tail->i, e->head->i, edge(e)->x);
26.3456 + }
26.3457 + glp_delete_graph(G);
26.3458 + return 0;
26.3459 +}
26.3460 +\end{verbatim}
26.3461 +\end{footnotesize}
26.3462 +
26.3463 +If `\verb|sample.asn|' is the example data file from the subsection
26.3464 +describing the routine \verb|glp_read_asnprob|, the output may look
26.3465 +like follows:
26.3466 +
26.3467 +\begin{footnotesize}
26.3468 +\begin{verbatim}
26.3469 +Reading assignment problem data from `sample.asn'...
26.3470 +Assignment problem has 8 + 9 = 17 nodes and 22 arcs
26.3471 +38 lines were read
26.3472 +card = 7
26.3473 +edge 1 12: x = 1
26.3474 +edge 1 10: x = 0
26.3475 +edge 1 9: x = 0
26.3476 +edge 2 13: x = 1
26.3477 +edge 2 12: x = 0
26.3478 +edge 2 10: x = 0
26.3479 +edge 3 13: x = 0
26.3480 +edge 3 11: x = 1
26.3481 +edge 4 14: x = 1
26.3482 +edge 4 12: x = 0
26.3483 +edge 4 9: x = 0
26.3484 +edge 5 17: x = 1
26.3485 +edge 5 16: x = 0
26.3486 +edge 5 15: x = 0
26.3487 +edge 5 14: x = 0
26.3488 +edge 5 13: x = 0
26.3489 +edge 5 12: x = 0
26.3490 +edge 5 11: x = 0
26.3491 +edge 6 9: x = 1
26.3492 +edge 7 10: x = 1
26.3493 +edge 8 11: x = 0
26.3494 +edge 8 10: x = 0
26.3495 +\end{verbatim}
26.3496 +\end{footnotesize}
26.3497 +
26.3498 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
26.3499 +
26.3500 +\newpage
26.3501 +
26.3502 +\section{Critical path problem}
26.3503 +
26.3504 +\subsection{Background}
26.3505 +
26.3506 +The {\it critical path problem} (CPP) is stated as follows. Let there
26.3507 +be given a project $J$, which a set of jobs (tasks, activities, etc.).
26.3508 +Performing each job $i\in J$ requires time $t_i\geq 0$. Besides, over
26.3509 +the set $J$ there is given a precedence relation $R\subseteq J\times J$,
26.3510 +where $(i,j)\in R$ means that job $i$ immediately precedes job $j$, i.e.
26.3511 +performing job $j$ cannot start until job $i$ has been completely
26.3512 +performed. The problem is to find starting times $x_i$ for each job
26.3513 +$i\in J$, which satisfy to the precedence relation and minimize the
26.3514 +total duration (makespan) of the project.
26.3515 +
26.3516 +The following is an example of the critical path problem:
26.3517 +
26.3518 +\begin{center}
26.3519 +\begin{tabular}{|c|l|c|c|}
26.3520 +\hline
26.3521 +Job&Desription&Time&Predecessors\\
26.3522 +\hline
26.3523 +A&Excavate&3&---\\
26.3524 +B&Lay foundation&4&A\\
26.3525 +C&Rough plumbing&3&B\\
26.3526 +D&Frame&10&B\\
26.3527 +E&Finish exterior&8&D\\
26.3528 +F&Install HVAC&4&D\\
26.3529 +G&Rough electric&6&D\\
26.3530 +H&Sheet rock&8&C, E, F, G\\
26.3531 +I&Install cabinets&5&H\\
26.3532 +J&Paint&5&H\\
26.3533 +K&Final plumbing&4&I\\
26.3534 +L&Final electric&2&J\\
26.3535 +M&Install flooring&4&K, L\\
26.3536 +\hline
26.3537 +\end{tabular}
26.3538 +\end{center}
26.3539 +
26.3540 +Obviously, the project along with the precedence relation can be
26.3541 +represented as a directed graph $G=(J,R)$ called {\it project network},
26.3542 +where each node $i\in J$ corresponds to a job, and arc
26.3543 +$(i\rightarrow j)\in R$ means that job $i$ immediately precedes job
26.3544 +$j$.\footnote{There exists another network representation of the
26.3545 +critical path problem, where jobs correspond to arcs while nodes
26.3546 +correspond to events introduced to express the precedence relation.
26.3547 +That representation, however, is much less convenient than the one,
26.3548 +where jobs are represented as nodes of the network.} The project network
26.3549 +for the example above is shown on Fig.~4.
26.3550 +
26.3551 +May note that the project network must be acyclic; otherwise, it would
26.3552 +be impossible to satisfy to the precedence relation for any job that
26.3553 +belongs to a cycle.
26.3554 +
26.3555 +\newpage
26.3556 +
26.3557 +\xymatrix
26.3558 +{&&&C|3\ar[rd]&&I|5\ar[r]&K|4\ar[rd]&\\
26.3559 +A|3\ar[r]&B|4\ar[rru]\ar[rd]&&E|8\ar[r]&H|8\ar[ru]\ar[rd]&&&M|4\\
26.3560 +&&D|10\ar[ru]\ar[r]\ar[rd]&F|4\ar[ru]&&J|5\ar[r]&L|2\ar[ru]&\\
26.3561 +&&&G|6\ar[ruu]&&&&\\
26.3562 +}
26.3563 +
26.3564 +\bigskip
26.3565 +
26.3566 +\noindent\hfil
26.3567 +Fig.~4. An example of the project network.
26.3568 +
26.3569 +\bigskip
26.3570 +
26.3571 +The critical path problem can be naturally formulated as the following
26.3572 +LP problem:
26.3573 +
26.3574 +\medskip
26.3575 +
26.3576 +\noindent
26.3577 +\hspace{.5in}minimize
26.3578 +$$z\eqno(19)$$
26.3579 +\hspace{.5in}subject to
26.3580 +$$x_i+t_i\leq z\ \ \ \hbox{for all}\ i\in J\ \ \ \ \eqno(20)$$
26.3581 +$$x_i+t_i\leq x_j\ \ \ \hbox{for all}\ (i,j)\in R\eqno(21)$$
26.3582 +$$x_i\geq 0\ \ \ \ \ \ \ \hbox{for all}\ i\in J\ \ \eqno(22)$$
26.3583 +
26.3584 +The inequality constraints (21), which are active in the optimal
26.3585 +solution, define so called {\it critical path} having the following
26.3586 +property: the minimal project duration $z$ can be decreased only by
26.3587 +decreasing the times $t_j$ for jobs on the critical path, and delaying
26.3588 +any critical job delays the entire project.
26.3589 +
26.3590 +\subsection{glp\_cpp---solve critical path problem}
26.3591 +
26.3592 +\subsubsection{Synopsis}
26.3593 +
26.3594 +\begin{verbatim}
26.3595 +double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls);
26.3596 +\end{verbatim}
26.3597 +
26.3598 +\subsubsection{Description}
26.3599 +
26.3600 +The routine \verb|glp_cpp| solves the critical path problem represented
26.3601 +in the form of the project network.
26.3602 +
26.3603 +The parameter \verb|G| is a pointer to the graph object, which
26.3604 +specifies the project network. This graph must be acyclic. Multiple
26.3605 +arcs are allowed being considered as single arcs.
26.3606 +
26.3607 +The parameter \verb|v_t| specifies an offset of the field of type
26.3608 +\verb|double| in the vertex data block, which contains time $t_i\geq 0$
26.3609 +needed to perform corresponding job $j\in J$. If \verb|v_t| $<0$, it is
26.3610 +assumed that $t_i=1$ for all jobs.
26.3611 +
26.3612 +The parameter \verb|v_es| specifies an offset of the field of type
26.3613 +\verb|double| in the vertex data block, to which the routine stores
26.3614 +the {\it earliest start time} for corresponding job. If \verb|v_es|
26.3615 +$<0$, this time is not stored.
26.3616 +
26.3617 +The parameter \verb|v_ls| specifies an offset of the field of type
26.3618 +\verb|double| in the vertex data block, to which the routine stores
26.3619 +the {\it latest start time} for corresponding job. If \verb|v_ls|
26.3620 +$<0$, this time is not stored.
26.3621 +
26.3622 +The difference between the latest and earliest start times of some job
26.3623 +is called its {\it time reserve}. Delaying a job within its time reserve
26.3624 +does not affect the project duration, so if the time reserve is zero,
26.3625 +the corresponding job is critical.
26.3626 +
26.3627 +\subsubsection{Returns}
26.3628 +
26.3629 +The routine \verb|glp_cpp| returns the minimal project duration, i.e.
26.3630 +minimal time needed to perform all jobs in the project.
26.3631 +
26.3632 +\subsubsection{Example}
26.3633 +
26.3634 +The example program below solves the critical path problem shown on
26.3635 +Fig.~4 by using the routine \verb|glp_cpp| and writes the solution found
26.3636 +to the standard output.
26.3637 +
26.3638 +\begin{footnotesize}
26.3639 +\begin{verbatim}
26.3640 +#include <stddef.h>
26.3641 +#include <stdio.h>
26.3642 +#include <stdlib.h>
26.3643 +#include <glpk.h>
26.3644 +
26.3645 +typedef struct { double t, es, ls; } v_data;
26.3646 +
26.3647 +#define node(v) ((v_data *)((v)->data))
26.3648 +
26.3649 +int main(void)
26.3650 +{ glp_graph *G;
26.3651 + int i;
26.3652 + double t, es, ef, ls, lf, total;
26.3653 + G = glp_create_graph(sizeof(v_data), 0);
26.3654 + glp_add_vertices(G, 13);
26.3655 + node(G->v[1])->t = 3; /* A: Excavate */
26.3656 + node(G->v[2])->t = 4; /* B: Lay foundation */
26.3657 + node(G->v[3])->t = 3; /* C: Rough plumbing */
26.3658 + node(G->v[4])->t = 10; /* D: Frame */
26.3659 + node(G->v[5])->t = 8; /* E: Finish exterior */
26.3660 + node(G->v[6])->t = 4; /* F: Install HVAC */
26.3661 + node(G->v[7])->t = 6; /* G: Rough elecrtic */
26.3662 + node(G->v[8])->t = 8; /* H: Sheet rock */
26.3663 + node(G->v[9])->t = 5; /* I: Install cabinets */
26.3664 + node(G->v[10])->t = 5; /* J: Paint */
26.3665 + node(G->v[11])->t = 4; /* K: Final plumbing */
26.3666 + node(G->v[12])->t = 2; /* L: Final electric */
26.3667 + node(G->v[13])->t = 4; /* M: Install flooring */
26.3668 + glp_add_arc(G, 1, 2); /* A precedes B */
26.3669 + glp_add_arc(G, 2, 3); /* B precedes C */
26.3670 + glp_add_arc(G, 2, 4); /* B precedes D */
26.3671 + glp_add_arc(G, 4, 5); /* D precedes E */
26.3672 + glp_add_arc(G, 4, 6); /* D precedes F */
26.3673 + glp_add_arc(G, 4, 7); /* D precedes G */
26.3674 + glp_add_arc(G, 3, 8); /* C precedes H */
26.3675 + glp_add_arc(G, 5, 8); /* E precedes H */
26.3676 + glp_add_arc(G, 6, 8); /* F precedes H */
26.3677 + glp_add_arc(G, 7, 8); /* G precedes H */
26.3678 + glp_add_arc(G, 8, 9); /* H precedes I */
26.3679 + glp_add_arc(G, 8, 10); /* H precedes J */
26.3680 + glp_add_arc(G, 9, 11); /* I precedes K */
26.3681 + glp_add_arc(G, 10, 12); /* J precedes L */
26.3682 + glp_add_arc(G, 11, 13); /* K precedes M */
26.3683 + glp_add_arc(G, 12, 13); /* L precedes M */
26.3684 + total = glp_cpp(G, offsetof(v_data, t), offsetof(v_data, es),
26.3685 + offsetof(v_data, ls));
26.3686 + printf("Minimal project duration is %.2f\n\n", total);
26.3687 + printf("Job Time ES EF LS LF\n");
26.3688 + printf("--- ------ ------ ------ ------ ------\n");
26.3689 + for (i = 1; i <= G->nv; i++)
26.3690 + { t = node(G->v[i])->t;
26.3691 + es = node(G->v[i])->es;
26.3692 + ef = es + node(G->v[i])->t;
26.3693 + ls = node(G->v[i])->ls;
26.3694 + lf = ls + node(G->v[i])->t;
26.3695 + printf("%3d %6.2f %s %6.2f %6.2f %6.2f %6.2f\n",
26.3696 + i, t, ls - es < 0.001 ? "*" : " ", es, ef, ls, lf);
26.3697 + }
26.3698 + glp_delete_graph(G);
26.3699 + return 0;
26.3700 +}
26.3701 +\end{verbatim}
26.3702 +\end{footnotesize}
26.3703 +
26.3704 +The output from the example program shown below includes job number,
26.3705 +the time needed to perform a job, earliest start time (\verb|ES|),
26.3706 +earliest finish time (\verb|EF|), latest start time (\verb|LS|), and
26.3707 +latest finish time (\verb|LF|) for each job in the project. Critical
26.3708 +jobs are marked by asterisks.
26.3709 +
26.3710 +\newpage
26.3711 +
26.3712 +\begin{footnotesize}
26.3713 +\begin{verbatim}
26.3714 +Minimal project duration is 46.00
26.3715 +
26.3716 +Job Time ES EF LS LF
26.3717 +--- ------ ------ ------ ------ ------
26.3718 + 1 3.00 * 0.00 3.00 0.00 3.00
26.3719 + 2 4.00 * 3.00 7.00 3.00 7.00
26.3720 + 3 3.00 7.00 10.00 22.00 25.00
26.3721 + 4 10.00 * 7.00 17.00 7.00 17.00
26.3722 + 5 8.00 * 17.00 25.00 17.00 25.00
26.3723 + 6 4.00 17.00 21.00 21.00 25.00
26.3724 + 7 6.00 17.00 23.00 19.00 25.00
26.3725 + 8 8.00 * 25.00 33.00 25.00 33.00
26.3726 + 9 5.00 * 33.00 38.00 33.00 38.00
26.3727 + 10 5.00 33.00 38.00 35.00 40.00
26.3728 + 11 4.00 * 38.00 42.00 38.00 42.00
26.3729 + 12 2.00 38.00 40.00 40.00 42.00
26.3730 + 13 4.00 * 42.00 46.00 42.00 46.00
26.3731 +\end{verbatim}
26.3732 +\end{footnotesize}
26.3733 +
26.3734 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
26.3735 +
26.3736 +\chapter{Graph Optimization API Routines}
26.3737 +
26.3738 +\section{Maximum clique problem}
26.3739 +
26.3740 +\subsection{Background}
26.3741 +
26.3742 +The {\it maximum clique problem (MCP)} is a classic combinatorial
26.3743 +optimization problem. Given an undirected graph $G=(V,E)$, where $V$ is
26.3744 +a set of vertices, and $E$ is a set of edges, this problem is to find
26.3745 +the largest {\it clique} $C\subseteq G$, i.e. the largest induced
26.3746 +complete subgraph. A generalization of this problem is the {\it maximum
26.3747 +weight clique problem (MWCP)}, which is to find a clique $C\subseteq G$
26.3748 +of the largest weight $\displaystyle\sum_{v\in C}w(v)\rightarrow\max$,
26.3749 +where $w(v)$ is a weight of vertex $v\in V$.
26.3750 +
26.3751 +An example of the maximum weight clique problem is shown on Fig.~5.
26.3752 +
26.3753 +\begin{figure}
26.3754 +\noindent\hfil
26.3755 +\begin{tabular}{c}
26.3756 +{\xymatrix %@C=16pt
26.3757 +{&&&{v_1}\ar@{-}[lllddd]\ar@{-}[llddddd]\ar@{-}[dddddd]
26.3758 +\ar@{-}[rrrddd]&&&\\
26.3759 +&{v_2}\ar@{-}[rrrr]\ar@{-}[rrrrdddd]\ar@{-}[rrddddd]\ar@{-}[dddd]&&&&
26.3760 +{v_3}\ar@{-}[llllldd]\ar@{-}[lllldddd]\ar@{-}[dddd]&\\
26.3761 +&&&&&&\\
26.3762 +{v_4}\ar@{-}[rrrrrr]\ar@{-}[rrrddd]&&&&&&{v_5}\ar@{-}[lllddd]
26.3763 +\ar@{-}[ldd]\\
26.3764 +&&&&&&\\
26.3765 +&{v_6}\ar@{-}[rrrr]&&&&{v_7}&\\
26.3766 +&&&{v_8}&&&\\
26.3767 +}}
26.3768 +\end{tabular}
26.3769 +\begin{tabular}{r@{\ }c@{\ }l}
26.3770 +$w(v_1)$&=&3\\$w(v_2)$&=&4\\$w(v_3)$&=&8\\$w(v_4)$&=&1\\
26.3771 +$w(v_5)$&=&5\\$w(v_6)$&=&2\\$w(v_7)$&=&1\\$w(v_8)$&=&3\\
26.3772 +\end{tabular}
26.3773 +
26.3774 +\begin{center}
26.3775 +Fig.~5. An example of the maximum weight clique problem.
26.3776 +\end{center}
26.3777 +\end{figure}
26.3778 +
26.3779 +\subsection{glp\_wclique\_exact---find maximum weight clique with exact
26.3780 +algorithm}
26.3781 +
26.3782 +\subsubsection*{Synopsis}
26.3783 +
26.3784 +\begin{verbatim}
26.3785 +int glp_wclique_exact(glp_graph *G, int v_wgt, double *sol,
26.3786 + int v_set);
26.3787 +\end{verbatim}
26.3788 +
26.3789 +\subsection*{Description}
26.3790 +
26.3791 +The routine {\it glp\_wclique\_exact} finds a maximum weight clique in
26.3792 +the specified undirected graph with the exact algorithm developed by
26.3793 +Patric \"Osterg{\aa}rd.\footnote{P.~R.~J.~\"Osterg{\aa}rd, A new
26.3794 +algorithm for the maximum-weight clique problem, Nordic J. of Computing,
26.3795 +Vol.~8, No.~4, 2001, pp.~424--36.}
26.3796 +
26.3797 +The parameter $G$ is the program object, which specifies an undirected
26.3798 +graph. Each arc $(x\rightarrow y)$ in $G$ is considered as edge
26.3799 +$(x,y)$, self-loops are ignored, and multiple edges, if present, are
26.3800 +replaced (internally) by simple edges.
26.3801 +
26.3802 +The parameter {\it v\_wgt} specifies an offset of the field of type
26.3803 +{\bf double} in the vertex data block, which contains a weight of
26.3804 +corresponding vertex. Vertex weights must be integer-valued in the
26.3805 +range $[0,$ {\it INT\_MAX}$]$. If {\it v\_wgt} $<0$, it is assumed that
26.3806 +all vertices of the graph have the weight 1.
26.3807 +
26.3808 +The parameter {\it sol} specifies a location, to which the routine
26.3809 +stores the weight of the clique found (the clique weight is the sum
26.3810 +of weights of all vertices included in the clique.) If {\it sol} is
26.3811 +{\it NULL}, the solution is not stored.
26.3812 +
26.3813 +The parameter {\it v\_set} specifies an offset of the field of type
26.3814 +{\bf int} in the vertex data block, to which the routines stores a
26.3815 +vertex flag: 1 means that the corresponding vertex is included in the
26.3816 +clique found, and 0 otherwise. If {\it v\_set} $<0$, vertex flags are
26.3817 +not stored.
26.3818 +
26.3819 +\subsubsection*{Returns}
26.3820 +
26.3821 +\def\arraystretch{1}
26.3822 +
26.3823 +\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
26.3824 +0 & Optimal solution found.\\
26.3825 +\verb|GLP_EDATA| & Unable to start the search, because some vertex
26.3826 +weights are either not integer-valued or out of range. This code is
26.3827 +also returned if the sum of weights of all vertices exceeds
26.3828 +{\it INT\_MAX}. \\
26.3829 +\end{tabular}
26.3830 +
26.3831 +\subsubsection*{Notes}
26.3832 +
26.3833 +\noindent\indent
26.3834 +1. The routine {\it glp\_wclique\_exact} finds exact solution. Since
26.3835 +both MCP and MWCP problems are NP-complete, the algorithm may require
26.3836 +exponential time in worst cases.
26.3837 +
26.3838 +2. Internally the specified graph is converted to an adjacency matrix
26.3839 +in {\it dense} format. This requires about $|V|^2/16$ bytes of memory,
26.3840 +where $|V|$ is the number of vertices in the graph.
26.3841 +
26.3842 +\subsubsection*{Example}
26.3843 +
26.3844 +The example program shown below reads a MWCP instance in DIMACS
26.3845 +clique/coloring format from file `\verb|sample.clq|', finds the clique
26.3846 +of largest weight, and writes the solution found to the standard output.
26.3847 +
26.3848 +\begin{footnotesize}
26.3849 +\begin{verbatim}
26.3850 +#include <stddef.h>
26.3851 +#include <stdio.h>
26.3852 +#include <stdlib.h>
26.3853 +#include <glpk.h>
26.3854 +
26.3855 +typedef struct { double wgt; int set; } v_data;
26.3856 +
26.3857 +#define vertex(v) ((v_data *)((v)->data))
26.3858 +
26.3859 +int main(void)
26.3860 +{ glp_graph *G;
26.3861 + glp_vertex *v;
26.3862 + int i, ret;
26.3863 + double sol;
26.3864 + G = glp_create_graph(sizeof(v_data), 0);
26.3865 + glp_read_ccdata(G, offsetof(v_data, wgt), "sample.clq");
26.3866 + ret = glp_wclique_exact(G, offsetof(v_data, wgt), &sol,
26.3867 + offsetof(v_data, set));
26.3868 + printf("ret = %d; sol = %g\n", ret, sol);
26.3869 + for (i = 1; i <= G->nv; i++)
26.3870 + { v = G->v[i];
26.3871 + printf("vertex %d: weight = %g, flag = %d\n",
26.3872 + i, vertex(v)->wgt, vertex(v)->set);
26.3873 + }
26.3874 + glp_delete_graph(G);
26.3875 + return 0;
26.3876 +}
26.3877 +\end{verbatim}
26.3878 +\end{footnotesize}
26.3879 +
26.3880 +\noindent
26.3881 +For the example shown on Fig.~5 the data file may look like follows:
26.3882 +
26.3883 +\begin{footnotesize}
26.3884 +\begin{verbatim}
26.3885 +c sample.clq
26.3886 +c
26.3887 +c This is an example of the maximum weight clique
26.3888 +c problem in DIMACS clique/coloring format.
26.3889 +c
26.3890 +p edge 8 16
26.3891 +n 1 3
26.3892 +n 2 4
26.3893 +n 3 8
26.3894 +n 5 5
26.3895 +n 6 2
26.3896 +n 8 3
26.3897 +e 1 4
26.3898 +e 1 5
26.3899 +e 1 6
26.3900 +e 1 8
26.3901 +e 2 3
26.3902 +e 2 6
26.3903 +e 2 7
26.3904 +e 2 8
26.3905 +e 3 4
26.3906 +e 3 6
26.3907 +e 3 7
26.3908 +e 4 5
26.3909 +e 4 8
26.3910 +e 5 7
26.3911 +e 5 8
26.3912 +e 6 7
26.3913 +c
26.3914 +c eof
26.3915 +\end{verbatim}
26.3916 +\end{footnotesize}
26.3917 +
26.3918 +\noindent
26.3919 +The corresponding output from the example program is the following:
26.3920 +
26.3921 +\begin{footnotesize}
26.3922 +\begin{verbatim}
26.3923 +Reading graph from `sample.clq'...
26.3924 +Graph has 8 vertices and 16 edges
26.3925 +28 lines were read
26.3926 +ret = 0; sol = 15
26.3927 +vertex 1: weight = 3, flag = 0
26.3928 +vertex 2: weight = 4, flag = 1
26.3929 +vertex 3: weight = 8, flag = 1
26.3930 +vertex 4: weight = 1, flag = 0
26.3931 +vertex 5: weight = 5, flag = 0
26.3932 +vertex 6: weight = 2, flag = 1
26.3933 +vertex 7: weight = 1, flag = 1
26.3934 +vertex 8: weight = 3, flag = 0
26.3935 +\end{verbatim}
26.3936 +\end{footnotesize}
26.3937 +
26.3938 +\end{document}
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
27.2 +++ b/doc/miplib2.txt Mon Dec 06 13:09:21 2010 +0100
27.3 @@ -0,0 +1,135 @@
27.4 +Solver: GLPSOL 4.40 (options used: --pcost)
27.5 +Computer: Intel Pentium 4, 3.0 GHz
27.6 +Platform: Cygwin 1.5.25
27.7 +Compiler: GCC 3.4.4 (options used: -O3)
27.8 +Test set: MIPLIB 2.0 <http://miplib.zib.de/miplib3/miplib/>
27.9 +
27.10 +Problem Optimal Solution Cuts Used Nodes Iters Time,s Mem,MB
27.11 +-------- ---------------- --------- -------- ------ ------ ------
27.12 +air01 +6.796000000e+03 3 41 < 1 1.2
27.13 +air02 +7.810000000e+03 43 201 6 13.8
27.14 +air03 +3.401600000e+05 33 414 12 21.0
27.15 +air04 +5.613700000e+04 1901 109800 396 32.4
27.16 +air05 +2.637400000e+04 6445 201649 452 45.0
27.17 +air06 +4.964900000e+04 11 6868 31 18.1
27.18 +bell3a +8.784303160e+05 --gomory 7965 42363 17 6.1
27.19 +bell3b +1.178616062e+07 --gomory 6031 30467 19 3.2
27.20 +bell4 +1.854148420e+07 --gomory 7203 25019 16 2.9
27.21 +bell5 +8.966406492e+06 --gomory 5605 18555 8 1.5
27.22 +bm23 +3.400000000e+01 373 878 < 1 0.2
27.23 +cracpb1 +2.219900000e+04 47 5258 2 1.3
27.24 +dcmulti +1.881820000e+05 743 3366 2 1.1
27.25 +diamond infeasible 3 4 < 1 0.1
27.26 +dsbmip -3.051981750e+02 --mir 217 46088 24 4.5
27.27 +egout +5.681007000e+02 91 137 < 1 0.3
27.28 +enigma +0.000000000e+00 16419 55071 6 3.2
27.29 +fixnet3 +5.197300000e+04 81 380 < 1 1.4
27.30 +fixnet4 +8.936000000e+03 211 1095 1 1.4
27.31 +fixnet6 +3.983000000e+03 1031 3136 2 1.7
27.32 +flugpl +1.201500000e+06 397 231 < 1 0.1
27.33 +gen +1.123133627e+05 195 3991 1 1.7
27.34 +khb05250 +1.069402260e+08 2163 14498 5 2.8
27.35 +l152lav +4.722000000e+03 7419 95299 68 12.0
27.36 +lp4l +2.967000000e+03 173 1331 2 1.7
27.37 +lseu +1.120000000e+03 10821 31954 5 2.5
27.38 +misc01 +5.635000000e+02 769 4593 1 0.5
27.39 +misc02 +1.690000000e+03 29 282 < 1 0.2
27.40 +misc03 +3.360000000e+03 957 6742 2 1.1
27.41 +misc04 +2.666699247e+03 17 2052 1 7.0
27.42 +misc05 +2.984500000e+03 293 2520 1 1.1
27.43 +misc06 +1.285086074e+04 57 941 < 1 2.7
27.44 +misc07 +2.810000000e+03 --mir 66075 579129 424 33.4
27.45 +mod008 +3.070000000e+02 8185 24245 8 2.3
27.46 +mod010 +6.548000000e+03 315 6283 7 5.3
27.47 +mod011
27.48 +mod013 +2.809500000e+02 545 1155 < 1 0.3
27.49 +modglob +2.074050809e+07 --mir 5197 31985 20 2.8
27.50 +noswot
27.51 +p0033 +3.089000000e+03 305 955 < 1 0.2
27.52 +p0040 +6.202700000e+04 17 66 < 1 0.1
27.53 +p0201 +7.615000000e+03 521 3660 1 0.9
27.54 +p0282 +2.584110000e+05 623 1204 1 0.8
27.55 +p0291 +5.223749000e+03 71 154 < 1 0.7
27.56 +p0548 +8.691000000e+03 7617 23556 9 2.9
27.57 +p2756 +3.124000000e+03 --mir 3911 15157 57 10.9
27.58 +p6000 -2.451377000e+06 19209 40906 570 15.8
27.59 +pipex +7.882630000e+02 1569 2469 < 1 0.4
27.60 +qiu -1.328731369e+02 80473 1918742 1174 69.2
27.61 +rentacar +3.035676098e+07 43 1649 3 12.1
27.62 +rgn +8.219999924e+01 3325 18700 2 1.2
27.63 +sample2 +3.750000000e+02 163 347 < 1 0.2
27.64 +sentoy -7.772000000e+03 335 723 < 1 0.4
27.65 +set1al +1.586975000e+04 --mir 17 532 < 1 1.5
27.66 +set1ch
27.67 +set1cl +6.484250000e+03 --mir 1 502 < 1 1.1
27.68 +stein15 +9.000000000e+00 87 375 < 1 0.2
27.69 +stein27 +1.800000000e+01 3255 15327 2 1.0
27.70 +stein45 +3.000000000e+01 52301 389140 139 19.2
27.71 +stein9 +5.000000000e+00 17 45 < 1 0.1
27.72 +vpm1 +2.000000000e+01 --mir 9 836 < 1 0.9
27.73 +
27.74 +PROBLEM CHARACTERISTICS
27.75 +
27.76 +Problem Rows Cols ( Int 0/1) Nonz Best Solution
27.77 +-------- ------ ---------------------- ------ --------------------------
27.78 +air01 24 771 ( all all) 4986 6796 (opt)
27.79 +air02 51 6774 ( all all) 68329 7810 (opt)
27.80 +air03 125 10757 ( all all) 101785 340160 (opt)
27.81 +air04 824 8904 ( all all) 81869 56138 (opt)
27.82 +air05 427 7195 ( all all) 59316 26402 (not opt)
27.83 +air06 826 8627 ( all all) 79433 49649 (opt)
27.84 +bell3a 124 133 ( 71 39) 441 878430.32 (opt)
27.85 +bell3b 124 133 ( 71 39) 441 11786160.62 (opt)
27.86 +bell4 106 117 ( 64 34) 385 18541484.20 (opt)
27.87 +bell5 92 104 ( 58 30) 340 8966406.49 (opt)
27.88 +bm23 21 27 ( all all) 505 34 (opt)
27.89 +cracpb1 144 572 ( all all) 4730 22199 (opt)
27.90 +dcmulti 291 548 ( 75 all) 1833 188182.0000 (opt)
27.91 +diamond 5 2 ( all all) 9 integer infeasible
27.92 +dsbmip 1855 1886 ( 192 160) 9768 -305.198 (opt)
27.93 +egout 99 141 ( 55 all) 392 568.101 (opt)
27.94 +enigma 22 100 ( all all) 298 0.0 (opt)
27.95 +fixnet3 479 878 ( 378 all) 2631 51973 (opt)
27.96 +fixnet4 479 878 ( 378 all) 2621 8936 (opt)
27.97 +fixnet6 479 878 ( 378 all) 2550 3983 (opt)
27.98 +flugpl 19 18 ( 11 none) 64 1201500 (opt)
27.99 +gen 781 870 ( 150 144) 3174 112313 (opt)
27.100 +khb05250 102 1350 ( 24 all) 3973 106940226 (opt)
27.101 +l152lav 98 1989 ( all all) 11911 4750 (not opt)
27.102 +lp4l 86 1086 ( all all) 5763 2967 (opt)
27.103 +lseu 29 89 ( all all) 394 1120 (opt)
27.104 +misc01 55 83 ( 82 all) 746 563.5 (opt)
27.105 +misc02 40 59 ( 58 all) 414 1690 (opt)
27.106 +misc03 97 160 ( 159 all) 2054 3360 (opt)
27.107 +misc04 1726 4897 ( 30 all) 17253 2666.699 (opt)
27.108 +misc05 301 136 ( 74 all) 2946 2984.5 (opt)
27.109 +misc06 821 1808 ( 112 all) 5860 12850.8607 (opt)
27.110 +misc07 213 260 ( 259 all) 8620 2810 (not opt)
27.111 +mod008 7 319 ( all all) 1562 307 (opt)
27.112 +mod010 147 2655 ( all all) 13858 6548 (opt)
27.113 +mod011 4482 10958 ( 96 all) 37425 -54558535 (opt)
27.114 +mod013 63 96 ( 48 all) 288 280.95 (opt)
27.115 +modglob 292 422 ( 98 all) 1390 20740508 (opt)
27.116 +noswot 183 128 ( 100 75) 760 -43 (opt)
27.117 +p0033 17 33 ( all all) 131 3089 (opt)
27.118 +p0040 24 40 ( all all) 150 62027 (opt)
27.119 +p0201 134 201 ( all all) 2124 7615 (opt)
27.120 +p0282 242 282 ( all all) 2248 258411 (opt)
27.121 +p0291 253 291 ( all all) 349 5223.7490 (opt)
27.122 +p0548 177 548 ( all all) 2127 8691 (opt)
27.123 +p2756 756 2756 ( all all) 11103 3124 (opt)
27.124 +p6000 2177 6000 ( all all) 54238 -2451377 (opt)
27.125 +pipex 26 48 ( all all) 240 788.263 (opt)
27.126 +qiu 1193 840 ( 48 all) 3432 -132.873137 (opt)
27.127 +rentacar 6804 9557 ( 55 all) 42019 30356761 (opt)
27.128 +rgn 25 180 ( 100 all) 540 82.1999 (opt)
27.129 +sample2 46 67 ( 21 all) 179 375 (opt)
27.130 +sentoy 31 60 ( all all) 1860 -7772 (opt)
27.131 +set1al 493 712 ( 240 all) 1884 15869.7 (opt)
27.132 +set1ch 493 712 ( 240 all) 1884 54537.7 (opt)
27.133 +set1cl 493 712 ( 240 all) 1884 6484.25 (opt)
27.134 +stein15 37 15 ( all all) 135 9 (opt)
27.135 +stein27 119 27 ( all all) 405 18 (opt)
27.136 +stein45 332 45 ( all all) 1079 30 (opt)
27.137 +stein9 14 9 ( all all) 54 5 (opt)
27.138 +vpm1 235 378 ( 168 all) 917 20 (opt)
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
28.2 +++ b/doc/miplib3.txt Mon Dec 06 13:09:21 2010 +0100
28.3 @@ -0,0 +1,143 @@
28.4 +Solver: GLPSOL 4.40
28.5 +Computer: Intel Pentium 4, 3.0 GHz
28.6 +Platform: Cygwin 1.5.25
28.7 +Compiler: GCC 3.4.4 (options used: -O3)
28.8 +Test set: MIPLIB 3.0 <http://miplib.zib.de/miplib3/miplib.html>
28.9 +
28.10 +Problem Optimal Solution Options Used Nodes Iters Time,s Mem,MB
28.11 +-------- ---------------- ---------------- -------- ------ ------ ------
28.12 +10teams +9.240000000e+02 --pcost --gomory 6013 349276 207 12.7
28.13 +air03 +3.401600000e+05 --pcost 33 414 12 21.0
28.14 +air04 +5.613700000e+04 --pcost 1901 109800 396 32.4
28.15 +air05 +2.637400000e+04 --pcost 6445 201649 452 45.0
28.16 +arki001
28.17 +bell3a +8.784303160e+05 --pcost --gomory 7965 42363 17 6.1
28.18 +bell5 +8.966406492e+06 --pcost --gomory 5605 18555 8 1.5
28.19 +blend2 +7.598985000e+00 --pcost 7185 24256 7 2.1
28.20 +cap6000 -2.451377000e+06 --pcost 19209 40906 569 15.8
28.21 +dano3mip
28.22 +danoint
28.23 +dcmulti +1.881820000e+05 --pcost 743 3366 2 1.1
28.24 +dsbmip -3.051981750e+02 --pcost --mir 217 46088 24 4.5
28.25 +egout +5.681007000e+02 --pcost 91 137 < 1 0.3
28.26 +enigma +0.000000000e+00 --pcost 16419 55071 6 3.2
28.27 +fast0507
28.28 +fiber +4.059351800e+05 --pcost --mir 407 3108 4 2.4
28.29 +fixnet6 +3.983000000e+03 --pcost 1031 3136 2 1.7
28.30 +flugpl +1.201500000e+06 --pcost 397 231 < 1 0.1
28.31 +gen +1.123133627e+05 --pcost 195 3991 1 1.7
28.32 +gesa2 +2.577985637e+07 --pcost --mir 59 2723 4 4.1
28.33 +gesa2_o +2.577985637e+07 --pcost --mir 69 2588 5 3.7
28.34 +gesa3 +2.799104265e+07 --pcost --mir 93 2774 5 3.7
28.35 +gesa3_o +2.799104265e+07 --pcost --mir 117 3271 6 3.6
28.36 +gt2 +2.116600000e+04 --pcost 5613 26115 2 1.2
28.37 +harp2
28.38 +khb05250 +1.069402260e+08 --pcost 2163 14498 5 2.8
28.39 +l152lav +4.722000000e+03 --pcost 7419 95299 68 12.0
28.40 +lseu +1.120000000e+03 --pcost 10821 31954 5 2.5
28.41 +marksh1
28.42 +marksh2
28.43 +mas74
28.44 +mas76
28.45 +misc03 +3.360000000e+03 --pcost 957 6742 2 1.1
28.46 +misc06 +1.285086074e+04 --pcost 57 941 < 1 2.7
28.47 +misc07 +2.810000000e+03 --pcost --mir 66075 579129 424 33.4
28.48 +mitre
28.49 +mkc
28.50 +mod008 +3.070000000e+02 --pcost 8185 24245 8 2.3
28.51 +mod010 +6.548000000e+03 --pcost 315 6283 7 5.3
28.52 +mod011
28.53 +modglob +2.074050809e+07 --pcost --mir 5197 31985 20 2.8
28.54 +noswot
28.55 +nw04 +1.686200000e+04 (none) 361 5544 345 138.3
28.56 +p0033 +3.089000000e+03 --pcost 305 955 < 1 0.2
28.57 +p0201 +7.615000000e+03 --pcost 521 3660 1 0.9
28.58 +p0282 +2.584110000e+05 --pcost 623 1204 1 0.8
28.59 +p0548 +8.691000000e+03 --pcost 7617 23556 9 2.9
28.60 +p2756 +3.124000000e+03 --pcost --mir 3911 15157 57 10.9
28.61 +pk1
28.62 +pp08a +7.350000000e+03 --pcost --mir 663 9196 4 1.3
28.63 +pp08acut +7.350000000e+03 --pcost --mir 17233 260160 154 21.1
28.64 +qiu -1.328731369e+02 --pcost 80473 1918742 1174 69.2
28.65 +qnet1 +1.602969268e+04 --pcost --mir 183 20352 16 3.6
28.66 +qnet1_o +1.602969268e+04 --pcost --mir 75 7645 9 3.3
28.67 +rentacar +3.035676098e+07 --pcost 43 1649 3 12.1
28.68 +rgn +8.219999924e+01 --pcost 3325 18700 2 1.2
28.69 +rout
28.70 +set1ch
28.71 +seymour
28.72 +stein27 +1.800000000e+01 --pcost 3255 15327 2 1.0
28.73 +stein45 +3.000000000e+01 --pcost 52301 389140 139 19.2
28.74 +swath
28.75 +vpm1 +2.000000000e+01 --pcost --mir 9 836 < 1 0.9
28.76 +vpm2 +1.375000000e+01 --pcost --mir 11729 164856 91 9.2
28.77 +
28.78 +PROBLEM CHARACTERISTICS
28.79 +
28.80 +Problem Rows Cols ( Int 0/1) Nonz Best Solution
28.81 +-------- ------ ---------------------- ------ --------------------------
28.82 +10teams 230 2025 ( 1800 all) 12150 924 (opt)
28.83 +air03 125 10757 ( all all) 101785 340160 (opt)
28.84 +air04 824 8904 ( all all) 81869 56138 (opt)
28.85 +air05 427 7195 ( all all) 59316 26402 (not opt)
28.86 +arki001 1048 1388 ( 538 415) 20439 7580813.0459 (not opt)
28.87 +bell3a 124 133 ( 71 39) 441 878430.32 (opt)
28.88 +bell5 92 104 ( 58 30) 340 8966406.49 (opt)
28.89 +blend2 274 353 ( 264 231) 1409 7.598985 (opt)
28.90 +cap6000 2176 6000 ( all all) 48249 -2451377 (opt)
28.91 +dano3mip 3202 13873 ( 552 all) 79655 728.1111 (not opt)
28.92 +danoint 664 521 ( 56 all) 3232 65.67 (opt)
28.93 +dcmulti 291 548 ( 75 all) 1833 188182.0000 (opt)
28.94 +dsbmip 1855 1886 ( 192 160) 9768 -305.198 (opt)
28.95 +egout 99 141 ( 55 all) 392 568.101 (opt)
28.96 +enigma 22 100 ( all all) 298 0.0 (opt)
28.97 +fast0507 507 63009 ( all all) 409439 174 (opt)
28.98 +fiber 363 1298 ( 1254 all) 2944 405935.18000 (opt)
28.99 +fixnet6 479 878 ( 378 all) 2550 3983 (opt)
28.100 +flugpl 19 18 ( 11 none) 64 1201500 (opt)
28.101 +gen 781 870 ( 150 144) 3174 112313 (opt)
28.102 +gesa2 1392 1224 ( 408 240) 5064 25779856.372 (opt)
28.103 +gesa2_o 1248 1224 ( 720 384) 3672 25779856.372 (opt)
28.104 +gesa3 1368 1152 ( 384 216) 4944 27991042.648 (opt)
28.105 +gesa3_o 1224 1152 ( 672 336) 3624 27991042.648 (opt)
28.106 +gt2 29 188 ( all 24) 376 21166.000 (opt)
28.107 +harp2 112 2993 ( all all) 5840 -73899798.00 (opt)
28.108 +khb05250 102 1350 ( 24 all) 3973 106940226 (opt)
28.109 +l152lav 98 1989 ( all all) 11911 4750 (not opt)
28.110 +lseu 29 89 ( all all) 394 1120 (opt)
28.111 +marksh1 7 62 ( 50 all) 324
28.112 +marksh2 8 74 ( 60 all) 448
28.113 +mas74 13 151 ( 150 all) 1705 11801.1857 (opt)
28.114 +mas76 12 151 ( 150 all) 1639 40005.0541 (opt)
28.115 +misc03 97 160 ( 159 all) 2054 3360 (opt)
28.116 +misc06 821 1808 ( 112 all) 5860 12850.8607 (opt)
28.117 +misc07 213 260 ( 259 all) 8620 2810 (not opt)
28.118 +mitre 2054 10724 ( all all) 39704 115155 (opt)
28.119 +mkc 3412 5325 ( 5323 all) 20621
28.120 +mod008 7 319 ( all all) 1562 307 (opt)
28.121 +mod010 147 2655 ( all all) 13858 6548 (opt)
28.122 +mod011 4482 10958 ( 96 all) 37425 -54558535 (opt)
28.123 +modglob 292 422 ( 98 all) 1390 20740508 (opt)
28.124 +noswot 183 128 ( 100 75) 760 -43 (opt)
28.125 +nw04 36 87482 ( all all) 636666 16862 (opt)
28.126 +p0033 17 33 ( all all) 131 3089 (opt)
28.127 +p0201 134 201 ( all all) 2124 7615 (opt)
28.128 +p0282 242 282 ( all all) 2248 258411 (opt)
28.129 +p0548 177 548 ( all all) 2127 8691 (opt)
28.130 +p2756 756 2756 ( all all) 11103 3124 (opt)
28.131 +pk1 45 86 ( 55 all) 915 11 (opt)
28.132 +pp08a 136 240 ( 64 all) 480 7350 (opt)
28.133 +pp08acut 246 240 ( 64 all) 839 7350 (opt)
28.134 +qiu 1193 840 ( 48 all) 3432 -132.873137 (opt)
28.135 +qnet1 503 1541 ( 1417 1288) 4622 16029.692681 (opt)
28.136 +qnet1_o 456 1541 ( 1417 1288) 4214 16029.692681 (opt)
28.137 +rentacar 6804 9557 ( 55 all) 42019 30356761 (opt)
28.138 +rgn 25 180 ( 100 all) 540 82.1999 (opt)
28.139 +rout 291 556 ( 315 300) 2431 1077.56 (opt)
28.140 +set1ch 493 712 ( 240 all) 1884 54537.7 (opt)
28.141 +seymour 4944 1372 ( all all) 33549 423 (not opt)
28.142 +stein27 119 27 ( all all) 405 18 (opt)
28.143 +stein45 332 45 ( all all) 1079 30 (opt)
28.144 +swath 885 6805 ( 6724 all) 34966
28.145 +vpm1 235 378 ( 168 all) 917 20 (opt)
28.146 +vpm2 234 378 ( 168 all) 917 13.75 (opt)
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
29.2 +++ b/doc/netlib.txt Mon Dec 06 13:09:21 2010 +0100
29.3 @@ -0,0 +1,103 @@
29.4 +Solver: GLPSOL 4.40 (default options used)
29.5 +Computer: Intel Pentium 4, 3.0 GHz
29.6 +Platform: Cygwin 1.5.25
29.7 +Compiler: GCC 3.4.4 (options used: -O3)
29.8 +Test set: Netlib LP collection <ftp://ftp.netlib.org/lp/data/>
29.9 +
29.10 +Problem Rows Cols Nonz Optimum Iters Time,s Mem,MB
29.11 +-------- ----- ----- ------ ---------------- ------ ------ ------
29.12 +25fv47 822 1571 11127 +5.501845888e+03 1651 < 1 2.1
29.13 +80bau3b 2263 9799 29063 +9.872241924e+05 5358 3 6.4
29.14 +adlittle 57 97 465 +2.254949632e+05 71 < 1 0.1
29.15 +afiro 28 32 88 -4.647531429e+02 10 < 1 0.1
29.16 +agg 489 163 2541 -3.599176729e+07 100 < 1 0.5
29.17 +agg2 517 302 4515 -2.023925236e+07 178 < 1 0.8
29.18 +agg3 517 302 4531 +1.031211594e+07 182 < 1 0.8
29.19 +bandm 306 472 2659 -1.586280185e+02 252 < 1 0.6
29.20 +beaconfd 174 262 3476 +3.359248581e+04 61 < 1 0.4
29.21 +blend 75 83 521 -3.081214985e+01 41 < 1 0.1
29.22 +bnl1 644 1175 6129 +1.977629562e+03 581 < 1 1.4
29.23 +bnl2 2325 3489 16124 +1.811236540e+03 1730 1 3.7
29.24 +boeing1 351 384 3865 -3.352135675e+02 419 < 1 0.7
29.25 +boeing2 167 143 1339 -3.150187280e+02 161 < 1 0.3
29.26 +bore3d 234 315 1525 +1.373080394e+03 38 < 1 0.3
29.27 +brandy 221 249 2150 +1.518509896e+03 191 < 1 0.5
29.28 +capri 272 353 1786 +2.690012914e+03 203 < 1 0.4
29.29 +cycle 1904 2857 21322 -5.226393025e+00 953 < 1 3.5
29.30 +czprob 930 3523 14173 +2.185196699e+06 754 < 1 2.6
29.31 +d2q06c 2172 5167 35674 +1.227842108e+05 5368 7 6.2
29.32 +d6cube 416 6184 43888 +3.154916667e+02 6596 6 6.0
29.33 +degen2 445 534 4449 -1.435178000e+03 506 < 1 1.0
29.34 +degen3 1504 1818 26230 -9.872940000e+02 2205 2 4.1
29.35 +dfl001 6072 12230 41873 +1.126639605e+07 39863 117 11.0
29.36 +e226 224 282 2767 -2.586492907e+01 206 < 1 0.5
29.37 +etamacro 401 688 2489 -7.557152333e+02 444 < 1 0.7
29.38 +fffff800 525 854 6235 +5.556795648e+05 167 < 1 1.0
29.39 +finnis 498 614 2714 +1.727910656e+05 338 < 1 0.6
29.40 +fit1d 25 1026 14430 -9.146378092e+03 488 < 1 1.7
29.41 +fit1p 628 1677 10894 +9.146378092e+03 1379 < 1 1.9
29.42 +fit2d 26 10500 138018 -6.846429329e+04 5751 16 15.8
29.43 +fit2p 3001 13525 60784 +6.846429329e+04 11960 17 11.3
29.44 +forplan 162 421 4916 -6.642189613e+02 170 < 1 0.7
29.45 +ganges 1310 1681 7021 -1.095857361e+05 724 < 1 1.9
29.46 +gfrd-pnc 617 1092 3467 +6.902236000e+06 416 < 1 1.0
29.47 +greenbea 2393 5405 31499 -7.255524813e+07 3012 3 5.8
29.48 +greenbeb 2393 5405 31499 -4.302260261e+06 2153 2 5.8
29.49 +grow15 301 645 5665 -1.068709413e+08 358 < 1 1.1
29.50 +grow22 441 946 8318 -1.608343365e+08 606 < 1 1.6
29.51 +grow7 141 301 2633 -4.778781181e+07 159 < 1 0.5
29.52 +israel 175 142 2358 -8.966448219e+05 123 < 1 0.4
29.53 +kb2 44 41 291 -1.749900130e+03 38 < 1 0.1
29.54 +lotfi 154 308 1086 -2.526470606e+01 104 < 1 0.3
29.55 +maros 847 1443 10006 -5.806374370e+04 703 < 1 1.8
29.56 +maros-r7 3137 9408 151120 +1.497185166e+06 2340 5 16.7
29.57 +modszk1 688 1620 4158 +3.206197291e+02 705 < 1 1.4
29.58 +nesm 663 2923 13988 +1.407603649e+07 2240 1 2.4
29.59 +perold 626 1376 6026 -9.380755278e+03 1103 < 1 1.5
29.60 +pilot 1442 3652 43220 -5.574831533e+02 5726 11 7.8
29.61 +pilot-ja 941 1988 14706 -6.113136466e+03 1697 1 2.5
29.62 +pilot-we 723 2789 9218 -2.720107533e+06 1382 1 2.3
29.63 +pilot4 411 1000 5145 -2.581139259e+03 532 < 1 1.3
29.64 +pilot87 2031 4883 73804 +3.017103744e+02 7573 28 12.2
29.65 +pilotnov 976 2172 13129 -4.497276188e+03 988 1 2.5
29.66 +recipe 92 180 752 -2.666160000e+02 17 < 1 0.2
29.67 +sc105 106 103 281 -5.220206121e+01 51 < 1 0.2
29.68 +sc205 206 203 552 -5.220206121e+01 124 < 1 0.3
29.69 +sc50a 51 48 131 -6.457507706e+01 25 < 1 0.1
29.70 +sc50b 51 48 119 -7.000000000e+01 30 < 1 0.1
29.71 +scagr25 472 500 2029 -1.475343306e+07 352 < 1 0.7
29.72 +scagr7 130 140 553 -2.331389824e+06 94 < 1 0.2
29.73 +scfxm1 331 457 2612 +1.841675903e+04 281 < 1 0.6
29.74 +scfxm2 661 914 5229 +3.666026156e+04 587 < 1 1.1
29.75 +scfxm3 991 1371 7846 +5.490125455e+04 881 < 1 1.7
29.76 +scorpion 389 358 1708 +1.878124823e+03 146 < 1 0.4
29.77 +scrs8 491 1169 4029 +9.042969538e+02 545 < 1 1.1
29.78 +scsd1 78 760 3148 +8.666666674e+00 91 < 1 0.6
29.79 +scsd6 148 1350 5666 +5.050000008e+01 182 < 1 1.0
29.80 +scsd8 398 2750 11334 +9.049999999e+02 397 < 1 2.1
29.81 +sctap1 301 480 2052 +1.412250000e+03 196 < 1 0.5
29.82 +sctap2 1091 1880 8124 +1.724807143e+03 425 < 1 1.7
29.83 +sctap3 1481 2480 10734 +1.424000000e+03 729 < 1 2.4
29.84 +seba 516 1028 4874 +1.571160000e+04 883 < 1 1.0
29.85 +share1b 118 225 1182 -7.658931858e+04 167 < 1 0.3
29.86 +share2b 97 79 730 -4.157322407e+02 87 < 1 0.2
29.87 +shell 537 1775 4900 +1.208825346e+09 467 < 1 1.2
29.88 +ship04l 403 2118 8450 +1.793324538e+06 373 < 1 1.5
29.89 +ship04s 403 1458 5810 +1.798714700e+06 262 < 1 1.0
29.90 +ship08l 779 4283 17085 +1.909055211e+06 516 < 1 2.9
29.91 +ship08s 779 2387 9501 +1.920098211e+06 274 < 1 1.7
29.92 +ship12l 1152 5427 21597 +1.470187919e+06 686 < 1 3.7
29.93 +ship12s 1152 2763 10941 +1.489236134e+06 383 < 1 2.0
29.94 +sierra 1228 2036 9252 +1.539436218e+07 857 < 1 2.1
29.95 +stair 357 467 3857 -2.512669512e+02 399 < 1 1.0
29.96 +standata 360 1075 3038 +1.257699500e+03 140 < 1 0.7
29.97 +standgub 362 1184 3147 +1.257699500e+03 140 < 1 0.8
29.98 +standmps 468 1075 3686 +1.406017500e+03 299 < 1 0.9
29.99 +stocfor1 118 111 474 -4.113197622e+04 24 < 1 0.2
29.100 +stocfor2 2158 2031 9492 -3.902440854e+04 499 < 1 2.6
29.101 +stocfor3 16676 15695 74004 -3.997678394e+04 4456 11 19.7
29.102 +truss 1001 8806 36642 +4.588158472e+05 4744 4 6.5
29.103 +tuff 334 587 4523 +2.921477651e-01 61 < 1 0.8
29.104 +vtp-base 199 203 914 +1.298314625e+05 69 < 1 0.2
29.105 +wood1p 245 2594 70216 +1.442902412e+00 326 < 1 7.1
29.106 +woodw 1099 8405 37478 +1.304476333e+00 1093 < 1 6.0
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
30.2 +++ b/examples/INDEX Mon Dec 06 13:09:21 2010 +0100
30.3 @@ -0,0 +1,52 @@
30.4 +assign.mod Assignment problem
30.5 +bpp.mod Bin packing problem
30.6 +cal.mod Print an ASCII calendar of the given year
30.7 +cf12a.mod Curve fitting problem
30.8 +cf12b.mod Curve fitting problem
30.9 +cflsq.mod Curve fitting problem by least squares
30.10 +color.mod Graph coloring problem
30.11 +cpp.mod Critical path problem
30.12 +crypto.mod A crypto-arithmetic puzzle
30.13 +dea.mod Data envelopment analysis (DEA)
30.14 +diet.mod Stigler's nutrition model
30.15 +dist.mod A product distribution model
30.16 +egypt.mod A static model for fertilizer production
30.17 +fctp.mod Fixed-charge transportation problem
30.18 +food.mod Food manufacture model
30.19 +food2.mod Food manufacture model
30.20 +gap.mod Generalized assignment problem
30.21 +graph.mod Graph visualization
30.22 +hashi.mod A solver for the Japanese number-puzzle Hashiwokakero
30.23 +huge.mod Arithmetic mean of a large number of integers
30.24 +jssp.mod Job-shop scheduling problem
30.25 +magic.mod Magic square
30.26 +maxcut.mod Maximum cut problem
30.27 +maxflow.mod Maximum flow problem
30.28 +mfasp.mod Minimum feedback arc set problem
30.29 +mfvsp.mod Minimum feedback vertex set problem
30.30 +min01ks.mod Finding minimal equivalent 0-1 knapsack inequality
30.31 +misp.mod Maximum independent set problem
30.32 +money.mod A crypto-arithmetic puzzle
30.33 +mvcp.mod Minimum vertex cover problem
30.34 +numbrix.mod Number placement puzzle
30.35 +pbn.mod Paint-by-numbers puzzle
30.36 +plan.mod A simple LP problem
30.37 +prod.mod A multiperiod production model
30.38 +qfit.mod Quadratic curve fitting solution
30.39 +queens.mod A classic combinatorial optimization problem
30.40 +sat.mod Satisfiability problem
30.41 +shiftcover.mod Workforce shift coverage assignment problem
30.42 +shikaku.mod A solver for the logic puzzle Shikaku
30.43 +sorting.mod How to sort arrays in MathProg
30.44 +spp.mod Shortest path problem
30.45 +stigler.mod Original Stigler's 1939 diet problem
30.46 +sudoku.mod Number placement puzzle
30.47 +tas.mod Tail assignment problem
30.48 +todd.mod A class of hard instances of 0-1 knapsack problems
30.49 +train.mod A model of railroad passenger car allocation
30.50 +transp.mod A transportation problem
30.51 +trick.mod A transportation design problem
30.52 +tsp.mod Traveling salesman problem
30.53 +xyacfs.mod Extended yet another curve fitting solution
30.54 +yacfs.mod Yet another curve fitting solution
30.55 +zebra.mod Who owns the zebra?
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
31.2 +++ b/examples/Makefile.am Mon Dec 06 13:09:21 2010 +0100
31.3 @@ -0,0 +1,15 @@
31.4 +## Process this file with automake to produce Makefile.in ##
31.5 +
31.6 +INCLUDES = -I$(srcdir)/../include
31.7 +
31.8 +LDADD = ../src/libglpk.la
31.9 +
31.10 +bin_PROGRAMS = glpsol
31.11 +
31.12 +glpsol_SOURCES = glpsol.c
31.13 +
31.14 +check: glpsol$(EXEEXT)
31.15 + ./glpsol$(EXEEXT) --version
31.16 + ./glpsol$(EXEEXT) --mps $(srcdir)/plan.mps
31.17 +
31.18 +## eof ##
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
32.2 +++ b/examples/assign.mod Mon Dec 06 13:09:21 2010 +0100
32.3 @@ -0,0 +1,77 @@
32.4 +/* ASSIGN, Assignment Problem */
32.5 +
32.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
32.7 +
32.8 +/* The assignment problem is one of the fundamental combinatorial
32.9 + optimization problems.
32.10 +
32.11 + In its most general form, the problem is as follows:
32.12 +
32.13 + There are a number of agents and a number of tasks. Any agent can be
32.14 + assigned to perform any task, incurring some cost that may vary
32.15 + depending on the agent-task assignment. It is required to perform all
32.16 + tasks by assigning exactly one agent to each task in such a way that
32.17 + the total cost of the assignment is minimized.
32.18 +
32.19 + (From Wikipedia, the free encyclopedia.) */
32.20 +
32.21 +param m, integer, > 0;
32.22 +/* number of agents */
32.23 +
32.24 +param n, integer, > 0;
32.25 +/* number of tasks */
32.26 +
32.27 +set I := 1..m;
32.28 +/* set of agents */
32.29 +
32.30 +set J := 1..n;
32.31 +/* set of tasks */
32.32 +
32.33 +param c{i in I, j in J}, >= 0;
32.34 +/* cost of allocating task j to agent i */
32.35 +
32.36 +var x{i in I, j in J}, >= 0;
32.37 +/* x[i,j] = 1 means task j is assigned to agent i
32.38 + note that variables x[i,j] are binary, however, there is no need to
32.39 + declare them so due to the totally unimodular constraint matrix */
32.40 +
32.41 +s.t. phi{i in I}: sum{j in J} x[i,j] <= 1;
32.42 +/* each agent can perform at most one task */
32.43 +
32.44 +s.t. psi{j in J}: sum{i in I} x[i,j] = 1;
32.45 +/* each task must be assigned exactly to one agent */
32.46 +
32.47 +minimize obj: sum{i in I, j in J} c[i,j] * x[i,j];
32.48 +/* the objective is to find a cheapest assignment */
32.49 +
32.50 +solve;
32.51 +
32.52 +printf "\n";
32.53 +printf "Agent Task Cost\n";
32.54 +printf{i in I} "%5d %5d %10g\n", i, sum{j in J} j * x[i,j],
32.55 + sum{j in J} c[i,j] * x[i,j];
32.56 +printf "----------------------\n";
32.57 +printf " Total: %10g\n", sum{i in I, j in J} c[i,j] * x[i,j];
32.58 +printf "\n";
32.59 +
32.60 +data;
32.61 +
32.62 +/* These data correspond to an example from [Christofides]. */
32.63 +
32.64 +/* Optimal solution is 76 */
32.65 +
32.66 +param m := 8;
32.67 +
32.68 +param n := 8;
32.69 +
32.70 +param c : 1 2 3 4 5 6 7 8 :=
32.71 + 1 13 21 20 12 8 26 22 11
32.72 + 2 12 36 25 41 40 11 4 8
32.73 + 3 35 32 13 36 26 21 13 37
32.74 + 4 34 54 7 8 12 22 11 40
32.75 + 5 21 6 45 18 24 34 12 48
32.76 + 6 42 19 39 15 14 16 28 46
32.77 + 7 16 34 38 3 34 40 22 24
32.78 + 8 26 20 5 17 45 31 37 43 ;
32.79 +
32.80 +end;
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
33.2 +++ b/examples/bpp.mod Mon Dec 06 13:09:21 2010 +0100
33.3 @@ -0,0 +1,83 @@
33.4 +/* BPP, Bin Packing Problem */
33.5 +
33.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
33.7 +
33.8 +/* Given a set of items I = {1,...,m} with weight w[i] > 0, the Bin
33.9 + Packing Problem (BPP) is to pack the items into bins of capacity c
33.10 + in such a way that the number of bins used is minimal. */
33.11 +
33.12 +param m, integer, > 0;
33.13 +/* number of items */
33.14 +
33.15 +set I := 1..m;
33.16 +/* set of items */
33.17 +
33.18 +param w{i in 1..m}, > 0;
33.19 +/* w[i] is weight of item i */
33.20 +
33.21 +param c, > 0;
33.22 +/* bin capacity */
33.23 +
33.24 +/* We need to estimate an upper bound of the number of bins sufficient
33.25 + to contain all items. The number of items m can be used, however, it
33.26 + is not a good idea. To obtain a more suitable estimation an easy
33.27 + heuristic is used: we put items into a bin while it is possible, and
33.28 + if the bin is full, we use another bin. The number of bins used in
33.29 + this way gives us a more appropriate estimation. */
33.30 +
33.31 +param z{i in I, j in 1..m} :=
33.32 +/* z[i,j] = 1 if item i is in bin j, otherwise z[i,j] = 0 */
33.33 +
33.34 + if i = 1 and j = 1 then 1
33.35 + /* put item 1 into bin 1 */
33.36 +
33.37 + else if exists{jj in 1..j-1} z[i,jj] then 0
33.38 + /* if item i is already in some bin, do not put it into bin j */
33.39 +
33.40 + else if sum{ii in 1..i-1} w[ii] * z[ii,j] + w[i] > c then 0
33.41 + /* if item i does not fit into bin j, do not put it into bin j */
33.42 +
33.43 + else 1;
33.44 + /* otherwise put item i into bin j */
33.45 +
33.46 +check{i in I}: sum{j in 1..m} z[i,j] = 1;
33.47 +/* each item must be exactly in one bin */
33.48 +
33.49 +check{j in 1..m}: sum{i in I} w[i] * z[i,j] <= c;
33.50 +/* no bin must be overflowed */
33.51 +
33.52 +param n := sum{j in 1..m} if exists{i in I} z[i,j] then 1;
33.53 +/* determine the number of bins used by the heuristic; obviously it is
33.54 + an upper bound of the optimal solution */
33.55 +
33.56 +display n;
33.57 +
33.58 +set J := 1..n;
33.59 +/* set of bins */
33.60 +
33.61 +var x{i in I, j in J}, binary;
33.62 +/* x[i,j] = 1 means item i is in bin j */
33.63 +
33.64 +var used{j in J}, binary;
33.65 +/* used[j] = 1 means bin j contains at least one item */
33.66 +
33.67 +s.t. one{i in I}: sum{j in J} x[i,j] = 1;
33.68 +/* each item must be exactly in one bin */
33.69 +
33.70 +s.t. lim{j in J}: sum{i in I} w[i] * x[i,j] <= c * used[j];
33.71 +/* if bin j is used, it must not be overflowed */
33.72 +
33.73 +minimize obj: sum{j in J} used[j];
33.74 +/* objective is to minimize the number of bins used */
33.75 +
33.76 +data;
33.77 +
33.78 +/* The optimal solution is 3 bins */
33.79 +
33.80 +param m := 6;
33.81 +
33.82 +param w := 1 50, 2 60, 3 30, 4 70, 5 50, 6 40;
33.83 +
33.84 +param c := 100;
33.85 +
33.86 +end;
34.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
34.2 +++ b/examples/cal.mod Mon Dec 06 13:09:21 2010 +0100
34.3 @@ -0,0 +1,49 @@
34.4 +/* cal.mod - print an ASCII calendar of the given year */
34.5 +
34.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
34.7 +
34.8 +param year, integer, >= 0001, <= 3999, default 2010;
34.9 +
34.10 +param first_day{m in 1..12}, integer, >= 0, <= 6, :=
34.11 + time2str(str2time(year & "-" & m & "-01", "%Y-%m-%d"), "%w");
34.12 +
34.13 +param days_in_month{m in 1..12}, integer, >= 28, <= 31, :=
34.14 + (str2time(year + (if m < 12 then 0 else 1) & "-" &
34.15 + (if m < 12 then m+1 else 1) & "-01", "%Y-%m-%d") -
34.16 + str2time(year & "-" & m & "-01", "%Y-%m-%d")) / 86400;
34.17 +
34.18 +param foo{m in 1..12, k in 0..5, d in 0..6}, integer, :=
34.19 + 7 * k + d + 1 - first_day[m];
34.20 +
34.21 +param cal{m in 1..12, k in 0..5, d in 0..6}, integer, :=
34.22 + if 1 <= foo[m,k,d] and foo[m,k,d] <= days_in_month[m] then
34.23 + foo[m,k,d];
34.24 +
34.25 +printf "\n";
34.26 +printf "%33s%04d\n", "", year;
34.27 +printf "\n";
34.28 +for {t in 1..12 by 3}
34.29 +{ for {m in t..t+2}
34.30 + { printf "%7s%-14s", "", time2str(str2time(m, "%m"), "%B");
34.31 + printf{0..0: m < t+2} " ";
34.32 + }
34.33 + printf "\n";
34.34 + for {m in t..t+2}
34.35 + { printf " S M Tu W Th F S";
34.36 + printf{0..0: m < t+2} " ";
34.37 + }
34.38 + printf "\n";
34.39 + for {k in 0..5}
34.40 + { for {m in t..t+2}
34.41 + { for {d in 0..6}
34.42 + { printf{0..0: cal[m,k,d] = 0} " ";
34.43 + printf{0..0: cal[m,k,d] != 0} " %2d", cal[m,k,d];
34.44 + }
34.45 + printf{0..0: m < t+2} " ";
34.46 + }
34.47 + printf "\n";
34.48 + }
34.49 +}
34.50 +printf "\n";
34.51 +
34.52 +end;
35.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
35.2 +++ b/examples/cf12a.mod Mon Dec 06 13:09:21 2010 +0100
35.3 @@ -0,0 +1,81 @@
35.4 +/*
35.5 +
35.6 + Curve fitting problem 12.11(a) H P Williams "Model Building in Mathematical Programming"
35.7 +
35.8 + Dr. H J Mackenzie
35.9 + HARD software
35.10 + hjm@hardsoftware.com
35.11 +
35.12 + 2006-01-05
35.13 +
35.14 + */
35.15 +
35.16 +# set of points
35.17 +
35.18 +set I;
35.19 +
35.20 +# independent variable
35.21 +
35.22 +param x {i in I};
35.23 +
35.24 +# dependent variable
35.25 +
35.26 +param y {i in I};
35.27 +
35.28 +# output input values
35.29 +
35.30 +printf {i in I} "x = %.1f; y = %.1f\n", x[i], y[i];
35.31 +
35.32 +# define equation variables
35.33 +
35.34 +var a;
35.35 +
35.36 +var b;
35.37 +
35.38 +var u {i in I}, >= 0;
35.39 +
35.40 +var v {i in I}, >= 0;
35.41 +
35.42 +# define objective function
35.43 +
35.44 +minimize error: sum {i in I} u[i] + sum {i in I} v[i];
35.45 +
35.46 +# define equation constraint
35.47 +
35.48 +s.t. equation {i in I} : b * x[i] + a + u[i] - v[i] = y[i];
35.49 +
35.50 +solve;
35.51 +
35.52 +printf "y = %.4fx + %.4f\n", b, a;
35.53 +
35.54 +/*
35.55 + *
35.56 + * DATA section
35.57 + *
35.58 + */
35.59 +
35.60 +data;
35.61 +
35.62 +param : I : x y :=
35.63 + 1 0 1
35.64 + 2 0.5 0.9
35.65 + 3 1 0.7
35.66 + 4 1.5 1.5
35.67 + 5 1.9 2
35.68 + 6 2.5 2.4
35.69 + 7 3 3.2
35.70 + 8 3.5 2
35.71 + 9 4 2.7
35.72 + 10 4.5 3.5
35.73 + 11 5 1
35.74 + 12 5.5 4
35.75 + 13 6 3.6
35.76 + 14 6.6 2.7
35.77 + 15 7 5.7
35.78 + 16 7.6 4.6
35.79 + 17 8.5 6
35.80 + 18 9 6.8
35.81 + 19 10 7.3
35.82 +;
35.83 +
35.84 +end;
36.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
36.2 +++ b/examples/cf12b.mod Mon Dec 06 13:09:21 2010 +0100
36.3 @@ -0,0 +1,88 @@
36.4 +/*
36.5 +
36.6 + Curve fitting problem 12.11(b) H P Williams "Model Building in Mathematical Programming"
36.7 +
36.8 + Dr. H J Mackenzie
36.9 + HARD software
36.10 + hjm@hardsoftware.com
36.11 +
36.12 + 2006-01-23
36.13 +
36.14 + */
36.15 +
36.16 +# set of points
36.17 +
36.18 +set I;
36.19 +
36.20 +# independent variable
36.21 +
36.22 +param x {i in I};
36.23 +
36.24 +# dependent variable
36.25 +
36.26 +param y {i in I};
36.27 +
36.28 +# output input values
36.29 +
36.30 +printf {i in I} "x = %.1f; y = %.1f\n", x[i], y[i];
36.31 +
36.32 +# define equation variables
36.33 +
36.34 +var a;
36.35 +
36.36 +var b;
36.37 +
36.38 +var u {i in I}, >= 0;
36.39 +
36.40 +var v {i in I}, >= 0;
36.41 +
36.42 +var z;
36.43 +
36.44 +# define objective function
36.45 +
36.46 +minimize deviation: z;
36.47 +
36.48 +# define equation constraint
36.49 +
36.50 +s.t. equation {i in I} : b * x[i] + a + u[i] - v[i] = y[i];
36.51 +
36.52 +# define deviation constrains
36.53 +
36.54 +s.t. u_deviation {i in I} : z - u[i] >= 0;
36.55 +s.t. v_deviation {i in I} : z - v[i] >= 0;
36.56 +
36.57 +solve;
36.58 +
36.59 +printf "y = %.4fx + %.4f Max deviation = %.4f\n", b, a, z;
36.60 +
36.61 +/*
36.62 + *
36.63 + * DATA section
36.64 + *
36.65 + */
36.66 +
36.67 +data;
36.68 +
36.69 +param : I : x y :=
36.70 + 1 0 1
36.71 + 2 0.5 0.9
36.72 + 3 1 0.7
36.73 + 4 1.5 1.5
36.74 + 5 1.9 2
36.75 + 6 2.5 2.4
36.76 + 7 3 3.2
36.77 + 8 3.5 2
36.78 + 9 4 2.7
36.79 + 10 4.5 3.5
36.80 + 11 5 1
36.81 + 12 5.5 4
36.82 + 13 6 3.6
36.83 + 14 6.6 2.7
36.84 + 15 7 5.7
36.85 + 16 7.6 4.6
36.86 + 17 8.5 6
36.87 + 18 9 6.8
36.88 + 19 10 7.3
36.89 +;
36.90 +
36.91 +end;
37.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
37.2 +++ b/examples/cflsq.mod Mon Dec 06 13:09:21 2010 +0100
37.3 @@ -0,0 +1,51 @@
37.4 +/*Curve fitting problem by Least Squares
37.5 + Nigel_Galloway@operamail.com
37.6 + October 1st., 2007
37.7 +*/
37.8 +set Sample;
37.9 +param Sx {z in Sample};
37.10 +param Sy {z in Sample};
37.11 +
37.12 +var X;
37.13 +var Y;
37.14 +var Ex{z in Sample};
37.15 +var Ey{z in Sample};
37.16 +
37.17 +/* sum of variances is zero for Sx*/
37.18 +variencesX{z in Sample}: X + Ex[z] = Sx[z];
37.19 +zumVariancesX: sum{z in Sample} Ex[z] = 0;
37.20 +/* sum of variances is zero for Sy*/
37.21 +variencesY{z in Sample}: Y + Ey[z] = Sy[z];
37.22 +zumVariancesY: sum{z in Sample} Ey[z] = 0;
37.23 +
37.24 +solve;
37.25 +
37.26 +param b1 := (sum{z in Sample} Ex[z]*Ey[z])/(sum{z in Sample} Ex[z]*Ex[z]);
37.27 +printf "\nbest linear fit is:\n\ty = %f %s %fx\n\n", Y-b1*X, if b1 < 0 then "-" else "+", abs(b1);
37.28 +
37.29 +data;
37.30 +
37.31 +param:
37.32 +Sample: Sx Sy :=
37.33 + 1 0 1
37.34 + 2 0.5 0.9
37.35 + 3 1 0.7
37.36 + 4 1.5 1.5
37.37 + 5 1.9 2
37.38 + 6 2.5 2.4
37.39 + 7 3 3.2
37.40 + 8 3.5 2
37.41 + 9 4 2.7
37.42 + 10 4.5 3.5
37.43 + 11 5 1
37.44 + 12 5.5 4
37.45 + 13 6 3.6
37.46 + 14 6.6 2.7
37.47 + 15 7 5.7
37.48 + 16 7.6 4.6
37.49 + 17 8.5 6
37.50 + 18 9 6.8
37.51 + 19 10 7.3
37.52 +;
37.53 +
37.54 +end;
38.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
38.2 +++ b/examples/color.mod Mon Dec 06 13:09:21 2010 +0100
38.3 @@ -0,0 +1,113 @@
38.4 +/* COLOR, Graph Coloring Problem */
38.5 +
38.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
38.7 +
38.8 +/* Given an undirected loopless graph G = (V, E), where V is a set of
38.9 + nodes, E <= V x V is a set of arcs, the Graph Coloring Problem is to
38.10 + find a mapping (coloring) F: V -> C, where C = {1, 2, ... } is a set
38.11 + of colors whose cardinality is as small as possible, such that
38.12 + F(i) != F(j) for every arc (i,j) in E, that is adjacent nodes must
38.13 + be assigned different colors. */
38.14 +
38.15 +param n, integer, >= 2;
38.16 +/* number of nodes */
38.17 +
38.18 +set V := {1..n};
38.19 +/* set of nodes */
38.20 +
38.21 +set E, within V cross V;
38.22 +/* set of arcs */
38.23 +
38.24 +check{(i,j) in E}: i != j;
38.25 +/* there must be no loops */
38.26 +
38.27 +/* We need to estimate an upper bound of the number of colors |C|.
38.28 + The number of nodes |V| can be used, however, for sparse graphs such
38.29 + bound is not very good. To obtain a more suitable estimation we use
38.30 + an easy "greedy" heuristic. Let nodes 1, ..., i-1 are already
38.31 + assigned some colors. To assign a color to node i we see if there is
38.32 + an existing color not used for coloring nodes adjacent to node i. If
38.33 + so, we use this color, otherwise we introduce a new color. */
38.34 +
38.35 +set EE := setof{(i,j) in E} (i,j) union setof{(i,j) in E} (j,i);
38.36 +/* symmetrisized set of arcs */
38.37 +
38.38 +param z{i in V, case in 0..1} :=
38.39 +/* z[i,0] = color index assigned to node i
38.40 + z[i,1] = maximal color index used for nodes 1, 2, ..., i-1 which are
38.41 + adjacent to node i */
38.42 +( if case = 0 then
38.43 + ( /* compute z[i,0] */
38.44 + min{c in 1..z[i,1]}
38.45 + ( if not exists{j in V: j < i and (i,j) in EE} z[j,0] = c then
38.46 + c
38.47 + else
38.48 + z[i,1] + 1
38.49 + )
38.50 + )
38.51 + else
38.52 + ( /* compute z[i,1] */
38.53 + if not exists{j in V: j < i} (i,j) in EE then
38.54 + 1
38.55 + else
38.56 + max{j in V: j < i and (i,j) in EE} z[j,0]
38.57 + )
38.58 +);
38.59 +
38.60 +check{(i,j) in E}: z[i,0] != z[j,0];
38.61 +/* check that all adjacent nodes are assigned distinct colors */
38.62 +
38.63 +param nc := max{i in V} z[i,0];
38.64 +/* number of colors used by the heuristic; obviously, it is an upper
38.65 + bound of the optimal solution */
38.66 +
38.67 +display nc;
38.68 +
38.69 +var x{i in V, c in 1..nc}, binary;
38.70 +/* x[i,c] = 1 means that node i is assigned color c */
38.71 +
38.72 +var u{c in 1..nc}, binary;
38.73 +/* u[c] = 1 means that color c is used, i.e. assigned to some node */
38.74 +
38.75 +s.t. map{i in V}: sum{c in 1..nc} x[i,c] = 1;
38.76 +/* each node must be assigned exactly one color */
38.77 +
38.78 +s.t. arc{(i,j) in E, c in 1..nc}: x[i,c] + x[j,c] <= u[c];
38.79 +/* adjacent nodes cannot be assigned the same color */
38.80 +
38.81 +minimize obj: sum{c in 1..nc} u[c];
38.82 +/* objective is to minimize the number of colors used */
38.83 +
38.84 +data;
38.85 +
38.86 +/* These data correspond to the instance myciel3.col from:
38.87 + http://mat.gsia.cmu.edu/COLOR/instances.html */
38.88 +
38.89 +/* The optimal solution is 4 */
38.90 +
38.91 +param n := 11;
38.92 +
38.93 +set E :=
38.94 + 1 2
38.95 + 1 4
38.96 + 1 7
38.97 + 1 9
38.98 + 2 3
38.99 + 2 6
38.100 + 2 8
38.101 + 3 5
38.102 + 3 7
38.103 + 3 10
38.104 + 4 5
38.105 + 4 6
38.106 + 4 10
38.107 + 5 8
38.108 + 5 9
38.109 + 6 11
38.110 + 7 11
38.111 + 8 11
38.112 + 9 11
38.113 + 10 11
38.114 +;
38.115 +
38.116 +end;
39.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
39.2 +++ b/examples/cplex/README Mon Dec 06 13:09:21 2010 +0100
39.3 @@ -0,0 +1,44 @@
39.4 +The program module in this subdirectory is a crude implementation of
39.5 +CPLEX-like interface to GLPK API. It consists of two files: cplex.c and
39.6 +cplex.h.
39.7 +
39.8 +NOTE that this module is NOT a clean room implementation of the CPLEX
39.9 +callable library. It only implements a CPLEX-like interface to the GLPK
39.10 +API routines, and its main purpose is to provide possibility to build
39.11 +and run applications which normally use the CPLEX callable library.
39.12 +
39.13 +This module approximately corresponds to CPLEX 9.0.
39.14 +
39.15 +Currently this module can be used as a linear programming solver for
39.16 +Concorde, the state-of-the-art computer code for solving the symmetric
39.17 +traveling salesman problem (TSP) developed by David Applegate, Robert
39.18 +Bixby, Vasek Chvatal, and William Cook. For details about Concorde see
39.19 +its web page at http://www.tsp.gatech.edu/concorde.html.
39.20 +
39.21 +To build Concorde along with GLPK you need to do the following:
39.22 +
39.23 +1. Configure, build, and install GLPK.
39.24 +
39.25 +2. Download the Concorde tarball co031219.tgz (version Dec 19, 2003),
39.26 + unpack and unarchive it.
39.27 +
39.28 +3. Copy files cplex.h and cplex.c to subdirectory concorde/LP/.
39.29 +
39.30 +4. Create file named lpglpk.c in subdirectory concorde/LP/. This file
39.31 + must contain the following two lines:
39.32 +
39.33 + #include "cplex.c"
39.34 + #include "lpcplex8.c"
39.35 +
39.36 +5. Configure Concorde in usual way (./configure) and then build it with
39.37 + the following command:
39.38 +
39.39 + make CPPFLAGS=-I. LPSOLVER_INTERFACE=lpglpk.c LPSOLVER_LIB=-lglpk
39.40 +
39.41 + The Concorde executable can be found in subdirectory concorde/TSP/.
39.42 +
39.43 +Please note that currently this GLPK interface module does not support
39.44 +some important features (namely, CPXgetijdiv, CPXmdleave, CPXpivotin,
39.45 +CPXpivotout, and CPXstrongbranch), so large (more than 1000 nodes) TSP
39.46 +instances cannot be solved in a reasonable time, and some instances may
39.47 +cause abnormal termination of Concorde (if CPXgetijdiv is called).
40.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
40.2 +++ b/examples/cplex/concorde.txt Mon Dec 06 13:09:21 2010 +0100
40.3 @@ -0,0 +1,121 @@
40.4 +Solver: Concorde-03.12.19 (options used: -s 99)
40.5 + http://www.tsp.gatech.edu/concorde.html
40.6 +LP Solver: GLPK 4.34 (CPLEX-like interface module examples/cplex)
40.7 +Computer: Intel Pentium 4 CPU 3GHz, 2GB of RAM
40.8 +Platform: Cygwin 1.5.24 (Windows XP 5.1 Build 2600 Service Pack 4)
40.9 +Compiler: GCC 3.4.4 (options used: -O2)
40.10 +Test set: http://www.iwr.uni-heidelberg.de/groups/comopt/software/
40.11 + TSPLIB95/
40.12 +
40.13 +Problem Solution B&B Time, s
40.14 +--------- -------- --- -------
40.15 +a280 2579 1 3.09
40.16 +ali535 202339 1 21.88
40.17 +att48 10628 1 0.20
40.18 +att532 27686 7 74.31
40.19 +bayg29 1610 1 0.08
40.20 +bays29 2020 1 0.08
40.21 +berlin52 7542 1 0.11
40.22 +bier127 118282 1 0.62
40.23 +brazil58 25395 1 0.23
40.24 +brd14051
40.25 +brg180 1950 1 0.34
40.26 +burma14 3323 1 0.06
40.27 +ch130 6110 1 0.92
40.28 +ch150 6528 1 1.69
40.29 +d1291
40.30 +d15112
40.31 +d1655
40.32 +d18512
40.33 +d198 15780 3 4.92
40.34 +d2103
40.35 +d493 35002 5 123.89
40.36 +d657 48913 11 148.17
40.37 +dantzig42 699 1 0.08
40.38 +dsj1000 18660188 13 251.00
40.39 +eil101 (failed due to CPXgetijdiv)
40.40 +eil51 426 1 0.17
40.41 +eil76 538 1 0.11
40.42 +fl1400
40.43 +fl1577
40.44 +fl3795
40.45 +fl417 11861 1 47.20
40.46 +fnl4461
40.47 +fri26 937 1 0.05
40.48 +gil262 2378 3 10.39
40.49 +gr120 6942 1 0.66
40.50 +gr137 69853 1 2.09
40.51 +gr17 2085 1 0.03
40.52 +gr202 40160 1 3.97
40.53 +gr21 2707 1 0.03
40.54 +gr229 134602 7 19.45
40.55 +gr24 1272 1 0.03
40.56 +gr431 171414 9 40.67
40.57 +gr48 5046 1 0.22
40.58 +gr666 294358 3 40.23
40.59 +gr96 55209 1 1.22
40.60 +hk48 11461 1 0.08
40.61 +kroA100 21282 1 0.41
40.62 +kroA150 26524 1 2.09
40.63 +kroA200 29368 1 2.44
40.64 +kroB100 22141 1 1.20
40.65 +kroB150 26130 1 1.66
40.66 +kroB200 29437 1 1.41
40.67 +kroC100 20749 1 0.42
40.68 +kroD100 21294 1 0.50
40.69 +kroE100 22068 1 0.94
40.70 +lin105 14379 1 0.23
40.71 +lin318 42029 1 4.28
40.72 +nrw1379
40.73 +p654 34643 1 17.08
40.74 +pa561 2763 15 370.70
40.75 +pcb1173 56892 11 370.30
40.76 +pcb3038
40.77 +pcb442 59778 13 35.86
40.78 +pla33810
40.79 +pla7397
40.80 +pla85900
40.81 +pr1002 259045 1 23.08
40.82 +pr107 44303 1 0.38
40.83 +pr124 59030 1 1.23
40.84 +pr136 96772 1 2.19
40.85 +pr144 58537 1 0.89
40.86 +pr152 73682 1 2.73
40.87 +pr226 80369 1 2.72
40.88 +pr2392
40.89 +pr264 49135 1 1.61
40.90 +pr299 48191 3 14.52
40.91 +pr439 107217 15 117.75
40.92 +pr76 108159 1 0.95
40.93 +rat195 2323 5 12.91
40.94 +rat575 6773 19 202.52
40.95 +rat783 8806 1 37.92
40.96 +rat99 1211 1 0.50
40.97 +rd100 7910 1 0.28
40.98 +rd400 15281 11 74.41
40.99 +rl11849
40.100 +rl1304
40.101 +rl1323
40.102 +rl1889
40.103 +rl5915
40.104 +rl5934
40.105 +si1032 92650 1 82.09
40.106 +si175 21407 3 8.97
40.107 +si535 48450 1 71.28
40.108 +st70 675 1 0.20
40.109 +swiss42 1273 1 0.06
40.110 +ts225 126643 1 21.25
40.111 +tsp225 3916 1 10.14
40.112 +u1060 224094 13 507.44
40.113 +u1432
40.114 +u159 42080 1 0.41
40.115 +u1817
40.116 +u2152
40.117 +u2319
40.118 +u574 36905 1 32.84
40.119 +u724 41910 19 238.42
40.120 +ulysses16 6859 1 0.19
40.121 +ulysses22 7013 1 0.47
40.122 +usa13509
40.123 +vm1084 239297 9 543.38
40.124 +vm1748
41.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
41.2 +++ b/examples/cplex/cplex.c Mon Dec 06 13:09:21 2010 +0100
41.3 @@ -0,0 +1,2130 @@
41.4 +/* cplex.c (CPLEX-like interface to GLPK API) */
41.5 +
41.6 +/***********************************************************************
41.7 +* This code is part of GLPK (GNU Linear Programming Kit).
41.8 +*
41.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
41.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
41.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
41.12 +* E-mail: <mao@gnu.org>.
41.13 +*
41.14 +* GLPK is free software: you can redistribute it and/or modify it
41.15 +* under the terms of the GNU General Public License as published by
41.16 +* the Free Software Foundation, either version 3 of the License, or
41.17 +* (at your option) any later version.
41.18 +*
41.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
41.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
41.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
41.22 +* License for more details.
41.23 +*
41.24 +* You should have received a copy of the GNU General Public License
41.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
41.26 +***********************************************************************/
41.27 +
41.28 +#include <ctype.h>
41.29 +#include <stdarg.h>
41.30 +#include <stdio.h>
41.31 +#include <stdlib.h>
41.32 +#include <string.h>
41.33 +#include <glpk.h>
41.34 +#include "cplex.h"
41.35 +
41.36 +struct CPXENV
41.37 +{ /* environment block */
41.38 + CPXLP *list;
41.39 + /* linked list of problem objects */
41.40 + int *intparam; /* int intparam[]; */
41.41 + /* integer control parameters */
41.42 + double *dblparam; /* double dblparam[]; */
41.43 + /* floating-point control parameters */
41.44 +};
41.45 +
41.46 +struct CPXLP
41.47 +{ /* problem object */
41.48 + CPXENV *env;
41.49 + /* pointer to environment block */
41.50 + glp_prob *prob;
41.51 + /* pointer to underlying GLPK problem object */
41.52 + int rflen;
41.53 + /* length of the array rflag */
41.54 + char *rflag; /* char rflag[rflen]; */
41.55 + /* rflag[i], i = 0,...,nrows-1, is a flag of i-th row: */
41.56 +#define RF_NOT_RANGED 0 /* not ranged */
41.57 +#define RF_RANGED_POS 1 /* ranged, RHS = lower bound */
41.58 +#define RF_RANGED_NEG 2 /* ranged, RHS = upper bound */
41.59 + int stat;
41.60 + /* solution status reported by CPXgetstat; zero means no solution
41.61 + exists */
41.62 + int meth;
41.63 + /* method indicator reported by CPXgetmethod */
41.64 + int iwlen;
41.65 + /* length of the working array */
41.66 + int *iwork; /* int iwork[iwlen] */
41.67 + /* working array initialized by binary zeros */
41.68 + CPXLP *link;
41.69 + /* pointer to another problem object */
41.70 +};
41.71 +
41.72 +struct intparam
41.73 +{ int which;
41.74 + int defv;
41.75 + int minv;
41.76 + int maxv;
41.77 +};
41.78 +
41.79 +struct dblparam
41.80 +{ int which;
41.81 + double defv;
41.82 + double minv;
41.83 + double maxv;
41.84 +};
41.85 +
41.86 +struct errstring
41.87 +{ int code;
41.88 + const char *string;
41.89 +};
41.90 +
41.91 +#define BIGINT 2100000000
41.92 +#define BIGDBL 1e75
41.93 +
41.94 +static const struct intparam intparam[] =
41.95 +{ {CPX_PARAM_ADVIND, 0, 0, 2},
41.96 + {CPX_PARAM_AGGIND, -1, -1, BIGINT},
41.97 + {CPX_PARAM_DATACHECK, CPX_OFF, CPX_OFF, CPX_ON},
41.98 + {CPX_PARAM_DPRIIND, CPX_DPRIIND_AUTO, CPX_DPRIIND_AUTO,
41.99 + CPX_DPRIIND_DEVEX},
41.100 + {CPX_PARAM_FASTMIP, CPX_OFF, CPX_OFF, CPX_ON}, /* ??? */
41.101 + {CPX_PARAM_ITLIM, BIGINT, 0, BIGINT},
41.102 + {CPX_PARAM_PERIND, CPX_OFF, CPX_OFF, CPX_ON},
41.103 + {CPX_PARAM_PPRIIND, CPX_PPRIIND_AUTO, CPX_PPRIIND_PARTIAL,
41.104 + CPX_PPRIIND_FULL},
41.105 + {CPX_PARAM_PREIND, CPX_ON, CPX_OFF, CPX_ON},
41.106 + {CPX_PARAM_REINV, 0, 0, 10000},
41.107 + {CPX_PARAM_SCRIND, CPX_OFF, CPX_OFF, CPX_ON},
41.108 + {CPX_PARAM_SIMDISPLAY, 1, 0, 2},
41.109 +};
41.110 +
41.111 +static const struct dblparam dblparam[] =
41.112 +{ {CPX_PARAM_EPOPT, 1e-6, 1e-9, 1e-1},
41.113 + {CPX_PARAM_EPPER, 1e-6, 1e-8, BIGDBL},
41.114 + {CPX_PARAM_EPRHS, 1e-6, 1e-9, 1e-1},
41.115 + {CPX_PARAM_OBJLLIM, -BIGDBL, -BIGDBL, +BIGDBL},
41.116 + {CPX_PARAM_OBJULIM, +BIGDBL, -BIGDBL, +BIGDBL},
41.117 +};
41.118 +
41.119 +static const struct errstring errstring[] =
41.120 +{ {CPXERR_ARRAY_NOT_ASCENDING, "Array entry %d not ascending"},
41.121 + {CPXERR_BAD_ARGUMENT, "Invalid argument"},
41.122 + {CPXERR_BAD_CTYPE, "Invalid ctype entry %d"},
41.123 + {CPXERR_BAD_FILETYPE, "Invalid filetype"},
41.124 + {CPXERR_BAD_LUB, "Invalid bound change indicator entry %d"},
41.125 + {CPXERR_BAD_PARAM_NUM, "Invalid parameter number"},
41.126 + {CPXERR_BAD_SENSE, "Invalid sense entry %d"},
41.127 + {CPXERR_BAD_STATUS, "Invalid status entry %d for basis specificat"
41.128 + "ion"},
41.129 + {CPXERR_COL_INDEX_RANGE, "Column index %d out of range"},
41.130 + {CPXERR_COUNT_RANGE, "Count entry %d negative or larger than allo"
41.131 + "wed"},
41.132 + {CPXERR_DUP_ENTRY, "Duplicate entry"},
41.133 + {CPXERR_FAIL_OPEN_WRITE, "Could not open file '%s' for writing"},
41.134 + {CPXERR_INDEX_RANGE, "Index is outside range of valid values"},
41.135 + {CPXERR_NEGATIVE_SURPLUS, "Insufficient array length"},
41.136 + {CPXERR_NO_BASIC_SOLN, "No basic solution exists"},
41.137 + {CPXERR_NO_ENVIRONMENT, "No environment exists"},
41.138 + {CPXERR_NO_FILENAME, "File name not specified"},
41.139 + {CPXERR_NO_MEMORY, "Out of memory"},
41.140 + {CPXERR_NO_PROBLEM, "No problem exists"},
41.141 + {CPXERR_NO_SOLN, "No solution exists"},
41.142 + {CPXERR_NOT_FIXED, "Only fixed variables are pivoted out"},
41.143 + {CPXERR_NULL_NAME, "Null pointer %d in name array"},
41.144 + {CPXERR_NULL_POINTER, "Null pointer for required data"},
41.145 + {CPXERR_PARAM_TOO_BIG, "Parameter value too big"},
41.146 + {CPXERR_PARAM_TOO_SMALL, "Parameter value too small"},
41.147 + {CPXERR_ROW_INDEX_RANGE, "Row index %d out of range"},
41.148 +};
41.149 +
41.150 +/**********************************************************************/
41.151 +
41.152 +#define xassert glp_assert
41.153 +#define xprintf glp_printf
41.154 +#define xmalloc glp_malloc
41.155 +#define xcalloc glp_calloc
41.156 +#define xfree glp_free
41.157 +
41.158 +/**********************************************************************/
41.159 +
41.160 +static int findintparam(int whichparam)
41.161 +{ int k, card;
41.162 + card = sizeof(intparam) / sizeof(struct intparam);
41.163 + for (k = 0; k < card; k++)
41.164 + if (intparam[k].which == whichparam) return k;
41.165 + return -1;
41.166 +}
41.167 +
41.168 +static int getintparam(CPXENV *env, int whichparam)
41.169 +{ int k;
41.170 + xassert(env != NULL);
41.171 + k = findintparam(whichparam);
41.172 + xassert(k >= 0);
41.173 + return env->intparam[k];
41.174 +}
41.175 +
41.176 +static int finddblparam(int whichparam)
41.177 +{ int k, card;
41.178 + card = sizeof(dblparam) / sizeof(struct dblparam);
41.179 + for (k = 0; k < card; k++)
41.180 + if (dblparam[k].which == whichparam) return k;
41.181 + return -1;
41.182 +}
41.183 +
41.184 +static double getdblparam(CPXENV *env, int whichparam)
41.185 +{ int k;
41.186 + xassert(env != NULL);
41.187 + k = finddblparam(whichparam);
41.188 + xassert(k >= 0);
41.189 + return env->dblparam[k];
41.190 +}
41.191 +
41.192 +static const char *finderrstring(int errcode)
41.193 +{ int k, card;
41.194 + card = sizeof(errstring) / sizeof(struct errstring);
41.195 + for (k = 0; k < card; k++)
41.196 + { if (errstring[k].code == errcode)
41.197 + return errstring[k].string;
41.198 + }
41.199 + return NULL;
41.200 +}
41.201 +
41.202 +static int error(CPXENV *env, int errcode, ...)
41.203 +{ va_list arg;
41.204 + char buffer[510];
41.205 + xassert(env != NULL);
41.206 + if (getintparam(env, CPX_PARAM_SCRIND) == CPX_ON)
41.207 + { xassert(CPXgeterrorstring(env, errcode, buffer) == buffer);
41.208 + va_start(arg, errcode);
41.209 + vprintf(buffer, arg);
41.210 + va_end(arg);
41.211 + }
41.212 + return errcode;
41.213 +}
41.214 +
41.215 +static int checkenv(CPXENV *env)
41.216 +{ int errcode;
41.217 + if (env == NULL)
41.218 + errcode = CPXERR_NO_ENVIRONMENT;
41.219 + else
41.220 + errcode = 0;
41.221 + return errcode;
41.222 +}
41.223 +
41.224 +static checklp(CPXENV *env, CPXLP *lp)
41.225 +{ int errcode;
41.226 + errcode = checkenv(env);
41.227 + if (errcode) goto done;
41.228 + if (lp == NULL)
41.229 + errcode = error(env, CPXERR_NO_PROBLEM);
41.230 +done: return errcode;
41.231 +}
41.232 +
41.233 +static void invalidate(CPXLP *lp)
41.234 +{ lp->stat = 0;
41.235 + lp->meth = CPX_ALG_NONE;
41.236 + return;
41.237 +}
41.238 +
41.239 +static void enlargerflag(CPXLP *lp)
41.240 +{ int m;
41.241 + xassert(lp != NULL);
41.242 + m = glp_get_num_rows(lp->prob);
41.243 + if (lp->rflen < m)
41.244 + { int rflen = lp->rflen;
41.245 + char *rflag = lp->rflag;
41.246 + while (lp->rflen < m)
41.247 + { lp->rflen += lp->rflen;
41.248 + xassert(lp->rflen > 0);
41.249 + }
41.250 + lp->rflag = xcalloc(lp->rflen, sizeof(char));
41.251 + memcpy(lp->rflag, rflag, rflen);
41.252 + xfree(rflag);
41.253 + }
41.254 + return;
41.255 +}
41.256 +
41.257 +static void enlargeiwork(CPXLP *lp, int len)
41.258 +{ xassert(len >= 0);
41.259 + if (lp->iwlen < len)
41.260 + { xfree(lp->iwork);
41.261 + while (lp->iwlen < len)
41.262 + { lp->iwlen += lp->iwlen;
41.263 + xassert(lp->iwlen > 0);
41.264 + }
41.265 + lp->iwork = xcalloc(lp->iwlen, sizeof(int));
41.266 + memset(lp->iwork, 0, lp->iwlen * sizeof(int));
41.267 + }
41.268 + return;
41.269 +}
41.270 +
41.271 +/**********************************************************************/
41.272 +
41.273 +int CPXaddcols(CPXENV *env, CPXLP *lp, int ccnt, int nzcnt,
41.274 + const double obj[], const int cmatbeg[], const int cmatind[],
41.275 + const double cmatval[], const double lb[], const double ub[],
41.276 + char *colname[])
41.277 +{ int j, k, m, n, beg, end, type, errcode;
41.278 + double lbnd, ubnd;
41.279 + errcode = checklp(env, lp);
41.280 + if (errcode) goto done;
41.281 + if (ccnt < 0 || nzcnt < 0)
41.282 + { errcode = error(env, CPXERR_BAD_ARGUMENT);
41.283 + goto done;
41.284 + }
41.285 + if (ccnt > 0)
41.286 + { if (cmatbeg == NULL || cmatind == NULL || cmatval == NULL)
41.287 + { errcode = error(env, CPXERR_NULL_POINTER);
41.288 + goto done;
41.289 + }
41.290 + }
41.291 + m = glp_get_num_rows(lp->prob);
41.292 + n = glp_get_num_cols(lp->prob);
41.293 + enlargeiwork(lp, m);
41.294 + for (j = 0; j < ccnt; j++)
41.295 + { beg = cmatbeg[j];
41.296 + if (j > 0 && !(cmatbeg[j-1] <= beg))
41.297 + { errcode = error(env, CPXERR_ARRAY_NOT_ASCENDING, j);
41.298 + goto done;
41.299 + }
41.300 + if (!(0 <= beg && beg <= nzcnt))
41.301 + { errcode = error(env, CPXERR_INDEX_RANGE);
41.302 + goto done;
41.303 + }
41.304 + end = (j < ccnt-1 ? cmatbeg[j+1] : nzcnt);
41.305 + for (k = beg; k < end; k++)
41.306 + { if (!(0 <= cmatind[k] && cmatind[k] < m))
41.307 + { errcode = error(env, CPXERR_ROW_INDEX_RANGE, k);
41.308 + goto done;
41.309 + }
41.310 + }
41.311 + errcode = 0;
41.312 + for (k = beg; k < end; k++)
41.313 + { if (lp->iwork[cmatind[k]])
41.314 + { errcode = error(env, CPXERR_DUP_ENTRY);
41.315 + break;
41.316 + }
41.317 + lp->iwork[cmatind[k]] = 1;
41.318 + }
41.319 + for (k = beg; k < end; k++)
41.320 + lp->iwork[cmatind[k]] = 0;
41.321 + if (errcode) goto done;
41.322 + if (colname != NULL)
41.323 + { if (colname[j] == NULL)
41.324 + { errcode = error(env, CPXERR_NULL_NAME, j);
41.325 + goto done;
41.326 + }
41.327 + }
41.328 + }
41.329 + errcode = 0;
41.330 + invalidate(lp);
41.331 + if (ccnt > 0)
41.332 + glp_add_cols(lp->prob, ccnt);
41.333 + for (j = 0; j < ccnt; j++)
41.334 + { if (colname != NULL)
41.335 + glp_set_col_name(lp->prob, n+j+1, colname[j]);
41.336 + lbnd = (lb == NULL ? 0.0 : lb[j]);
41.337 + ubnd = (ub == NULL ? +CPX_INFBOUND : ub[j]);
41.338 + if (lbnd <= -CPX_INFBOUND && ubnd >= +CPX_INFBOUND)
41.339 + type = GLP_FR;
41.340 + else if (ubnd >= +CPX_INFBOUND)
41.341 + type = GLP_LO;
41.342 + else if (lbnd <= -CPX_INFBOUND)
41.343 + type = GLP_UP;
41.344 + else if (lbnd != ubnd)
41.345 + type = GLP_DB;
41.346 + else
41.347 + type = GLP_FX;
41.348 + glp_set_col_bnds(lp->prob, n+j+1, type, lbnd, ubnd);
41.349 + if (obj != NULL)
41.350 + glp_set_obj_coef(lp->prob, n+j+1, obj[j]);
41.351 + beg = cmatbeg[j];
41.352 + end = (j < ccnt-1 ? cmatbeg[j+1] : nzcnt);
41.353 + for (k = beg; k < end; k++)
41.354 + lp->iwork[k-beg] = cmatind[k]+1;
41.355 + glp_set_mat_col(lp->prob, n+j+1, end-beg, lp->iwork-1,
41.356 + cmatval+beg-1);
41.357 + for (k = beg; k < end; k++)
41.358 + lp->iwork[k-beg] = 0;
41.359 + }
41.360 +done: return errcode;
41.361 +}
41.362 +
41.363 +int CPXaddrows(CPXENV *env, CPXLP *lp, int ccnt, int rcnt, int nzcnt,
41.364 + const double rhs[], const char sense[], const int rmatbeg[],
41.365 + const int rmatind[], const double rmatval[], char *colname[],
41.366 + char *rowname[])
41.367 +{ int i, j, k, m, n, beg, end, type, errcode;
41.368 + double temp;
41.369 + errcode = checklp(env, lp);
41.370 + if (errcode) goto done;
41.371 + if (ccnt < 0 || rcnt < 0 || nzcnt < 0)
41.372 + { errcode = error(env, CPXERR_BAD_ARGUMENT);
41.373 + goto done;
41.374 + }
41.375 + if (rcnt > 0)
41.376 + { if (rmatbeg == NULL || rmatind == NULL || rmatval == NULL)
41.377 + { errcode = error(env, CPXERR_NULL_POINTER);
41.378 + goto done;
41.379 + }
41.380 + }
41.381 + m = glp_get_num_rows(lp->prob);
41.382 + n = glp_get_num_cols(lp->prob);
41.383 + enlargeiwork(lp, n+ccnt);
41.384 + for (i = 0; i < rcnt; i++)
41.385 + { if (sense != NULL)
41.386 + { if (!(sense[i] == 'L' || sense[i] == 'E' ||
41.387 + sense[i] == 'G' || sense[i] == 'R'))
41.388 + { errcode = error(env, CPXERR_BAD_SENSE, i);
41.389 + goto done;
41.390 + }
41.391 + }
41.392 + beg = rmatbeg[i];
41.393 + if (i > 0 && !(rmatbeg[i-1] <= beg))
41.394 + { errcode = error(env, CPXERR_ARRAY_NOT_ASCENDING, i);
41.395 + goto done;
41.396 + }
41.397 + if (!(0 <= beg && beg <= nzcnt))
41.398 + { errcode = error(env, CPXERR_INDEX_RANGE);
41.399 + goto done;
41.400 + }
41.401 + end = (i < rcnt-1 ? rmatbeg[i+1] : nzcnt);
41.402 + for (k = beg; k < end; k++)
41.403 + { if (!(0 <= rmatind[k] && rmatind[k] < n+ccnt))
41.404 + { errcode = error(env, CPXERR_COL_INDEX_RANGE, k);
41.405 + goto done;
41.406 + }
41.407 + }
41.408 + errcode = 0;
41.409 + for (k = beg; k < end; k++)
41.410 + { if (lp->iwork[rmatind[k]])
41.411 + { errcode = error(env, CPXERR_DUP_ENTRY);
41.412 + break;
41.413 + }
41.414 + lp->iwork[rmatind[k]] = 1;
41.415 + }
41.416 + for (k = beg; k < end; k++)
41.417 + lp->iwork[rmatind[k]] = 0;
41.418 + if (errcode) goto done;
41.419 + if (rowname != NULL)
41.420 + { if (rowname[i] == NULL)
41.421 + { errcode = error(env, CPXERR_NULL_NAME, i);
41.422 + goto done;
41.423 + }
41.424 + }
41.425 + }
41.426 + for (j = 0; j < ccnt; j++)
41.427 + { if (colname != NULL)
41.428 + { if (colname[j] == NULL)
41.429 + { errcode = error(env, CPXERR_NULL_NAME, j);
41.430 + goto done;
41.431 + }
41.432 + }
41.433 + }
41.434 + errcode = 0;
41.435 + invalidate(lp);
41.436 + if (rcnt > 0)
41.437 + glp_add_rows(lp->prob, rcnt);
41.438 + if (ccnt > 0)
41.439 + glp_add_cols(lp->prob, ccnt);
41.440 + enlargerflag(lp);
41.441 + for (i = 0; i < rcnt; i++)
41.442 + { if (rowname != NULL)
41.443 + glp_set_row_name(lp->prob, m+i+1, rowname[i]);
41.444 + temp = (rhs == NULL ? 0.0 : rhs[i]);
41.445 + if (sense == NULL || sense[i] == 'E')
41.446 + { lp->rflag[m+i] = RF_NOT_RANGED;
41.447 + type = GLP_FX;
41.448 + }
41.449 + else if (sense[i] == 'L')
41.450 + { lp->rflag[m+i] = RF_NOT_RANGED;
41.451 + type = GLP_UP;
41.452 + }
41.453 + else if (sense[i] == 'G')
41.454 + { lp->rflag[m+i] = RF_NOT_RANGED;
41.455 + type = GLP_LO;
41.456 + }
41.457 + else if (sense[i] == 'R')
41.458 + { lp->rflag[m+i] = RF_RANGED_POS;
41.459 + type = GLP_FX;
41.460 + }
41.461 + else
41.462 + xassert(sense != sense);
41.463 + glp_set_row_bnds(lp->prob, m+i+1, type, temp, temp);
41.464 + beg = rmatbeg[i];
41.465 + end = (i < rcnt-1 ? rmatbeg[i+1] : nzcnt);
41.466 + for (k = beg; k < end; k++)
41.467 + lp->iwork[k-beg] = rmatind[k]+1;
41.468 + glp_set_mat_row(lp->prob, m+i+1, end-beg, lp->iwork-1,
41.469 + rmatval+beg-1);
41.470 + for (k = beg; k < end; k++)
41.471 + lp->iwork[k-beg] = 0;
41.472 + }
41.473 + for (j = 0; j < ccnt; j++)
41.474 + { if (colname != NULL)
41.475 + glp_set_col_name(lp->prob, n+j+1, colname[j]);
41.476 + glp_set_col_bnds(lp->prob, n+j+1, GLP_LO, 0.0, 0.0);
41.477 + }
41.478 +done: return errcode;
41.479 +}
41.480 +
41.481 +int CPXbaropt(CPXENV *env, CPXLP *lp)
41.482 +{ xassert(env == env);
41.483 + xassert(lp == lp);
41.484 + xprintf("CPXbaropt: not implemented yet\n");
41.485 + exit(EXIT_FAILURE);
41.486 + return -1;
41.487 +}
41.488 +
41.489 +int CPXbinvrow(CPXENV *env, CPXLP *lp, int i, double y[])
41.490 +{ xassert(env == env);
41.491 + xassert(lp == lp);
41.492 + xassert(i == i);
41.493 + xassert(y == y);
41.494 + xprintf("CPXbinvrow: not implemented yet\n");
41.495 + exit(EXIT_FAILURE);
41.496 + return -1;
41.497 +}
41.498 +
41.499 +int CPXchgbds(CPXENV *env, CPXLP *lp, int cnt, const int indices[],
41.500 + const char lu[], const double bd[])
41.501 +{ int j, n, type, errcode;
41.502 + double lbnd, ubnd;
41.503 + errcode = checklp(env, lp);
41.504 + if (errcode) goto done;
41.505 + if (cnt < 0)
41.506 + { errcode = error(env, CPXERR_BAD_ARGUMENT);
41.507 + goto done;
41.508 + }
41.509 + if (cnt > 0)
41.510 + { if (indices == NULL || lu == NULL || bd == NULL)
41.511 + { errcode = error(env, CPXERR_NULL_POINTER);
41.512 + goto done;
41.513 + }
41.514 + }
41.515 + n = glp_get_num_cols(lp->prob);
41.516 + for (j = 0; j < cnt; j++)
41.517 + { if (!(0 <= indices[j] && indices[j] < n))
41.518 + { errcode = error(env, CPXERR_COL_INDEX_RANGE, j);
41.519 + goto done;
41.520 + }
41.521 + if (!(lu[j] == 'L' || lu[j] == 'U' || lu[j] == 'B'))
41.522 + { errcode = error(env, CPXERR_BAD_LUB, j);
41.523 + goto done;
41.524 + }
41.525 + }
41.526 + errcode = 0;
41.527 + invalidate(lp);
41.528 + for (j = 0; j < cnt; j++)
41.529 + { type = glp_get_col_type(lp->prob, indices[j]+1);
41.530 + lbnd = glp_get_col_lb(lp->prob, indices[j]+1);
41.531 + ubnd = glp_get_col_ub(lp->prob, indices[j]+1);
41.532 + if (type == GLP_FR || type == GLP_UP)
41.533 + lbnd = -CPX_INFBOUND;
41.534 + if (type == GLP_FR || type == GLP_LO)
41.535 + ubnd = +CPX_INFBOUND;
41.536 + if (lu[j] == 'L')
41.537 + lbnd = bd[j];
41.538 + else if (lu[j] == 'U')
41.539 + ubnd = bd[j];
41.540 + else if (lu[j] == 'B')
41.541 + lbnd = ubnd = bd[j];
41.542 + else
41.543 + xassert(lu != lu);
41.544 + if (lbnd <= -CPX_INFBOUND && ubnd >= +CPX_INFBOUND)
41.545 + type = GLP_FR;
41.546 + else if (ubnd >= +CPX_INFBOUND)
41.547 + type = GLP_LO;
41.548 + else if (lbnd <= -CPX_INFBOUND)
41.549 + type = GLP_UP;
41.550 + else if (lbnd != ubnd)
41.551 + type = GLP_DB;
41.552 + else
41.553 + type = GLP_FX;
41.554 + glp_set_col_bnds(lp->prob, indices[j]+1, type, lbnd, ubnd);
41.555 + }
41.556 +done: return errcode;
41.557 +}
41.558 +
41.559 +int CPXchgcoeflist(CPXENV *env, CPXLP *lp, int numcoefs,
41.560 + const int rowlist[], const int collist[], const double vallist[])
41.561 +{ int i, j, k, m, n, rcnt, ccnt, len, ptr, errcode;
41.562 + int *head, *next, *ind;
41.563 + double *val;
41.564 + errcode = checklp(env, lp);
41.565 + if (errcode) goto done;
41.566 + if (numcoefs < 0)
41.567 + { errcode = error(env, CPXERR_BAD_ARGUMENT);
41.568 + goto done;
41.569 + }
41.570 + if (numcoefs == 0)
41.571 + { errcode = 0;
41.572 + goto done;
41.573 + }
41.574 + if (rowlist == NULL || collist == NULL || vallist == NULL)
41.575 + { errcode = error(env, CPXERR_NULL_POINTER);
41.576 + goto done;
41.577 + }
41.578 + /* check triplets and determine the number of rows and columns
41.579 + to be changed */
41.580 + m = glp_get_num_rows(lp->prob);
41.581 + n = glp_get_num_cols(lp->prob);
41.582 + enlargeiwork(lp, m);
41.583 + enlargeiwork(lp, n);
41.584 + rcnt = ccnt = 0;
41.585 + for (k = 0; k < numcoefs; k++)
41.586 + { i = rowlist[k];
41.587 + if (!(0 <= i && i < m))
41.588 + { errcode = error(env, CPXERR_ROW_INDEX_RANGE, i);
41.589 + goto done;
41.590 + }
41.591 + if (!(lp->iwork[i] & 0x01))
41.592 + rcnt++, lp->iwork[i] |= 0x01;
41.593 + j = collist[k];
41.594 + if (!(0 <= j && j < n))
41.595 + { errcode = error(env, CPXERR_COL_INDEX_RANGE, j);
41.596 + goto done;
41.597 + }
41.598 + if (!(lp->iwork[j] & 0x02))
41.599 + ccnt++, lp->iwork[j] |= 0x02;
41.600 + }
41.601 + memset(lp->iwork, 0, m * sizeof(int));
41.602 + memset(lp->iwork, 0, n * sizeof(int));
41.603 + errcode = 0;
41.604 + invalidate(lp);
41.605 + if (rcnt <= ccnt)
41.606 + { /* change the matrix by rows */
41.607 + /* build the linked list of triplets:
41.608 + head[i] is a pointer to first triplet for row i
41.609 + next[k] is a pointer to next triplet for the same row */
41.610 + head = xcalloc(m, sizeof(int));
41.611 + for (i = 0; i < m; i++)
41.612 + head[i] = -1;
41.613 + next = xcalloc(numcoefs, sizeof(int));
41.614 + for (k = 0; k < numcoefs; k++)
41.615 + { i = rowlist[k];
41.616 + next[k] = head[i];
41.617 + head[i] = k;
41.618 + }
41.619 + /* check duplicate columns */
41.620 + for (i = 0; i < m; i++)
41.621 + { for (k = head[i]; k >= 0; k = next[k])
41.622 + { j = collist[k];
41.623 + if (lp->iwork[j])
41.624 + { xfree(head);
41.625 + xfree(next);
41.626 + errcode = error(env, CPXERR_DUP_ENTRY);
41.627 + goto done;
41.628 + }
41.629 + lp->iwork[j] = 1;
41.630 + }
41.631 + for (k = head[i]; k >= 0; k = next[k])
41.632 + lp->iwork[collist[k]] = 0;
41.633 + }
41.634 + /* perform operation */
41.635 + ind = xcalloc(1+n, sizeof(int));
41.636 + val = xcalloc(1+n, sizeof(double));
41.637 + for (i = 0; i < m; i++)
41.638 + { if (head[i] < 0) continue;
41.639 + len = glp_get_mat_row(lp->prob, i+1, ind, val);
41.640 + for (ptr = 1; ptr <= len; ptr++)
41.641 + { j = ind[ptr]-1;
41.642 + xassert(lp->iwork[j] == 0);
41.643 + lp->iwork[j] = ptr;
41.644 + }
41.645 + for (k = head[i]; k >= 0; k = next[k])
41.646 + { j = collist[k];
41.647 + if (lp->iwork[j] == 0)
41.648 + lp->iwork[j] = ++len;
41.649 + ptr = lp->iwork[j];
41.650 + ind[ptr] = j+1, val[ptr] = vallist[k];
41.651 + }
41.652 + glp_set_mat_row(lp->prob, i+1, len, ind, val);
41.653 + for (ptr = 1; ptr <= len; ptr++)
41.654 + lp->iwork[ind[ptr]-1] = 0;
41.655 + }
41.656 + }
41.657 + else
41.658 + { /* change the matrix by columns */
41.659 + /* build the linked lists of triplets:
41.660 + head[j] is a pointer to first triplet for column j
41.661 + next[k] is a pointer to next triplet for the same column */
41.662 + head = xcalloc(n, sizeof(int));
41.663 + for (j = 0; j < n; j++)
41.664 + head[j] = -1;
41.665 + next = xcalloc(numcoefs, sizeof(int));
41.666 + for (k = 0; k < numcoefs; k++)
41.667 + { j = collist[k];
41.668 + next[k] = head[j];
41.669 + head[j] = k;
41.670 + }
41.671 + /* check duplicate rows */
41.672 + for (j = 0; j < n; j++)
41.673 + { for (k = head[j]; k >= 0; k = next[k])
41.674 + { i = rowlist[k];
41.675 + if (lp->iwork[i])
41.676 + { xfree(head);
41.677 + xfree(next);
41.678 + errcode = error(env, CPXERR_DUP_ENTRY);
41.679 + goto done;
41.680 + }
41.681 + lp->iwork[i] = 1;
41.682 + }
41.683 + for (k = head[j]; k >= 0; k = next[k])
41.684 + lp->iwork[rowlist[k]] = 0;
41.685 + }
41.686 + /* perform operation */
41.687 + ind = xcalloc(1+m, sizeof(int));
41.688 + val = xcalloc(1+m, sizeof(double));
41.689 + for (j = 0; j < n; j++)
41.690 + { if (head[j] < 0) continue;
41.691 + len = glp_get_mat_col(lp->prob, j+1, ind, val);
41.692 + for (ptr = 1; ptr <= len; ptr++)
41.693 + { i = ind[ptr]-1;
41.694 + xassert(lp->iwork[i] == 0);
41.695 + lp->iwork[i] = ptr;
41.696 + }
41.697 + for (k = head[j]; k >= 0; k = next[k])
41.698 + { i = rowlist[k];
41.699 + if (lp->iwork[i] == 0)
41.700 + lp->iwork[i] = ++len;
41.701 + ptr = lp->iwork[i];
41.702 + ind[ptr] = i+1, val[ptr] = vallist[k];
41.703 + }
41.704 + glp_set_mat_col(lp->prob, j+1, len, ind, val);
41.705 + for (ptr = 1; ptr <= len; ptr++)
41.706 + lp->iwork[ind[ptr]-1] = 0;
41.707 + }
41.708 + }
41.709 + xfree(head);
41.710 + xfree(next);
41.711 + xfree(ind);
41.712 + xfree(val);
41.713 +done: return errcode;
41.714 +}
41.715 +
41.716 +void CPXchgobjsen(CPXENV *env, CPXLP *lp, int maxormin)
41.717 +{ int errcode;
41.718 + errcode = checklp(env, lp);
41.719 + if (errcode) goto done;
41.720 + if (!(maxormin == CPX_MIN || maxormin == CPX_MAX))
41.721 + { errcode = error(env, CPXERR_BAD_ARGUMENT);
41.722 + goto done;
41.723 + }
41.724 + errcode = 0;
41.725 + invalidate(lp);
41.726 + if (maxormin == CPX_MIN)
41.727 + glp_set_obj_dir(lp->prob, GLP_MIN);
41.728 + else
41.729 + glp_set_obj_dir(lp->prob, GLP_MAX);
41.730 +done: xassert(errcode == errcode);
41.731 + return;
41.732 +}
41.733 +
41.734 +int CPXchgsense(CPXENV *env, CPXLP *lp, int cnt, const int indices[],
41.735 + const char sense[])
41.736 +{ int i, m, type, errcode;
41.737 + double rhs;
41.738 + errcode = checklp(env, lp);
41.739 + if (errcode) goto done;
41.740 + if (cnt < 0)
41.741 + { errcode = error(env, CPXERR_BAD_ARGUMENT);
41.742 + goto done;
41.743 + }
41.744 + if (cnt > 0 && (indices == NULL || sense == NULL))
41.745 + { errcode = error(env, CPXERR_NULL_POINTER);
41.746 + goto done;
41.747 + }
41.748 + m = glp_get_num_rows(lp->prob);
41.749 + for (i = 0; i < cnt; i++)
41.750 + { if (!(0 <= indices[i] && indices[i] < m))
41.751 + { errcode = error(env, CPXERR_ROW_INDEX_RANGE, i);
41.752 + goto done;
41.753 + }
41.754 + if (!(sense[i] == 'L' || sense[i] == 'E' || sense[i] == 'G' ||
41.755 + sense[i] == 'R'))
41.756 + { errcode = error(env, CPXERR_BAD_SENSE, i);
41.757 + goto done;
41.758 + }
41.759 + }
41.760 + errcode = 0;
41.761 + invalidate(lp);
41.762 + for (i = 0; i < cnt; i++)
41.763 + { type = glp_get_row_type(lp->prob, indices[i]+1);
41.764 + if (lp->rflag[indices[i]] == RF_NOT_RANGED)
41.765 + { if (type == GLP_LO || type == GLP_FX)
41.766 + rhs = glp_get_row_lb(lp->prob, indices[i]+1);
41.767 + else if (type == GLP_UP)
41.768 + rhs = glp_get_row_ub(lp->prob, indices[i]+1);
41.769 + else
41.770 + xassert(type != type);
41.771 + }
41.772 + else if (lp->rflag[indices[i]] == RF_RANGED_POS)
41.773 + { xassert(type == GLP_DB || type == GLP_FX);
41.774 + rhs = glp_get_row_lb(lp->prob, indices[i]+1);
41.775 + }
41.776 + else if (lp->rflag[indices[i]] == RF_RANGED_NEG)
41.777 + { xassert(type == GLP_DB);
41.778 + rhs = glp_get_row_ub(lp->prob, indices[i]+1);
41.779 + }
41.780 + else
41.781 + xassert(lp != lp);
41.782 + if (sense[i] == 'L')
41.783 + { lp->rflag[indices[i]] = RF_NOT_RANGED;
41.784 + type = GLP_UP;
41.785 + }
41.786 + else if (sense[i] == 'E')
41.787 + { lp->rflag[indices[i]] = RF_NOT_RANGED;
41.788 + type = GLP_FX;
41.789 + }
41.790 + else if (sense[i] == 'G')
41.791 + { lp->rflag[indices[i]] = RF_NOT_RANGED;
41.792 + type = GLP_LO;
41.793 + }
41.794 + else if (sense[i] == 'R')
41.795 + { lp->rflag[indices[i]] = RF_RANGED_POS;
41.796 + type = GLP_FX;
41.797 + }
41.798 + else
41.799 + xassert(sense != sense);
41.800 + glp_set_row_bnds(lp->prob, indices[i]+1, type, rhs, rhs);
41.801 + }
41.802 +done: return errcode;
41.803 +}
41.804 +
41.805 +int CPXcloseCPLEX(CPXENV **_env)
41.806 +{ CPXENV *env;
41.807 + CPXLP *lp;
41.808 + int errcode;
41.809 + if (_env == NULL)
41.810 + { errcode = CPXERR_NULL_POINTER;
41.811 + goto done;
41.812 + }
41.813 + env = *_env;
41.814 + errcode = checkenv(env);
41.815 + if (errcode) goto done;
41.816 + while (env->list != NULL)
41.817 + { lp = env->list;
41.818 + errcode = CPXfreeprob(env, &lp);
41.819 + xassert(!errcode);
41.820 + }
41.821 + xfree(env->intparam);
41.822 + xfree(env->dblparam);
41.823 + xfree(env);
41.824 + *_env = NULL;
41.825 + errcode = 0;
41.826 +done: return errcode;
41.827 +}
41.828 +
41.829 +int CPXcopybase(CPXENV *env, CPXLP *lp, const int cstat[],
41.830 + const int rstat[])
41.831 +{ int i, j, m, n, stat, errcode;
41.832 + errcode = checklp(env, lp);
41.833 + if (errcode) goto done;
41.834 + m = glp_get_num_rows(lp->prob);
41.835 + n = glp_get_num_cols(lp->prob);
41.836 + if (m > 0 && rstat == NULL || n > 0 && cstat == NULL)
41.837 + { errcode = error(env, CPXERR_NULL_POINTER);
41.838 + goto done;
41.839 + }
41.840 + for (i = 0; i < m; i++)
41.841 + { if (!(rstat[i] == CPX_AT_LOWER || rstat[i] == CPX_BASIC ||
41.842 + rstat[i] == CPX_AT_UPPER))
41.843 + { errcode = error(env, CPXERR_BAD_STATUS, i);
41.844 + goto done;
41.845 + }
41.846 + }
41.847 + for (j = 0; j < n; j++)
41.848 + { if (!(cstat[j] == CPX_AT_LOWER || cstat[j] == CPX_BASIC ||
41.849 + cstat[j] == CPX_AT_UPPER || cstat[j] == CPX_FREE_SUPER))
41.850 + { errcode = error(env, CPXERR_BAD_STATUS, j);
41.851 + goto done;
41.852 + }
41.853 + }
41.854 + errcode = 0;
41.855 + invalidate(lp);
41.856 + for (i = 0; i < m; i++)
41.857 + { if (rstat[i] == CPX_AT_LOWER)
41.858 + stat = GLP_NL;
41.859 + else if (rstat[i] == CPX_BASIC)
41.860 + stat = GLP_BS;
41.861 + else if (rstat[i] == CPX_AT_UPPER)
41.862 + stat = GLP_NU;
41.863 + else
41.864 + xassert(rstat != rstat);
41.865 + glp_set_row_stat(lp->prob, i+1, stat);
41.866 + }
41.867 + for (j = 0; j < n; j++)
41.868 + { if (cstat[j] == CPX_AT_LOWER)
41.869 + stat = GLP_NL;
41.870 + else if (cstat[j] == CPX_BASIC)
41.871 + stat = GLP_BS;
41.872 + else if (cstat[j] == CPX_AT_UPPER)
41.873 + stat = GLP_NU;
41.874 + else if (cstat[j] == CPX_FREE_SUPER)
41.875 + stat = GLP_NF;
41.876 + else
41.877 + xassert(cstat != cstat);
41.878 + glp_set_col_stat(lp->prob, j+1, stat);
41.879 + }
41.880 +done: return errcode;
41.881 +}
41.882 +
41.883 +int CPXcopybasednorms(CPXENV *env, CPXLP *lp, const int cstat[],
41.884 + const int rstat[], const double dnorm[])
41.885 +{ int errcode;
41.886 + errcode = CPXcopybase(env, lp, cstat, rstat);
41.887 + xassert(dnorm == dnorm);
41.888 + return errcode;
41.889 +}
41.890 +
41.891 +int CPXcopylp(CPXENV *env, CPXLP *lp, int numcols, int numrows,
41.892 + int objsen, const double obj[], const double rhs[],
41.893 + const char sense[], const int matbeg[], const int matcnt[],
41.894 + const int matind[], const double matval[], const double lb[],
41.895 + const double ub[], const double rngval[])
41.896 +{ int errcode;
41.897 + errcode = CPXcopylpwnames(env, lp, numcols, numrows, objsen, obj,
41.898 + rhs, sense, matbeg, matcnt, matind, matval, lb, ub, rngval,
41.899 + NULL, NULL);
41.900 + return errcode;
41.901 +}
41.902 +
41.903 +int CPXcopylpwnames(CPXENV *env, CPXLP *lp, int numcols, int numrows,
41.904 + int objsen, const double obj[], const double rhs[],
41.905 + const char sense[], const int matbeg[], const int matcnt[],
41.906 + const int matind[], const double matval[], const double lb[],
41.907 + const double ub[], const double rngval[], char *colname[],
41.908 + char *rowname[])
41.909 +{ int i, j, k, beg, end, type, errcode;
41.910 + double lbnd, ubnd;
41.911 + char name[255+1];
41.912 + errcode = checklp(env, lp);
41.913 + if (errcode) goto done;
41.914 + if (numcols < 0 || numrows < 0)
41.915 + { errcode = error(env, CPXERR_BAD_ARGUMENT);
41.916 + goto done;
41.917 + }
41.918 + if (!(objsen == CPX_MIN || objsen == CPX_MAX))
41.919 + { errcode = error(env, CPXERR_BAD_ARGUMENT);
41.920 + goto done;
41.921 + }
41.922 + if (numcols > 0)
41.923 + { if (matbeg == NULL || matcnt == NULL || matind == NULL ||
41.924 + matval == NULL)
41.925 + { errcode = error(env, CPXERR_NULL_POINTER);
41.926 + goto done;
41.927 + }
41.928 + }
41.929 + for (i = 0; i < numrows; i++)
41.930 + { if (sense != NULL)
41.931 + { if (!(sense[i] == 'L' || sense[i] == 'E' ||
41.932 + sense[i] == 'G' || sense[i] == 'R'))
41.933 + { errcode = error(env, CPXERR_BAD_SENSE, i);
41.934 + goto done;
41.935 + }
41.936 + }
41.937 + if (rowname != NULL)
41.938 + { if (rowname[i] == NULL)
41.939 + { errcode = error(env, CPXERR_NULL_NAME, i);
41.940 + goto done;
41.941 + }
41.942 + }
41.943 + }
41.944 + enlargeiwork(lp, numrows);
41.945 + for (j = 0; j < numcols; j++)
41.946 + { beg = matbeg[j];
41.947 + if (j > 0 && !(matbeg[j-1] <= beg))
41.948 + { errcode = error(env, CPXERR_ARRAY_NOT_ASCENDING, j);
41.949 + goto done;
41.950 + }
41.951 + if (beg < 0)
41.952 + { errcode = error(env, CPXERR_INDEX_RANGE);
41.953 + goto done;
41.954 + }
41.955 + end = beg + matcnt[j];
41.956 + if (!(beg <= end) || j < numcols-1 && !(end <= matbeg[j+1]))
41.957 + { errcode = error(env, CPXERR_COUNT_RANGE, j);
41.958 + goto done;
41.959 + }
41.960 + for (k = beg; k < end; k++)
41.961 + { if (!(0 <= matind[k] && matind[k] < numrows))
41.962 + { errcode = error(env, CPXERR_ROW_INDEX_RANGE, k);
41.963 + goto done;
41.964 + }
41.965 + }
41.966 + errcode = 0;
41.967 + for (k = beg; k < end; k++)
41.968 + { if (lp->iwork[matind[k]])
41.969 + { errcode = error(env, CPXERR_DUP_ENTRY);
41.970 + break;
41.971 + }
41.972 + lp->iwork[matind[k]] = 1;
41.973 + }
41.974 + for (k = beg; k < end; k++)
41.975 + lp->iwork[matind[k]] = 0;
41.976 + if (errcode) goto done;
41.977 + if (colname != NULL)
41.978 + { if (colname[j] != NULL)
41.979 + { errcode = error(env, CPXERR_NULL_NAME, j);
41.980 + goto done;
41.981 + }
41.982 + }
41.983 + }
41.984 + errcode = 0;
41.985 + invalidate(lp);
41.986 + if (glp_get_prob_name(lp->prob) == NULL)
41.987 + name[0] = '\0';
41.988 + else
41.989 + strcpy(name, glp_get_prob_name(lp->prob));
41.990 + glp_erase_prob(lp->prob);
41.991 + glp_set_prob_name(lp->prob, name);
41.992 + if (objsen == CPX_MIN)
41.993 + glp_set_obj_dir(lp->prob, GLP_MIN);
41.994 + else if (objsen == CPX_MAX)
41.995 + glp_set_obj_dir(lp->prob, GLP_MAX);
41.996 + else
41.997 + xassert(objsen != objsen);
41.998 + if (numrows > 0)
41.999 + glp_add_rows(lp->prob, numrows);
41.1000 + enlargerflag(lp);
41.1001 + for (i = 0; i < numrows; i++)
41.1002 + { if (rowname != NULL)
41.1003 + glp_set_row_name(lp->prob, i+1, rowname[i]);
41.1004 + lbnd = ubnd = (rhs == NULL ? 0.0 : rhs[i]);
41.1005 + if (sense == NULL || sense[i] == 'E')
41.1006 + { lp->rflag[i] = RF_NOT_RANGED;
41.1007 + type = GLP_FX;
41.1008 + }
41.1009 + else if (sense[i] == 'L')
41.1010 + { lp->rflag[i] = RF_NOT_RANGED;
41.1011 + type = GLP_UP;
41.1012 + }
41.1013 + else if (sense[i] == 'G')
41.1014 + { lp->rflag[i] = RF_NOT_RANGED;
41.1015 + type = GLP_LO;
41.1016 + }
41.1017 + else if (sense[i] == 'R')
41.1018 + { if (rngval == NULL || rngval[i] == 0.0)
41.1019 + { lp->rflag[i] = RF_RANGED_POS;
41.1020 + type = GLP_FX;
41.1021 + }
41.1022 + else if (rngval[i] > 0.0)
41.1023 + { lp->rflag[i] = RF_RANGED_POS;
41.1024 + type = GLP_DB;
41.1025 + ubnd += rngval[i];
41.1026 + }
41.1027 + else /* rngval[i] < 0.0 */
41.1028 + { lp->rflag[i] = RF_RANGED_NEG;
41.1029 + type = GLP_DB;
41.1030 + lbnd += rngval[i];
41.1031 + }
41.1032 + }
41.1033 + else
41.1034 + xassert(sense != sense);
41.1035 + glp_set_row_bnds(lp->prob, i+1, type, lbnd, ubnd);
41.1036 + }
41.1037 + if (numcols > 0)
41.1038 + glp_add_cols(lp->prob, numcols);
41.1039 + for (j = 0; j < numcols; j++)
41.1040 + { if (colname != NULL)
41.1041 + glp_set_col_name(lp->prob, j+1, colname[j]);
41.1042 + lbnd = (lb == NULL ? 0.0 : lb[j]);
41.1043 + ubnd = (ub == NULL ? +CPX_INFBOUND : ub[j]);
41.1044 + if (lbnd <= -CPX_INFBOUND && ubnd >= +CPX_INFBOUND)
41.1045 + type = GLP_FR;
41.1046 + else if (ubnd >= +CPX_INFBOUND)
41.1047 + type = GLP_LO;
41.1048 + else if (lbnd <= -CPX_INFBOUND)
41.1049 + type = GLP_UP;
41.1050 + else if (lbnd != ubnd)
41.1051 + type = GLP_DB;
41.1052 + else
41.1053 + type = GLP_FX;
41.1054 + glp_set_col_bnds(lp->prob, j+1, type, lbnd, ubnd);
41.1055 + if (obj != NULL)
41.1056 + glp_set_obj_coef(lp->prob, j+1, obj[j]);
41.1057 + beg = matbeg[j];
41.1058 + end = beg + matcnt[j];
41.1059 + for (k = beg; k < end; k++)
41.1060 + lp->iwork[k-beg] = matind[k]+1;
41.1061 + glp_set_mat_col(lp->prob, j+1, end-beg, lp->iwork-1,
41.1062 + matval+beg-1);
41.1063 + for (k = beg; k < end; k++)
41.1064 + lp->iwork[k-beg] = 0;
41.1065 + }
41.1066 +done: return errcode;
41.1067 +}
41.1068 +
41.1069 +CPXLP *CPXcreateprob(CPXENV *env, int *status, const char *probname)
41.1070 +{ CPXLP *lp = NULL;
41.1071 + int errcode;
41.1072 + errcode = checkenv(env);
41.1073 + if (errcode) goto done;
41.1074 + lp = xmalloc(sizeof(struct CPXLP));
41.1075 + lp->env = env;
41.1076 + lp->prob = glp_create_prob();
41.1077 + glp_set_prob_name(lp->prob, probname);
41.1078 + lp->rflen = 100;
41.1079 + lp->rflag = xcalloc(lp->rflen, sizeof(char));
41.1080 + lp->iwlen = 100;
41.1081 + lp->iwork = xcalloc(lp->iwlen, sizeof(int));
41.1082 + memset(lp->iwork, 0, lp->iwlen * sizeof(int));
41.1083 + lp->link = env->list;
41.1084 + env->list = lp;
41.1085 + invalidate(lp);
41.1086 +done: if (status != NULL) *status = errcode;
41.1087 + return lp;
41.1088 +}
41.1089 +
41.1090 +int CPXdelcols(CPXENV *env, CPXLP *lp, int begin, int end)
41.1091 +{ int j, n, errcode;
41.1092 + errcode = checklp(env, lp);
41.1093 + if (errcode) goto done;
41.1094 + n = glp_get_num_cols(lp->prob);
41.1095 + if (!(0 <= begin && begin <= end && end < n))
41.1096 + { errcode = error(env, CPXERR_INDEX_RANGE);
41.1097 + goto done;
41.1098 + }
41.1099 + errcode = 0;
41.1100 + invalidate(lp);
41.1101 + enlargeiwork(lp, end-begin+1);
41.1102 + for (j = begin; j <= end; j++)
41.1103 + lp->iwork[j-begin] = j+1;
41.1104 + glp_del_cols(lp->prob, end-begin+1, lp->iwork-1);
41.1105 + for (j = begin; j <= end; j++)
41.1106 + lp->iwork[j-begin] = 0;
41.1107 +done: return errcode;
41.1108 +}
41.1109 +
41.1110 +int CPXdelrows(CPXENV *env, CPXLP *lp, int begin, int end)
41.1111 +{ int i, m, errcode;
41.1112 + errcode = checklp(env, lp);
41.1113 + if (errcode) goto done;
41.1114 + m = glp_get_num_rows(lp->prob);
41.1115 + if (!(0 <= begin && begin <= end && end < m))
41.1116 + { errcode = error(env, CPXERR_INDEX_RANGE);
41.1117 + goto done;
41.1118 + }
41.1119 + errcode = 0;
41.1120 + invalidate(lp);
41.1121 + enlargeiwork(lp, end-begin+1);
41.1122 + for (i = begin; i <= end; i++)
41.1123 + lp->iwork[i-begin] = i+1;
41.1124 + glp_del_rows(lp->prob, end-begin+1, lp->iwork-1);
41.1125 + for (i = begin; i <= end; i++)
41.1126 + lp->iwork[i-begin] = 0;
41.1127 + for (i = end+1; i < m; i++)
41.1128 + lp->rflag[i-(end-begin+1)] = lp->rflag[i];
41.1129 +done: return errcode;
41.1130 +}
41.1131 +
41.1132 +int CPXdelsetcols(CPXENV *env, CPXLP *lp, int delstat[])
41.1133 +{ xassert(env == env);
41.1134 + xassert(lp == lp);
41.1135 + xassert(delstat == delstat);
41.1136 + xprintf("CPXdelsetcols: not implemented yet\n");
41.1137 + exit(EXIT_FAILURE);
41.1138 + return -1;
41.1139 +}
41.1140 +
41.1141 +int CPXdelsetrows(CPXENV *env, CPXLP *lp, int delstat[])
41.1142 +{ int i, m, cnt, ind, errcode;
41.1143 + errcode = checklp(env, lp);
41.1144 + if (errcode) goto done;
41.1145 + m = glp_get_num_rows(lp->prob);
41.1146 + if (m > 0 && delstat == NULL)
41.1147 + { errcode = error(env, CPXERR_NULL_POINTER);
41.1148 + goto done;
41.1149 + }
41.1150 + errcode = 0;
41.1151 + invalidate(lp);
41.1152 + enlargeiwork(lp, m);
41.1153 + cnt = ind = 0;
41.1154 + for (i = 0; i < m; i++)
41.1155 + { if (delstat[i] == 1)
41.1156 + { delstat[i] = -1;
41.1157 + lp->iwork[cnt++] = i+1;
41.1158 + }
41.1159 + else
41.1160 + { delstat[i] = ind;
41.1161 + lp->rflag[ind++] = lp->rflag[i];
41.1162 + }
41.1163 + }
41.1164 + if (cnt > 0)
41.1165 + glp_del_rows(lp->prob, cnt, lp->iwork-1);
41.1166 + for (i = 0; i < cnt; i++)
41.1167 + lp->iwork[i] = 0;
41.1168 +done: return errcode;
41.1169 +}
41.1170 +
41.1171 +int CPXdualopt(CPXENV *env, CPXLP *lp);
41.1172 +
41.1173 +int CPXfreeprob(CPXENV *env, CPXLP **_lp)
41.1174 +{ CPXLP *lp;
41.1175 + int errcode;
41.1176 + errcode = checkenv(env);
41.1177 + if (errcode) goto done;
41.1178 + if (_lp == NULL)
41.1179 + { errcode = error(env, CPXERR_NULL_POINTER);
41.1180 + goto done;
41.1181 + }
41.1182 + lp = *_lp;
41.1183 + errcode = checklp(env, lp);
41.1184 + if (errcode) goto done;
41.1185 + errcode = 0;
41.1186 + env = lp->env;
41.1187 + if (env->list == lp)
41.1188 + env->list = lp->link;
41.1189 + else
41.1190 + { CPXLP *pp;
41.1191 + for (pp = env->list; pp != NULL; pp = pp->link)
41.1192 + if (pp->link == lp) break;
41.1193 + xassert(pp != NULL);
41.1194 + pp->link = lp->link;
41.1195 + }
41.1196 + glp_delete_prob(lp->prob);
41.1197 + xfree(lp->rflag);
41.1198 + xfree(lp->iwork);
41.1199 + xfree(lp);
41.1200 + *_lp = NULL;
41.1201 +done: return errcode;
41.1202 +}
41.1203 +
41.1204 +int CPXgetbase(CPXENV *env, CPXLP *lp, int cstat[], int rstat[])
41.1205 +{ int i, j, m, n, stat, errcode;
41.1206 + errcode = checklp(env, lp);
41.1207 + if (errcode) goto done;
41.1208 + if (!lp->stat)
41.1209 + { errcode = error(env, CPXERR_NO_SOLN);
41.1210 + goto done;
41.1211 + }
41.1212 + if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
41.1213 + ;
41.1214 + else
41.1215 + { errcode = error(env, CPXERR_NO_BASIC_SOLN);
41.1216 + goto done;
41.1217 + }
41.1218 + errcode = 0;
41.1219 + if (rstat != NULL)
41.1220 + { m = glp_get_num_rows(lp->prob);
41.1221 + for (i = 0; i < m; i++)
41.1222 + { stat = glp_get_row_stat(lp->prob, i+1);
41.1223 + if (stat == GLP_BS)
41.1224 + rstat[i] = CPX_BASIC;
41.1225 + else if (lp->rflag[i] == RF_NOT_RANGED || stat != GLP_NU)
41.1226 + rstat[i] = CPX_AT_LOWER;
41.1227 + else
41.1228 + rstat[i] = CPX_AT_UPPER;
41.1229 + }
41.1230 + }
41.1231 + if (cstat != NULL)
41.1232 + { n = glp_get_num_cols(lp->prob);
41.1233 + for (j = 0; j < n; j++)
41.1234 + { stat = glp_get_col_stat(lp->prob, j+1);
41.1235 + if (stat == GLP_BS)
41.1236 + cstat[j] = CPX_BASIC;
41.1237 + else if (stat == GLP_NU)
41.1238 + cstat[j] = CPX_AT_UPPER;
41.1239 + else if (stat == GLP_NF)
41.1240 + cstat[j] = CPX_FREE_SUPER;
41.1241 + else
41.1242 + cstat[j] = CPX_AT_LOWER;
41.1243 + }
41.1244 + }
41.1245 +done: return errcode;
41.1246 +}
41.1247 +
41.1248 +int CPXgetbasednorms(CPXENV *env, CPXLP *lp, int cstat[], int rstat[],
41.1249 + double dnorm[])
41.1250 +{ int i, m, errcode;
41.1251 + errcode = CPXgetbase(env, lp, cstat, rstat);
41.1252 + if (errcode) goto done;
41.1253 + if (dnorm != NULL)
41.1254 + { m = glp_get_num_rows(lp->prob);
41.1255 + for (i = 0; i < m; i++) dnorm[i] = 1.0;
41.1256 + }
41.1257 +done: return errcode;
41.1258 +}
41.1259 +
41.1260 +int CPXgetbhead(CPXENV *env, CPXLP *lp, int head[], double x[])
41.1261 +{ xassert(env == env);
41.1262 + xassert(lp == lp);
41.1263 + xassert(head == head);
41.1264 + xassert(x == x);
41.1265 + xprintf("CPXgetbhead: not implemented yet\n");
41.1266 + exit(EXIT_FAILURE);
41.1267 + return -1;
41.1268 +}
41.1269 +
41.1270 +int CPXgetdblparam(CPXENV *env, int whichparam, double *value)
41.1271 +{ int k, errcode;
41.1272 + errcode = checkenv(env);
41.1273 + if (errcode) goto done;
41.1274 + k = finddblparam(whichparam);
41.1275 + if (k < 0)
41.1276 + { errcode = error(env, CPXERR_BAD_PARAM_NUM);
41.1277 + goto done;
41.1278 + }
41.1279 + errcode = 0;
41.1280 + if (value != NULL)
41.1281 + *value = env->dblparam[k];
41.1282 +done: return errcode;
41.1283 +}
41.1284 +
41.1285 +int CPXgetdj(CPXENV *env, CPXLP *lp, double dj[], int begin, int end)
41.1286 +{ int j, n, errcode;
41.1287 + errcode = checklp(env, lp);
41.1288 + if (errcode) goto done;
41.1289 + n = glp_get_num_cols(lp->prob);
41.1290 + if (!(0 <= begin && begin <= end && end < n))
41.1291 + { errcode = error(env, CPXERR_INDEX_RANGE);
41.1292 + goto done;
41.1293 + }
41.1294 + if (!lp->stat)
41.1295 + { errcode = error(env, CPXERR_NO_SOLN);
41.1296 + goto done;
41.1297 + }
41.1298 + errcode = 0;
41.1299 + if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
41.1300 + { if (dj != NULL)
41.1301 + { for (j = begin; j <= end; j++)
41.1302 + dj[j-begin] = glp_get_col_dual(lp->prob, j+1);
41.1303 + }
41.1304 + }
41.1305 + else
41.1306 + xassert(lp != lp);
41.1307 +done: return errcode;
41.1308 +}
41.1309 +
41.1310 +char *CPXgeterrorstring(CPXENV *env, int errcode, char *buffer)
41.1311 +{ const char *string;
41.1312 + xassert(env == env);
41.1313 + string = finderrstring(errcode);
41.1314 + if (string == NULL)
41.1315 + buffer = NULL;
41.1316 + else
41.1317 + sprintf(buffer, "CPLEX Error %5d: %s.\n", errcode, string);
41.1318 + return buffer;
41.1319 +}
41.1320 +
41.1321 +int CPXgetijdiv(CPXENV *env, CPXLP *lp, int *idiv, int *jdiv)
41.1322 +{ xassert(env == env);
41.1323 + xassert(lp == lp);
41.1324 + xassert(idiv == idiv);
41.1325 + xassert(jdiv == jdiv);
41.1326 + xprintf("CPXgetijdiv: not implemented yet\n");
41.1327 + exit(EXIT_FAILURE);
41.1328 + return -1;
41.1329 +}
41.1330 +
41.1331 +int CPXgetintparam(CPXENV *env, int whichparam, int *value)
41.1332 +{ int k, errcode;
41.1333 + errcode = checkenv(env);
41.1334 + if (errcode) goto done;
41.1335 + k = findintparam(whichparam);
41.1336 + if (k < 0)
41.1337 + { errcode = error(env, CPXERR_BAD_PARAM_NUM);
41.1338 + goto done;
41.1339 + }
41.1340 + errcode = 0;
41.1341 + if (value != NULL)
41.1342 + *value = env->intparam[k];
41.1343 +done: return errcode;
41.1344 +}
41.1345 +
41.1346 +int CPXgetlb(CPXENV *env, CPXLP *lp, double lb[], int begin, int end)
41.1347 +{ xassert(env == env);
41.1348 + xassert(lp == lp);
41.1349 + xassert(lb == lb);
41.1350 + xassert(begin == begin);
41.1351 + xassert(end == end);
41.1352 + xprintf("CPXgetlb: not implemented yet\n");
41.1353 + exit(EXIT_FAILURE);
41.1354 + return -1;
41.1355 +}
41.1356 +
41.1357 +int CPXgetmethod(CPXENV *env, CPXLP *lp)
41.1358 +{ int method;
41.1359 + if (checklp(env, lp))
41.1360 + method = CPX_ALG_NONE;
41.1361 + else
41.1362 + method = lp->meth;
41.1363 + return method;
41.1364 +}
41.1365 +
41.1366 +int CPXgetnumcols(CPXENV *env, CPXLP *lp)
41.1367 +{ int numcols;
41.1368 + if (checklp(env, lp))
41.1369 + numcols = 0;
41.1370 + else
41.1371 + numcols = glp_get_num_cols(lp->prob);
41.1372 + return numcols;
41.1373 +}
41.1374 +
41.1375 +int CPXgetnumnz(CPXENV *env, CPXLP *lp)
41.1376 +{ int numnz;
41.1377 + if (checklp(env, lp))
41.1378 + numnz = 0;
41.1379 + else
41.1380 + numnz = glp_get_num_nz(lp->prob);
41.1381 + return numnz;
41.1382 +}
41.1383 +
41.1384 +int CPXgetnumrows(CPXENV *env, CPXLP *lp)
41.1385 +{ int numrows;
41.1386 + if (checklp(env, lp))
41.1387 + numrows = 0;
41.1388 + else
41.1389 + numrows = glp_get_num_rows(lp->prob);
41.1390 + return numrows;
41.1391 +}
41.1392 +
41.1393 +int CPXgetobjval(CPXENV *env, CPXLP *lp, double *objval)
41.1394 +{ int errcode;
41.1395 + errcode = checklp(env, lp);
41.1396 + if (errcode) goto done;
41.1397 + if (!lp->stat)
41.1398 + { errcode = error(env, CPXERR_NO_SOLN);
41.1399 + goto done;
41.1400 + }
41.1401 + errcode = 0;
41.1402 + if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
41.1403 + { if (objval != NULL)
41.1404 + *objval = glp_get_obj_val(lp->prob);
41.1405 + }
41.1406 + else
41.1407 + xassert(lp != lp);
41.1408 +done: return errcode;
41.1409 +}
41.1410 +
41.1411 +int CPXgetpi(CPXENV *env, CPXLP *lp, double pi[], int begin, int end)
41.1412 +{ int i, m, errcode;
41.1413 + errcode = checklp(env, lp);
41.1414 + if (errcode) goto done;
41.1415 + m = glp_get_num_rows(lp->prob);
41.1416 + if (!(0 <= begin && begin <= end && end < m))
41.1417 + { errcode = error(env, CPXERR_INDEX_RANGE);
41.1418 + goto done;
41.1419 + }
41.1420 + if (!lp->stat)
41.1421 + { errcode = error(env, CPXERR_NO_SOLN);
41.1422 + goto done;
41.1423 + }
41.1424 + errcode = 0;
41.1425 + if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
41.1426 + { if (pi != NULL)
41.1427 + { for (i = begin; i <= end; i++)
41.1428 + pi[i-begin] = glp_get_row_dual(lp->prob, i+1);
41.1429 + }
41.1430 + }
41.1431 + else
41.1432 + xassert(lp != lp);
41.1433 +done: return errcode;
41.1434 +}
41.1435 +
41.1436 +int CPXgetsense(CPXENV *env, CPXLP *lp, char sense[], int begin,
41.1437 + int end)
41.1438 +{ xassert(env == env);
41.1439 + xassert(lp == lp);
41.1440 + xassert(sense == sense);
41.1441 + xassert(begin == begin);
41.1442 + xassert(end == end);
41.1443 + xprintf("CPXgetsense: not implemented yet\n");
41.1444 + exit(EXIT_FAILURE);
41.1445 + return -1;
41.1446 +}
41.1447 +
41.1448 +int CPXgetslack(CPXENV *env, CPXLP *lp, double slack[], int begin,
41.1449 + int end)
41.1450 +{ int i, m, type, errcode;
41.1451 + double temp;
41.1452 + errcode = checklp(env, lp);
41.1453 + if (errcode) goto done;
41.1454 + m = glp_get_num_rows(lp->prob);
41.1455 + if (!(0 <= begin && begin <= end && end < m))
41.1456 + { errcode = error(env, CPXERR_INDEX_RANGE);
41.1457 + goto done;
41.1458 + }
41.1459 + if (!lp->stat)
41.1460 + { errcode = error(env, CPXERR_NO_SOLN);
41.1461 + goto done;
41.1462 + }
41.1463 + errcode = 0;
41.1464 + if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
41.1465 + { if (slack != NULL)
41.1466 + { for (i = begin; i <= end; i++)
41.1467 + { type = glp_get_row_type(lp->prob, i+1);
41.1468 + temp = glp_get_row_prim(lp->prob, i+1);
41.1469 + if (lp->rflag[i] == RF_NOT_RANGED)
41.1470 + { if (type == GLP_LO || type == GLP_FX)
41.1471 + slack[i-begin] =
41.1472 + glp_get_row_lb(lp->prob, i+1) - temp;
41.1473 + else if (type == GLP_UP)
41.1474 + slack[i-begin] =
41.1475 + glp_get_row_ub(lp->prob, i+1) - temp;
41.1476 + else
41.1477 + xassert(type != type);
41.1478 + }
41.1479 + else if (lp->rflag[i] == RF_RANGED_POS)
41.1480 + { xassert(type == GLP_DB || type == GLP_FX);
41.1481 + slack[i-begin] =
41.1482 + temp - glp_get_row_lb(lp->prob, i+1);
41.1483 + }
41.1484 + else if (lp->rflag[i] == RF_RANGED_NEG)
41.1485 + { xassert(type == GLP_DB);
41.1486 + slack[i-begin] =
41.1487 + temp - glp_get_row_ub(lp->prob, i+1);
41.1488 + }
41.1489 + else
41.1490 + xassert(lp != lp);
41.1491 + }
41.1492 + }
41.1493 + }
41.1494 + else
41.1495 + xassert(lp != lp);
41.1496 +done: return errcode;
41.1497 +}
41.1498 +
41.1499 +int CPXgetstat(CPXENV *env, CPXLP *lp)
41.1500 +{ int stat;
41.1501 + if (checklp(env, lp))
41.1502 + stat = 0;
41.1503 + else
41.1504 + stat = lp->stat;
41.1505 + return stat;
41.1506 +}
41.1507 +
41.1508 +int CPXgetub(CPXENV *env, CPXLP *lp, double ub[], int begin, int end)
41.1509 +{ xassert(env == env);
41.1510 + xassert(lp == lp);
41.1511 + xassert(ub == ub);
41.1512 + xassert(begin == begin);
41.1513 + xassert(end == end);
41.1514 + xprintf("CPXgetub: not implemented yet\n");
41.1515 + exit(EXIT_FAILURE);
41.1516 + return -1;
41.1517 +}
41.1518 +
41.1519 +int CPXgetweight(CPXENV *env, CPXLP *lp, int rcnt, const int rmatbeg[],
41.1520 + const int rmatind[], const double rmatval[], double weight[],
41.1521 + int dpriind)
41.1522 +{ xassert(env == env);
41.1523 + xassert(lp == lp);
41.1524 + xassert(rcnt == rcnt);
41.1525 + xassert(rmatbeg == rmatbeg);
41.1526 + xassert(rmatind == rmatind);
41.1527 + xassert(rmatval == rmatval);
41.1528 + xassert(weight == weight);
41.1529 + xassert(dpriind == dpriind);
41.1530 + xprintf("CPXgetweight: not implemented yet\n");
41.1531 + exit(EXIT_FAILURE);
41.1532 + return -1;
41.1533 +}
41.1534 +
41.1535 +int CPXgetx(CPXENV *env, CPXLP *lp, double x[], int begin, int end)
41.1536 +{ int j, n, errcode;
41.1537 + errcode = checklp(env, lp);
41.1538 + if (errcode) goto done;
41.1539 + n = glp_get_num_cols(lp->prob);
41.1540 + if (!(0 <= begin && begin <= end && end < n))
41.1541 + { errcode = error(env, CPXERR_INDEX_RANGE);
41.1542 + goto done;
41.1543 + }
41.1544 + if (!lp->stat)
41.1545 + { errcode = error(env, CPXERR_NO_SOLN);
41.1546 + goto done;
41.1547 + }
41.1548 + errcode = 0;
41.1549 + if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
41.1550 + { if (x != NULL)
41.1551 + { for (j = begin; j <= end; j++)
41.1552 + x[j-begin] = glp_get_col_prim(lp->prob, j+1);
41.1553 + }
41.1554 + }
41.1555 + else
41.1556 + xassert(lp != lp);
41.1557 +done: return errcode;
41.1558 +}
41.1559 +
41.1560 +int CPXinfodblparam(CPXENV *env, int whichparam, double *defvalue,
41.1561 + double *minvalue, double *maxvalue)
41.1562 +{ int k, errcode;
41.1563 + errcode = checkenv(env);
41.1564 + if (errcode) goto done;
41.1565 + k = finddblparam(whichparam);
41.1566 + if (k < 0)
41.1567 + { errcode = error(env, CPXERR_BAD_PARAM_NUM);
41.1568 + goto done;
41.1569 + }
41.1570 + errcode = 0;
41.1571 + if (defvalue != NULL)
41.1572 + *defvalue = dblparam[k].defv;
41.1573 + if (minvalue != NULL)
41.1574 + *minvalue = dblparam[k].minv;
41.1575 + if (maxvalue != NULL)
41.1576 + *maxvalue = dblparam[k].maxv;
41.1577 +done: return errcode;
41.1578 +}
41.1579 +
41.1580 +int CPXinfointparam(CPXENV *env, int whichparam, int *defvalue,
41.1581 + int *minvalue, int *maxvalue)
41.1582 +{ int k, errcode;
41.1583 + errcode = checkenv(env);
41.1584 + if (errcode) goto done;
41.1585 + k = findintparam(whichparam);
41.1586 + if (k < 0)
41.1587 + { errcode = error(env, CPXERR_BAD_PARAM_NUM);
41.1588 + goto done;
41.1589 + }
41.1590 + errcode = 0;
41.1591 + if (defvalue != NULL)
41.1592 + *defvalue = intparam[k].defv;
41.1593 + if (minvalue != NULL)
41.1594 + *minvalue = intparam[k].minv;
41.1595 + if (maxvalue != NULL)
41.1596 + *maxvalue = intparam[k].maxv;
41.1597 +done: return errcode;
41.1598 +}
41.1599 +
41.1600 +int CPXmdleave(const CPXENV *env, CPXLP *lp, const int goodlist[],
41.1601 + int goodlen, double downratio[], double upratio[])
41.1602 +{ int k;
41.1603 + xassert(env == env);
41.1604 + xassert(lp == lp);
41.1605 + xassert(goodlist == goodlist);
41.1606 + xassert(goodlen >= 0);
41.1607 + xassert(downratio != NULL);
41.1608 + xassert(upratio != NULL);
41.1609 + /* not implemented yet */
41.1610 + for (k = 0; k < goodlen; k++)
41.1611 + downratio[k] = upratio[k] = 0.0;
41.1612 + return 0;
41.1613 +}
41.1614 +
41.1615 +int CPXnewcols(CPXENV *env, CPXLP *lp, int ccnt, const double obj[],
41.1616 + const double lb[], const double ub[], const char ctype[],
41.1617 + char *colname[])
41.1618 +{ int j, n, kind, type, errcode;
41.1619 + double lbnd, ubnd;
41.1620 + errcode = checklp(env, lp);
41.1621 + if (errcode) goto done;
41.1622 + if (ccnt < 0)
41.1623 + { errcode = error(env, CPXERR_BAD_ARGUMENT);
41.1624 + goto done;
41.1625 + }
41.1626 + for (j = 0; j < ccnt; j++)
41.1627 + { if (ctype != NULL)
41.1628 + { if (!(ctype[j] == 'C' || ctype[j] == 'B' ||
41.1629 + ctype[j] == 'I'))
41.1630 + { errcode = error(env, CPXERR_BAD_CTYPE, j);
41.1631 + goto done;
41.1632 + }
41.1633 + }
41.1634 + if (colname != NULL)
41.1635 + { if (colname[j] == NULL)
41.1636 + { errcode = error(env, CPXERR_NULL_NAME, j);
41.1637 + goto done;
41.1638 + }
41.1639 + }
41.1640 + }
41.1641 + errcode = 0;
41.1642 + invalidate(lp);
41.1643 + n = glp_get_num_cols(lp->prob);
41.1644 + if (ccnt > 0)
41.1645 + glp_add_cols(lp->prob, ccnt);
41.1646 + for (j = 0; j < ccnt; j++)
41.1647 + { if (colname != NULL)
41.1648 + glp_set_col_name(lp->prob, n+j+1, colname[j]);
41.1649 + if (obj != NULL)
41.1650 + glp_set_obj_coef(lp->prob, n+j+1, obj[j]);
41.1651 + lbnd = (lb == NULL ? 0.0 : lb[j]);
41.1652 + ubnd = (ub == NULL ? 0.0 : ub[j]);
41.1653 + if (lbnd <= -CPX_INFBOUND && ubnd >= +CPX_INFBOUND)
41.1654 + type = GLP_FR;
41.1655 + else if (ubnd >= +CPX_INFBOUND)
41.1656 + type = GLP_LO;
41.1657 + else if (lbnd <= -CPX_INFBOUND)
41.1658 + type = GLP_UP;
41.1659 + else if (lbnd != ubnd)
41.1660 + type = GLP_DB;
41.1661 + else
41.1662 + type = GLP_FX;
41.1663 + glp_set_col_bnds(lp->prob, n+j+1, type, lbnd, ubnd);
41.1664 + if (ctype != NULL)
41.1665 + { if (ctype[j] == 'C')
41.1666 + kind = GLP_CV;
41.1667 + else if (ctype[j] == 'B')
41.1668 + kind = GLP_BV;
41.1669 + else if (ctype[j] == 'I')
41.1670 + kind = GLP_IV;
41.1671 + else
41.1672 + xassert(ctype != ctype);
41.1673 + glp_set_col_kind(lp->prob, n+j+1, kind);
41.1674 + }
41.1675 + }
41.1676 +done: return errcode;
41.1677 +}
41.1678 +
41.1679 +int CPXnewrows(CPXENV *env, CPXLP *lp, int rcnt, const double rhs[],
41.1680 + const char sense[], const double rngval[], char *rowname[])
41.1681 +{ int i, m, type, errcode;
41.1682 + double lbnd, ubnd;
41.1683 + errcode = checklp(env, lp);
41.1684 + if (errcode) goto done;
41.1685 + if (rcnt < 0)
41.1686 + { errcode = error(env, CPXERR_BAD_ARGUMENT);
41.1687 + goto done;
41.1688 + }
41.1689 + for (i = 0; i < rcnt; i++)
41.1690 + { if (sense != NULL)
41.1691 + { if (!(sense[i] == 'L' || sense[i] == 'E' ||
41.1692 + sense[i] == 'G' || sense[i] == 'R'))
41.1693 + { errcode = error(env, CPXERR_BAD_SENSE, i);
41.1694 + goto done;
41.1695 + }
41.1696 + }
41.1697 + if (rowname != NULL)
41.1698 + { if (rowname[i] == NULL)
41.1699 + { errcode = error(env, CPXERR_NULL_NAME, i);
41.1700 + goto done;
41.1701 + }
41.1702 + }
41.1703 + }
41.1704 + errcode = 0;
41.1705 + invalidate(lp);
41.1706 + m = glp_get_num_rows(lp->prob);
41.1707 + if (rcnt > 0)
41.1708 + glp_add_rows(lp->prob, rcnt);
41.1709 + enlargerflag(lp);
41.1710 + for (i = 0; i < rcnt; i++)
41.1711 + { if (rowname != NULL)
41.1712 + glp_set_row_name(lp->prob, m+i+1, rowname[i]);
41.1713 + lbnd = ubnd = (rhs == NULL ? 0.0 : rhs[i]);
41.1714 + if (sense == NULL || sense[i] == 'E')
41.1715 + { lp->rflag[m+i] = RF_NOT_RANGED;
41.1716 + type = GLP_FX;
41.1717 + }
41.1718 + else if (sense[i] == 'L')
41.1719 + { lp->rflag[m+i] = RF_NOT_RANGED;
41.1720 + type = GLP_UP;
41.1721 + }
41.1722 + else if (sense[i] == 'G')
41.1723 + { lp->rflag[m+i] = RF_NOT_RANGED;
41.1724 + type = GLP_LO;
41.1725 + }
41.1726 + else if (sense[i] == 'R')
41.1727 + { if (rngval == NULL || rngval[i] == 0.0)
41.1728 + { lp->rflag[m+i] = RF_RANGED_POS;
41.1729 + type = GLP_FX;
41.1730 + }
41.1731 + else if (rngval[i] > 0.0)
41.1732 + { lp->rflag[m+i] = RF_RANGED_POS;
41.1733 + type = GLP_DB;
41.1734 + ubnd += rngval[i];
41.1735 + }
41.1736 + else /* rngval[i] < 0.0 */
41.1737 + { lp->rflag[m+i] = RF_RANGED_NEG;
41.1738 + type = GLP_DB;
41.1739 + lbnd += rngval[i];
41.1740 + }
41.1741 + }
41.1742 + else
41.1743 + xassert(sense != sense);
41.1744 + glp_set_row_bnds(lp->prob, m+i+1, type, lbnd, ubnd);
41.1745 + }
41.1746 +done: return errcode;
41.1747 +}
41.1748 +
41.1749 +CPXENV *CPXopenCPLEX(int *status)
41.1750 +{ CPXENV *env;
41.1751 + int k, card;
41.1752 + env = xmalloc(sizeof(CPXENV));
41.1753 + env->list = NULL;
41.1754 + card = sizeof(intparam) / sizeof(struct intparam);
41.1755 + env->intparam = xcalloc(card, sizeof(int));
41.1756 + for (k = 0; k < card; k++)
41.1757 + env->intparam[k] = intparam[k].defv;
41.1758 + card = sizeof(dblparam) / sizeof(struct dblparam);
41.1759 + env->dblparam = xcalloc(card, sizeof(double));
41.1760 + for (k = 0; k < card; k++)
41.1761 + env->dblparam[k] = dblparam[k].defv;
41.1762 + if (status != NULL) *status = 0;
41.1763 + return env;
41.1764 +}
41.1765 +
41.1766 +int CPXpivotin(CPXENV *env, CPXLP *lp, const int rlist[], int rlen)
41.1767 +{ int i, m, errcode;
41.1768 + errcode = checklp(env, lp);
41.1769 + if (errcode) goto done;
41.1770 + if (rlen < 0)
41.1771 + { errcode = error(env, CPXERR_BAD_ARGUMENT);
41.1772 + goto done;
41.1773 + }
41.1774 + if (rlen > 0 && rlist == NULL)
41.1775 + { errcode = error(env, CPXERR_NULL_POINTER);
41.1776 + goto done;
41.1777 + }
41.1778 + m = glp_get_num_rows(lp->prob);
41.1779 + for (i = 0; i < rlen; i++)
41.1780 + { if (!(0 <= rlist[i] && rlist[i] < m))
41.1781 + { errcode = error(env, CPXERR_ROW_INDEX_RANGE, i);
41.1782 + goto done;
41.1783 + }
41.1784 + }
41.1785 + errcode = 0;
41.1786 + for (i = 0; i < rlen; i++)
41.1787 + { if (glp_get_row_type(lp->prob, rlist[i]+1) != GLP_FX)
41.1788 + { if (glp_get_row_stat(lp->prob, rlist[i]+1) != GLP_BS)
41.1789 + { /* not implemented yet */
41.1790 + break;
41.1791 + }
41.1792 + }
41.1793 + }
41.1794 +done: return errcode;
41.1795 +}
41.1796 +
41.1797 +int CPXpivotout(CPXENV *env, CPXLP *lp, const int clist[], int clen)
41.1798 +{ int j, n, errcode;
41.1799 + errcode = checklp(env, lp);
41.1800 + if (errcode) goto done;
41.1801 + if (clen < 0)
41.1802 + { errcode = error(env, CPXERR_BAD_ARGUMENT);
41.1803 + goto done;
41.1804 + }
41.1805 + if (clen > 0 && clist == NULL)
41.1806 + { errcode = error(env, CPXERR_NULL_POINTER);
41.1807 + goto done;
41.1808 + }
41.1809 + n = glp_get_num_cols(lp->prob);
41.1810 + for (j = 0; j < clen; j++)
41.1811 + { if (!(0 <= clist[j] && clist[j] < n))
41.1812 + { errcode = error(env, CPXERR_COL_INDEX_RANGE, j);
41.1813 + goto done;
41.1814 + }
41.1815 + if (glp_get_col_type(lp->prob, clist[j]+1) != GLP_FX)
41.1816 + { errcode = error(env, CPXERR_NOT_FIXED);
41.1817 + goto done;
41.1818 + }
41.1819 + }
41.1820 + errcode = 0;
41.1821 + for (j = 0; j < clen; j++)
41.1822 + { if (glp_get_col_stat(lp->prob, clist[j]+1) == GLP_BS)
41.1823 + { /* not implemented yet */
41.1824 + break;
41.1825 + }
41.1826 + }
41.1827 +done: return errcode;
41.1828 +}
41.1829 +
41.1830 +int CPXprimopt(CPXENV *env, CPXLP *lp);
41.1831 +
41.1832 +int CPXsavwrite(CPXENV *env, CPXLP *lp, const char *filename)
41.1833 +{ xassert(env == env);
41.1834 + xassert(lp == lp);
41.1835 + xassert(filename == filename);
41.1836 + xprintf("CPXsavwrite: not implemented yet\n");
41.1837 + exit(EXIT_FAILURE);
41.1838 + return -1;
41.1839 +}
41.1840 +
41.1841 +int CPXsetdblparam(CPXENV *env, int whichparam, double newvalue)
41.1842 +{ int k, errcode;
41.1843 + errcode = checkenv(env);
41.1844 + if (errcode) goto done;
41.1845 + k = finddblparam(whichparam);
41.1846 + if (k < 0)
41.1847 + { errcode = error(env, CPXERR_BAD_PARAM_NUM);
41.1848 + goto done;
41.1849 + }
41.1850 + if (newvalue < dblparam[k].minv)
41.1851 + { errcode = error(env, CPXERR_PARAM_TOO_SMALL);
41.1852 + goto done;
41.1853 + }
41.1854 + if (newvalue > dblparam[k].maxv)
41.1855 + { errcode = error(env, CPXERR_PARAM_TOO_BIG);
41.1856 + goto done;
41.1857 + }
41.1858 + errcode = 0;
41.1859 + env->dblparam[k] = newvalue;
41.1860 +done: return errcode;
41.1861 +}
41.1862 +
41.1863 +int CPXsetintparam(CPXENV *env, int whichparam, int newvalue)
41.1864 +{ int k, errcode;
41.1865 + errcode = checkenv(env);
41.1866 + if (errcode) goto done;
41.1867 + k = findintparam(whichparam);
41.1868 + if (k < 0)
41.1869 + { errcode = error(env, CPXERR_BAD_PARAM_NUM);
41.1870 + goto done;
41.1871 + }
41.1872 + if (newvalue < intparam[k].minv)
41.1873 + { errcode = error(env, CPXERR_PARAM_TOO_SMALL);
41.1874 + goto done;
41.1875 + }
41.1876 + if (newvalue > intparam[k].maxv)
41.1877 + { errcode = error(env, CPXERR_PARAM_TOO_BIG);
41.1878 + goto done;
41.1879 + }
41.1880 + errcode = 0;
41.1881 + env->intparam[k] = newvalue;
41.1882 +done: return errcode;
41.1883 +}
41.1884 +
41.1885 +int CPXsolninfo(CPXENV *env, CPXLP *lp, int *solnmethod, int *solntype,
41.1886 + int *pfeasind, int *dfeasind)
41.1887 +{ int type, pfeas, dfeas, errcode;
41.1888 + errcode = checklp(env, lp);
41.1889 + if (errcode) goto done;
41.1890 + errcode = 0;
41.1891 + if (!lp->stat)
41.1892 + type = CPX_NO_SOLN, pfeas = dfeas = 0;
41.1893 + else if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
41.1894 + { type = CPX_BASIC_SOLN;
41.1895 + pfeas = (glp_get_prim_stat(lp->prob) == GLP_FEAS);
41.1896 + dfeas = (glp_get_dual_stat(lp->prob) == GLP_FEAS);
41.1897 + }
41.1898 + else
41.1899 + xassert(lp != lp);
41.1900 + if (solnmethod != NULL)
41.1901 + *solnmethod = lp->meth;
41.1902 + if (solntype != NULL)
41.1903 + *solntype = type;
41.1904 + if (pfeasind != NULL)
41.1905 + *pfeasind = pfeas;
41.1906 + if (dfeasind != NULL)
41.1907 + *dfeasind = dfeas;
41.1908 +done: return errcode;
41.1909 +}
41.1910 +
41.1911 +int CPXsolution(CPXENV *env, CPXLP *lp, int *lpstat, double *objval,
41.1912 + double x[], double pi[], double slack[], double dj[])
41.1913 +{ int m, n, errcode;
41.1914 + errcode = checklp(env, lp);
41.1915 + if (errcode) goto done;
41.1916 + if (!lp->stat)
41.1917 + { errcode = error(env, CPXERR_NO_SOLN);
41.1918 + goto done;
41.1919 + }
41.1920 + errcode = 0;
41.1921 + m = glp_get_num_rows(lp->prob);
41.1922 + n = glp_get_num_cols(lp->prob);
41.1923 + if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
41.1924 + { if (lpstat != NULL)
41.1925 + *lpstat = CPXgetstat(env, lp);
41.1926 + if (objval != NULL)
41.1927 + xassert(CPXgetobjval(env, lp, objval) == 0);
41.1928 + if (x != NULL)
41.1929 + xassert(CPXgetx(env, lp, x, 0, n-1) == 0);
41.1930 + if (pi != NULL)
41.1931 + xassert(CPXgetpi(env, lp, pi, 0, m-1) == 0);
41.1932 + if (slack != NULL)
41.1933 + xassert(CPXgetslack(env, lp, slack, 0, m-1) == 0);
41.1934 + if (dj != NULL)
41.1935 + xassert(CPXgetdj(env, lp, dj, 0, n-1) == 0);
41.1936 + }
41.1937 + else
41.1938 + xassert(lp != lp);
41.1939 +done: return errcode;
41.1940 +}
41.1941 +
41.1942 +int CPXstrongbranch(CPXENV *env, CPXLP *lp, const int goodlist[],
41.1943 + int goodlen, double downpen[], double uppen[], int itlim)
41.1944 +{ int k;
41.1945 + xassert(env == env);
41.1946 + xassert(lp == lp);
41.1947 + xassert(goodlist == goodlist);
41.1948 + xassert(goodlen >= 0);
41.1949 + xassert(downpen != NULL);
41.1950 + xassert(uppen != NULL);
41.1951 + xassert(itlim == itlim);
41.1952 + /* not implemented yet */
41.1953 + for (k = 0; k < goodlen; k++)
41.1954 + downpen[k] = uppen[k] = 0.0;
41.1955 + return 0;
41.1956 +}
41.1957 +
41.1958 +static int xstrcasecmp(const char *s1, const char *s2)
41.1959 +{ int c1, c2;
41.1960 + for (;;)
41.1961 + { c1 = toupper((unsigned char)*s1++);
41.1962 + c2 = toupper((unsigned char)*s2++);
41.1963 + if (c1 == '\0' || c1 != c2) break;
41.1964 + }
41.1965 + return c1 - c2;
41.1966 +}
41.1967 +
41.1968 +static void getfiletype(const char *filename, char type[3+1])
41.1969 +{ /* determine filetype from filename */
41.1970 + int beg, end;
41.1971 + beg = end = strlen(filename);
41.1972 + while (beg > 0 && filename[beg-1] != '.' && end - beg < 3)
41.1973 + beg--;
41.1974 + if (beg > 0 && filename[beg-1] == '.' &&
41.1975 + xstrcasecmp(&filename[beg], "gz") == 0)
41.1976 + { end = --beg;
41.1977 + while (beg > 0 && filename[beg-1] != '.' && end - beg < 3)
41.1978 + beg--;
41.1979 + }
41.1980 + if (beg > 0 && filename[beg-1] == '.')
41.1981 + { memcpy(type, &filename[beg], end - beg);
41.1982 + type[end - beg] = '\0';
41.1983 + }
41.1984 + else
41.1985 + type[0] = '\0';
41.1986 + return;
41.1987 +}
41.1988 +
41.1989 +int CPXwriteprob(CPXENV *env, CPXLP *lp, const char *filename,
41.1990 + const char *filetype)
41.1991 +{ glp_prob *copy;
41.1992 + int errcode;
41.1993 + char type[3+1];
41.1994 + errcode = checklp(env, lp);
41.1995 + if (errcode) goto done;
41.1996 + if (filename == NULL)
41.1997 + { errcode = error(env, CPXERR_NO_FILENAME);
41.1998 + goto done;
41.1999 + }
41.2000 + if (filetype == NULL)
41.2001 + getfiletype(filename, type), filetype = type;
41.2002 + if (xstrcasecmp(filetype, "MPS") == 0)
41.2003 + { glp_term_out(GLP_OFF);
41.2004 + errcode = glp_write_mps(lp->prob, GLP_MPS_FILE, NULL, filename)
41.2005 + ;
41.2006 + glp_term_out(GLP_ON);
41.2007 + }
41.2008 + else if (xstrcasecmp(filetype, "LP") == 0)
41.2009 + { glp_term_out(GLP_OFF);
41.2010 + errcode = glp_write_lp(lp->prob, NULL, filename);
41.2011 + glp_term_out(GLP_ON);
41.2012 + }
41.2013 + else if (xstrcasecmp(filetype, "RMP") == 0 ||
41.2014 + xstrcasecmp(filetype, "REW") == 0)
41.2015 + { copy = glp_create_prob();
41.2016 + glp_copy_prob(copy, lp->prob, GLP_OFF);
41.2017 + glp_term_out(GLP_OFF);
41.2018 + errcode = glp_write_mps(copy, GLP_MPS_DECK, NULL, filename);
41.2019 + glp_term_out(GLP_ON);
41.2020 + glp_delete_prob(copy);
41.2021 + }
41.2022 + else if (xstrcasecmp(filetype, "RLP") == 0)
41.2023 + { copy = glp_create_prob();
41.2024 + glp_copy_prob(copy, lp->prob, GLP_OFF);
41.2025 + glp_term_out(GLP_OFF);
41.2026 + errcode = glp_write_lp(copy, NULL, filename);
41.2027 + glp_term_out(GLP_ON);
41.2028 + glp_delete_prob(copy);
41.2029 + }
41.2030 + else
41.2031 + { errcode = error(env, CPXERR_BAD_FILETYPE);
41.2032 + goto done;
41.2033 + }
41.2034 + if (errcode)
41.2035 + errcode = error(env, CPXERR_FAIL_OPEN_WRITE, filename);
41.2036 +done: return errcode;
41.2037 +}
41.2038 +
41.2039 +/**********************************************************************/
41.2040 +
41.2041 +static int solvelp(CPXENV *env, CPXLP *lp, int meth)
41.2042 +{ glp_smcp parm;
41.2043 + int errcode;
41.2044 + errcode = checklp(env, lp);
41.2045 + if (errcode) goto done;
41.2046 + errcode = 0;
41.2047 + invalidate(lp);
41.2048 + glp_init_smcp(&parm);
41.2049 + switch (meth)
41.2050 + { case CPX_ALG_PRIMAL:
41.2051 + parm.meth = GLP_PRIMAL;
41.2052 + break;
41.2053 + case CPX_ALG_DUAL:
41.2054 + parm.meth = GLP_DUAL;
41.2055 + break;
41.2056 + default:
41.2057 + xassert(meth != meth);
41.2058 + }
41.2059 + switch (getintparam(env, CPX_PARAM_SIMDISPLAY))
41.2060 + { case 0:
41.2061 + parm.msg_lev = GLP_MSG_OFF;
41.2062 + break;
41.2063 + case 1:
41.2064 + parm.msg_lev = GLP_MSG_ALL;
41.2065 + break;
41.2066 + case 2:
41.2067 + parm.msg_lev = GLP_MSG_ALL;
41.2068 + parm.out_frq = 1;
41.2069 + break;
41.2070 + default:
41.2071 + xassert(env != env);
41.2072 + }
41.2073 + xassert(getdblparam == getdblparam);
41.2074 + switch (getintparam(env, CPX_PARAM_ADVIND))
41.2075 + { case 0:
41.2076 + glp_term_out(GLP_OFF);
41.2077 + glp_adv_basis(lp->prob, 0);
41.2078 + glp_term_out(GLP_ON);
41.2079 + break;
41.2080 + case 1:
41.2081 + case 2:
41.2082 + break;
41.2083 + default:
41.2084 + xassert(env != env);
41.2085 + }
41.2086 + if (!glp_bf_exists(lp->prob))
41.2087 + { if (glp_factorize(lp->prob) != 0)
41.2088 + { glp_term_out(GLP_OFF);
41.2089 + glp_adv_basis(lp->prob, 0);
41.2090 + glp_term_out(GLP_ON);
41.2091 + if (glp_factorize(lp->prob) != 0)
41.2092 + glp_std_basis(lp->prob);
41.2093 + }
41.2094 + }
41.2095 + xassert(glp_simplex(lp->prob, &parm) == 0);
41.2096 + switch (glp_get_status(lp->prob))
41.2097 + { case GLP_OPT:
41.2098 + lp->stat = CPX_STAT_OPTIMAL;
41.2099 + lp->meth = meth;
41.2100 + break;
41.2101 + case GLP_NOFEAS:
41.2102 + lp->stat = CPX_STAT_INFEASIBLE;
41.2103 + lp->meth = meth;
41.2104 + break;
41.2105 + case GLP_UNBND:
41.2106 + lp->stat = CPX_STAT_UNBOUNDED;
41.2107 + lp->meth = meth;
41.2108 + break;
41.2109 + default:
41.2110 + xassert(lp != lp);
41.2111 + }
41.2112 +done: return errcode;
41.2113 +}
41.2114 +
41.2115 +int CPXprimopt(CPXENV *env, CPXLP *lp)
41.2116 +{ int errcode;
41.2117 + errcode = solvelp(env, lp, CPX_ALG_PRIMAL);
41.2118 + return errcode;
41.2119 +}
41.2120 +
41.2121 +int CPXdualopt(CPXENV *env, CPXLP *lp)
41.2122 +{ int errcode;
41.2123 + errcode = solvelp(env, lp, CPX_ALG_DUAL);
41.2124 + return errcode;
41.2125 +}
41.2126 +
41.2127 +int CPXlpopt(CPXENV *env, CPXLP *lp)
41.2128 +{ int errcode;
41.2129 + errcode = solvelp(env, lp, CPX_ALG_PRIMAL);
41.2130 + return errcode;
41.2131 +}
41.2132 +
41.2133 +/* eof */
42.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
42.2 +++ b/examples/cplex/cplex.h Mon Dec 06 13:09:21 2010 +0100
42.3 @@ -0,0 +1,301 @@
42.4 +/* cplex.h (CPLEX-like interface to GLPK API) */
42.5 +
42.6 +/***********************************************************************
42.7 +* This code is part of GLPK (GNU Linear Programming Kit).
42.8 +*
42.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
42.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
42.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
42.12 +* E-mail: <mao@gnu.org>.
42.13 +*
42.14 +* GLPK is free software: you can redistribute it and/or modify it
42.15 +* under the terms of the GNU General Public License as published by
42.16 +* the Free Software Foundation, either version 3 of the License, or
42.17 +* (at your option) any later version.
42.18 +*
42.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
42.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
42.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
42.22 +* License for more details.
42.23 +*
42.24 +* You should have received a copy of the GNU General Public License
42.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
42.26 +***********************************************************************/
42.27 +
42.28 +#ifndef _CPLEX_H
42.29 +#define _CPLEX_H
42.30 +
42.31 +#ifdef __cplusplus
42.32 +extern "C" {
42.33 +#endif
42.34 +
42.35 +typedef struct CPXENV CPXENV, *CPXENVptr;
42.36 +typedef struct CPXLP CPXLP, *CPXLPptr;
42.37 +
42.38 +#define CPX_VERSION 900
42.39 +
42.40 +#define CPX_OFF 0
42.41 +#define CPX_ON 1
42.42 +
42.43 +#define CPX_INFBOUND 1e20
42.44 +
42.45 +/* error codes: */
42.46 +#define CPXERR_NO_MEMORY 1001
42.47 +#define CPXERR_NO_ENVIRONMENT 1002
42.48 +#define CPXERR_BAD_ARGUMENT 1003
42.49 +#define CPXERR_NULL_POINTER 1004
42.50 +#define CPXERR_NO_PROBLEM 1009
42.51 +#define CPXERR_BAD_PARAM_NUM 1013
42.52 +#define CPXERR_PARAM_TOO_SMALL 1014
42.53 +#define CPXERR_PARAM_TOO_BIG 1015
42.54 +#define CPXERR_INDEX_RANGE 1200
42.55 +#define CPXERR_COL_INDEX_RANGE 1201
42.56 +#define CPXERR_ROW_INDEX_RANGE 1203
42.57 +#define CPXERR_NEGATIVE_SURPLUS 1207
42.58 +#define CPXERR_BAD_SENSE 1215
42.59 +#define CPXERR_NO_SOLN 1217
42.60 +#define CPXERR_NOT_FIXED 1221
42.61 +#define CPXERR_DUP_ENTRY 1222
42.62 +#define CPXERR_NULL_NAME 1224
42.63 +#define CPXERR_ARRAY_NOT_ASCENDING 1226
42.64 +#define CPXERR_COUNT_RANGE 1227
42.65 +#define CPXERR_BAD_LUB 1229
42.66 +#define CPXERR_BAD_STATUS 1253
42.67 +#define CPXERR_NO_BASIC_SOLN 1261
42.68 +#define CPXERR_NO_FILENAME 1421
42.69 +#define CPXERR_FAIL_OPEN_WRITE 1422
42.70 +#define CPXERR_BAD_FILETYPE 1424
42.71 +#define CPXERR_BAD_CTYPE 3021
42.72 +
42.73 +/* control parameters: */
42.74 +#define CPX_PARAM_ADVIND 1001
42.75 +#define CPX_PARAM_AGGIND 1003
42.76 +#define CPX_PARAM_DPRIIND 1009
42.77 +#define CPX_PARAM_EPOPT 1014
42.78 +#define CPX_PARAM_EPPER 1015
42.79 +#define CPX_PARAM_EPRHS 1016
42.80 +#define CPX_PARAM_FASTMIP 1017 /* ??? */
42.81 +#define CPX_PARAM_SIMDISPLAY 1019
42.82 +#define CPX_PARAM_ITLIM 1020
42.83 +#define CPX_PARAM_OBJLLIM 1025
42.84 +#define CPX_PARAM_OBJULIM 1026
42.85 +#define CPX_PARAM_PERIND 1027
42.86 +#define CPX_PARAM_PPRIIND 1029
42.87 +#define CPX_PARAM_PREIND 1030
42.88 +#define CPX_PARAM_REINV 1031
42.89 +#define CPX_PARAM_SCRIND 1035
42.90 +#define CPX_PARAM_DATACHECK 1056
42.91 +
42.92 +/* CPX_PARAM_DPRIIND: */
42.93 +#define CPX_DPRIIND_AUTO 0
42.94 +#define CPX_DPRIIND_FULL 1
42.95 +#define CPX_DPRIIND_STEEP 2
42.96 +#define CPX_DPRIIND_FULL_STEEP 3
42.97 +#define CPX_DPRIIND_STEEPQSTART 4
42.98 +#define CPX_DPRIIND_DEVEX 5
42.99 +
42.100 +/* CPX_PARAM_PPRIIND: */
42.101 +#define CPX_PPRIIND_PARTIAL (-1)
42.102 +#define CPX_PPRIIND_AUTO 0
42.103 +#define CPX_PPRIIND_DEVEX 1
42.104 +#define CPX_PPRIIND_STEEP 2
42.105 +#define CPX_PPRIIND_STEEPQSTART 3
42.106 +#define CPX_PPRIIND_FULL 4
42.107 +
42.108 +/* CPXgetprobtype: */
42.109 +#define CPXPROB_LP 0
42.110 +#define CPXPROB_MIP 1
42.111 +#define CPXPROB_RELAXED 2
42.112 +#define CPXPROB_FIXED 3
42.113 +#define CPXPROB_QP 5
42.114 +#define CPXPROB_ZEROEDQP 6
42.115 +
42.116 +/* CPXgetobjsen: */
42.117 +#define CPX_MIN 1
42.118 +#define CPX_MAX (-1)
42.119 +
42.120 +/* CPXgetbase: */
42.121 +#define CPX_AT_LOWER 0
42.122 +#define CPX_BASIC 1
42.123 +#define CPX_AT_UPPER 2
42.124 +#define CPX_FREE_SUPER 3
42.125 +
42.126 +/* CPXgetstat: */
42.127 +#define CPX_STAT_OPTIMAL 1
42.128 +#define CPX_STAT_UNBOUNDED 2
42.129 +#define CPX_STAT_INFEASIBLE 3
42.130 +#define CPX_STAT_INForUNBD 4
42.131 +#define CPX_STAT_OPTIMAL_INFEAS 5
42.132 +#define CPX_STAT_ABORT_IT_LIM 10
42.133 +#define CPX_STAT_ABORT_OBJ_LIM 12
42.134 +
42.135 +/* CPXgetmethod: */
42.136 +#define CPX_ALG_NONE 0
42.137 +#define CPX_ALG_PRIMAL 1
42.138 +#define CPX_ALG_DUAL 2
42.139 +#define CPX_ALG_BARRIER 4
42.140 +
42.141 +/* CPXsolninfo: */
42.142 +#define CPX_NO_SOLN 0
42.143 +#define CPX_BASIC_SOLN 1
42.144 +#define CPX_NONBASIC_SOLN 2
42.145 +#define CPX_PRIMAL_SOLN 3
42.146 +
42.147 +int CPXaddcols(CPXENV *env, CPXLP *lp, int ccnt, int nzcnt,
42.148 + const double obj[], const int cmatbeg[], const int cmatind[],
42.149 + const double cmatval[], const double lb[], const double ub[],
42.150 + char *colname[]);
42.151 +
42.152 +int CPXaddrows(CPXENV *env, CPXLP *lp, int ccnt, int rcnt, int nzcnt,
42.153 + const double rhs[], const char sense[], const int rmatbeg[],
42.154 + const int rmatind[], const double rmatval[], char *colname[],
42.155 + char *rowname[]);
42.156 +
42.157 +int CPXbaropt(CPXENV *env, CPXLP *lp);
42.158 +
42.159 +int CPXbinvrow(CPXENV *env, CPXLP *lp, int i, double y[]);
42.160 +
42.161 +int CPXchgbds(CPXENV *env, CPXLP *lp, int cnt, const int indices[],
42.162 + const char lu[], const double bd[]);
42.163 +
42.164 +int CPXchgcoeflist(CPXENV *env, CPXLP *lp, int numcoefs,
42.165 + const int rowlist[], const int collist[], const double vallist[]);
42.166 +
42.167 +void CPXchgobjsen(CPXENV *env, CPXLP *lp, int maxormin);
42.168 +
42.169 +int CPXchgsense(CPXENV *env, CPXLP *lp, int cnt, const int indices[],
42.170 + const char sense[]);
42.171 +
42.172 +int CPXcloseCPLEX(CPXENV **env);
42.173 +
42.174 +int CPXcopybase(CPXENV *env, CPXLP *lp, const int cstat[],
42.175 + const int rstat[]);
42.176 +
42.177 +int CPXcopybasednorms(CPXENV *env, CPXLP *lp, const int cstat[],
42.178 + const int rstat[], const double dnorm[]);
42.179 +
42.180 +int CPXcopylp(CPXENV *env, CPXLP *lp, int numcols, int numrows,
42.181 + int objsen, const double obj[], const double rhs[],
42.182 + const char sense[], const int matbeg[], const int matcnt[],
42.183 + const int matind[], const double matval[], const double lb[],
42.184 + const double ub[], const double rngval[]);
42.185 +
42.186 +int CPXcopylpwnames(CPXENV *env, CPXLP *lp, int numcols, int numrows,
42.187 + int objsen, const double obj[], const double rhs[],
42.188 + const char sense[], const int matbeg[], const int matcnt[],
42.189 + const int matind[], const double matval[], const double lb[],
42.190 + const double ub[], const double rngval[], char *colname[],
42.191 + char *rowname[]);
42.192 +
42.193 +CPXLP *CPXcreateprob(CPXENV *env, int *status, const char *probname);
42.194 +
42.195 +int CPXdelcols(CPXENV *env, CPXLP *lp, int begin, int end);
42.196 +
42.197 +int CPXdelrows(CPXENV *env, CPXLP *lp, int begin, int end);
42.198 +
42.199 +int CPXdelsetcols(CPXENV *env, CPXLP *lp, int delstat[]);
42.200 +
42.201 +int CPXdelsetrows(CPXENV *env, CPXLP *lp, int delstat[]);
42.202 +
42.203 +int CPXdualopt(CPXENV *env, CPXLP *lp);
42.204 +
42.205 +int CPXfreeprob(CPXENV *env, CPXLP **lp);
42.206 +
42.207 +int CPXgetbase(CPXENV *env, CPXLP *lp, int cstat[], int rstat[]);
42.208 +
42.209 +int CPXgetbasednorms(CPXENV *env, CPXLP *lp, int cstat[], int rstat[],
42.210 + double dnorm[]);
42.211 +
42.212 +int CPXgetbhead(CPXENV *env, CPXLP *lp, int head[], double x[]);
42.213 +
42.214 +int CPXgetdblparam(CPXENV *env, int whichparam, double *value);
42.215 +
42.216 +int CPXgetdj(CPXENV *env, CPXLP *lp, double dj[], int begin, int end);
42.217 +
42.218 +char *CPXgeterrorstring(CPXENV *env, int errcode, char *buffer);
42.219 +
42.220 +int CPXgetijdiv(CPXENV *env, CPXLP *lp, int *idiv, int *jdiv);
42.221 +
42.222 +int CPXgetintparam(CPXENV *env, int whichparam, int *value);
42.223 +
42.224 +int CPXgetlb(CPXENV *env, CPXLP *lp, double lb[], int begin, int end);
42.225 +
42.226 +int CPXgetmethod(CPXENV *env, CPXLP *lp);
42.227 +
42.228 +int CPXgetnumcols(CPXENV *env, CPXLP *lp);
42.229 +
42.230 +int CPXgetnumnz(CPXENV *env, CPXLP *lp);
42.231 +
42.232 +int CPXgetnumrows(CPXENV *env, CPXLP *lp);
42.233 +
42.234 +int CPXgetobjval(CPXENV *env, CPXLP *lp, double *objval);
42.235 +
42.236 +int CPXgetpi(CPXENV *env, CPXLP *lp, double pi[], int begin, int end);
42.237 +
42.238 +int CPXgetsense(CPXENV *env, CPXLP *lp, char sense[], int begin,
42.239 + int end);
42.240 +
42.241 +int CPXgetslack(CPXENV *env, CPXLP *lp, double slack[], int begin,
42.242 + int end);
42.243 +
42.244 +int CPXgetstat(CPXENV *env, CPXLP *lp);
42.245 +
42.246 +int CPXgetub(CPXENV *env, CPXLP *lp, double ub[], int begin, int end);
42.247 +
42.248 +int CPXgetweight(CPXENV *env, CPXLP *lp, int rcnt, const int rmatbeg[],
42.249 + const int rmatind[], const double rmatval[], double weight[],
42.250 + int dpriind);
42.251 +
42.252 +int CPXgetx(CPXENV *env, CPXLP *lp, double x[], int begin, int end);
42.253 +
42.254 +int CPXinfodblparam(CPXENV *env, int whichparam, double *defvalue,
42.255 + double *minvalue, double *maxvalue);
42.256 +
42.257 +int CPXinfointparam(CPXENV *env, int whichparam, int *defvalue,
42.258 + int *minvalue, int *maxvalue);
42.259 +
42.260 +int CPXlpopt(CPXENV *env, CPXLP *lp);
42.261 +
42.262 +int CPXmdleave(const CPXENV *env, CPXLP *lp, const int goodlist[],
42.263 + int goodlen, double downratio[], double upratio[]);
42.264 +
42.265 +int CPXnewcols(CPXENV *env, CPXLP *lp, int ccnt, const double obj[],
42.266 + const double lb[], const double ub[], const char ctype[],
42.267 + char *colname[]);
42.268 +
42.269 +int CPXnewrows(CPXENV *env, CPXLP *lp, int rcnt, const double rhs[],
42.270 + const char sense[], const double rngval[], char *rowname[]);
42.271 +
42.272 +CPXENV *CPXopenCPLEX(int *status);
42.273 +
42.274 +int CPXpivotin(CPXENV *env, CPXLP *lp, const int rlist[], int rlen);
42.275 +
42.276 +int CPXpivotout(CPXENV *env, CPXLP *lp, const int clist[], int clen);
42.277 +
42.278 +int CPXprimopt(CPXENV *env, CPXLP *lp);
42.279 +
42.280 +int CPXsavwrite(CPXENV *env, CPXLP *lp, const char *filename);
42.281 +
42.282 +int CPXsetdblparam(CPXENV *env, int whichparam, double newvalue);
42.283 +
42.284 +int CPXsetintparam(CPXENV *env, int whichparam, int newvalue);
42.285 +
42.286 +int CPXsolninfo(CPXENV *env, CPXLP *lp, int *solnmethod, int *solntype,
42.287 + int *pfeasind, int *dfeasind);
42.288 +
42.289 +int CPXsolution(CPXENV *env, CPXLP *lp, int *lpstat, double *objval,
42.290 + double x[], double pi[], double slack[], double dj[]);
42.291 +
42.292 +int CPXstrongbranch(CPXENV *env, CPXLP *lp, const int goodlist[],
42.293 + int goodlen, double downpen[], double uppen[], int itlim);
42.294 +
42.295 +int CPXwriteprob(CPXENV *env, CPXLP *lp, const char *filename,
42.296 + const char *filetype);
42.297 +
42.298 +#ifdef __cplusplus
42.299 +}
42.300 +#endif
42.301 +
42.302 +#endif
42.303 +
42.304 +/* eof */
43.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
43.2 +++ b/examples/cpp.mod Mon Dec 06 13:09:21 2010 +0100
43.3 @@ -0,0 +1,67 @@
43.4 +/* CPP, Critical Path Problem */
43.5 +
43.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
43.7 +
43.8 +/* Note: Reduced costs of auxiliary variables phi[j,k] (see below)
43.9 + can be only zero or one. The critical path is defined by the
43.10 + constraints, whose reduced cost is one. */
43.11 +
43.12 +set J;
43.13 +/* set of jobs (activities) */
43.14 +
43.15 +set P{j in J}, in J, default {};
43.16 +/* P[j] is a subset of jobs that immediately precede job j */
43.17 +
43.18 +param t{j in J}, >= 0;
43.19 +/* duration required to perform job j */
43.20 +
43.21 +var x{j in J}, >= 0;
43.22 +/* starting time of job j */
43.23 +
43.24 +s.t. phi{j in J, k in P[j]}: x[j] >= x[k] + t[k];
43.25 +/* job j can start only after all immediately preceding jobs have been
43.26 + completely performed */
43.27 +
43.28 +var z;
43.29 +/* project makespan */
43.30 +
43.31 +s.t. fin{j in J}: z >= x[j] + t[j];
43.32 +/* which is the maximum of the completion times of all the jobs */
43.33 +
43.34 +minimize obj: z;
43.35 +/* the objective is make z as small as possible */
43.36 +
43.37 +data;
43.38 +
43.39 +/* The optimal solution is 46 */
43.40 +
43.41 +param : J : t :=
43.42 + A 3 /* Excavate */
43.43 + B 4 /* Lay foundation */
43.44 + C 3 /* Rough plumbing */
43.45 + D 10 /* Frame */
43.46 + E 8 /* Finish exterior */
43.47 + F 4 /* Install HVAC */
43.48 + G 6 /* Rough electric */
43.49 + H 8 /* Sheet rock */
43.50 + I 5 /* Install cabinets */
43.51 + J 5 /* Paint */
43.52 + K 4 /* Final plumbing */
43.53 + L 2 /* Final electric */
43.54 + M 4 /* Install flooring */
43.55 +;
43.56 +
43.57 +set P[B] := A;
43.58 +set P[C] := B;
43.59 +set P[D] := B;
43.60 +set P[E] := D;
43.61 +set P[F] := D;
43.62 +set P[G] := D;
43.63 +set P[H] := C E F G;
43.64 +set P[I] := H;
43.65 +set P[J] := H;
43.66 +set P[K] := I;
43.67 +set P[L] := J;
43.68 +set P[M] := K L;
43.69 +
43.70 +end;
44.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
44.2 +++ b/examples/crypto.mod Mon Dec 06 13:09:21 2010 +0100
44.3 @@ -0,0 +1,84 @@
44.4 +/* CRYPTO, a crypto-arithmetic puzzle */
44.5 +
44.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
44.7 +
44.8 +/* This problem comes from the newsgroup rec.puzzle.
44.9 + The numbers from 1 to 26 are assigned to the letters of the alphabet.
44.10 + The numbers beside each word are the total of the values assigned to
44.11 + the letters in the word (e.g. for LYRE: L, Y, R, E might be to equal
44.12 + 5, 9, 20 and 13, or any other combination that add up to 47).
44.13 + Find the value of each letter under the equations:
44.14 +
44.15 + BALLET 45 GLEE 66 POLKA 59 SONG 61
44.16 + CELLO 43 JAZZ 58 QUARTET 50 SOPRANO 82
44.17 + CONCERT 74 LYRE 47 SAXOPHONE 134 THEME 72
44.18 + FLUTE 30 OBOE 53 SCALE 51 VIOLIN 100
44.19 + FUGUE 50 OPERA 65 SOLO 37 WALTZ 34
44.20 +
44.21 + Solution:
44.22 + A, B,C, D, E,F, G, H, I, J, K,L,M, N, O, P,Q, R, S,T,U, V,W, X, Y, Z
44.23 + 5,13,9,16,20,4,24,21,25,17,23,2,8,12,10,19,7,11,15,3,1,26,6,22,14,18
44.24 +
44.25 + Reference:
44.26 + Koalog Constraint Solver <http://www.koalog.com/php/jcs.php>,
44.27 + Simple problems, the crypto-arithmetic puzzle ALPHACIPHER. */
44.28 +
44.29 +set LETTERS :=
44.30 +{ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
44.31 + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
44.32 +};
44.33 +/* set of letters */
44.34 +
44.35 +set VALUES := 1..card(LETTERS);
44.36 +/* set of values assigned to the letters */
44.37 +
44.38 +set WORDS;
44.39 +/* set of words */
44.40 +
44.41 +param total{word in WORDS};
44.42 +/* total[word] is the total of the values assigned to the letters in
44.43 + the word */
44.44 +
44.45 +var x{i in LETTERS, j in VALUES}, binary;
44.46 +/* x[i,j] = 1 means that letter i is assigned value j */
44.47 +
44.48 +s.t. phi{i in LETTERS}: sum{j in VALUES} x[i,j] = 1;
44.49 +
44.50 +s.t. psi{j in VALUES}: sum{i in LETTERS} x[i,j] = 1;
44.51 +
44.52 +s.t. eqn{word in WORDS}: sum{k in 1..length(word), j in VALUES}
44.53 + j * x[substr(word,k,1), j] = total[word];
44.54 +
44.55 +solve;
44.56 +
44.57 +printf{i in LETTERS} " %s", i;
44.58 +printf "\n";
44.59 +
44.60 +printf{i in LETTERS} " %2d", sum{j in VALUES} j * x[i,j];
44.61 +printf "\n";
44.62 +
44.63 +data;
44.64 +
44.65 +param : WORDS : total :=
44.66 + BALLET 45
44.67 + CELLO 43
44.68 + CONCERT 74
44.69 + FLUTE 30
44.70 + FUGUE 50
44.71 + GLEE 66
44.72 + JAZZ 58
44.73 + LYRE 47
44.74 + OBOE 53
44.75 + OPERA 65
44.76 + POLKA 59
44.77 + QUARTET 50
44.78 + SAXOPHONE 134
44.79 + SCALE 51
44.80 + SOLO 37
44.81 + SONG 61
44.82 + SOPRANO 82
44.83 + THEME 72
44.84 + VIOLIN 100
44.85 + WALTZ 34 ;
44.86 +
44.87 +end;
45.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
45.2 +++ b/examples/csv/distances.csv Mon Dec 06 13:09:21 2010 +0100
45.3 @@ -0,0 +1,7 @@
45.4 +plant,market,distance
45.5 +"Seattle","New York",2.5
45.6 +"Seattle","Chicago",1.7
45.7 +"Seattle","Topeka",1.8
45.8 +"San Diego","New York",2.5
45.9 +"San Diego","Chicago",1.8
45.10 +"San Diego","Topeka",1.4
46.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
46.2 +++ b/examples/csv/markets.csv Mon Dec 06 13:09:21 2010 +0100
46.3 @@ -0,0 +1,4 @@
46.4 +market,demand
46.5 +"New York",325.
46.6 +"Chicago",300.
46.7 +"Topeka",275.
47.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
47.2 +++ b/examples/csv/parameters.csv Mon Dec 06 13:09:21 2010 +0100
47.3 @@ -0,0 +1,2 @@
47.4 +parameter,value
47.5 +"transport cost",90.
48.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
48.2 +++ b/examples/csv/plants.csv Mon Dec 06 13:09:21 2010 +0100
48.3 @@ -0,0 +1,3 @@
48.4 +plant,capacity
48.5 +"Seattle",350.
48.6 +"San Diego",600.
49.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
49.2 +++ b/examples/csv/transp_csv.mod Mon Dec 06 13:09:21 2010 +0100
49.3 @@ -0,0 +1,70 @@
49.4 +# A TRANSPORTATION PROBLEM
49.5 +#
49.6 +# This problem finds a least cost shipping schedule that meets
49.7 +# requirements at markets and supplies at factories.
49.8 +#
49.9 +# References:
49.10 +# Dantzig G B, "Linear Programming and Extensions."
49.11 +# Princeton University Press, Princeton, New Jersey, 1963,
49.12 +# Chapter 3-3.
49.13 +
49.14 +set I;
49.15 +/* canning plants */
49.16 +
49.17 +set J;
49.18 +/* markets */
49.19 +
49.20 +set K dimen 2;
49.21 +/* transportation lane */
49.22 +
49.23 +set L;
49.24 +/* parameters */
49.25 +
49.26 +param a{i in I};
49.27 +/* capacity of plant i in cases */
49.28 +
49.29 +param b{j in J};
49.30 +/* demand at market j in cases */
49.31 +
49.32 +param d{i in I, j in J};
49.33 +/* distance in thousands of miles */
49.34 +
49.35 +param e{l in L};
49.36 +/* parameters */
49.37 +
49.38 +param f;
49.39 +/* freight in dollars per case per thousand miles */
49.40 +
49.41 +table tab_plant IN "CSV" "plants.csv" :
49.42 + I <- [plant], a ~ capacity;
49.43 +
49.44 +table tab_market IN "CSV" "markets.csv" :
49.45 + J <- [market], b ~ demand;
49.46 +
49.47 +table tab_distance IN "CSV" "distances.csv" :
49.48 + K <- [plant, market], d ~ distance;
49.49 +
49.50 +table tab_parameter IN "CSV" "parameters.csv" :
49.51 + L <- [parameter], e ~ value ;
49.52 +
49.53 +param c{i in I, j in J} := e['transport cost'] * d[i,j] / 1000;
49.54 +/* transport cost in thousands of dollars per case */
49.55 +
49.56 +var x{(i,j) in K} >= 0;
49.57 +/* shipment quantities in cases */
49.58 +
49.59 +minimize cost: sum{(i,j) in K} c[i,j] * x[i,j];
49.60 +/* total transportation costs in thousands of dollars */
49.61 +
49.62 +s.t. supply{i in I}: sum{(i,j) in K} x[i,j] <= a[i];
49.63 +/* observe supply limit at plant i */
49.64 +
49.65 +s.t. demand{j in J}: sum{(i,j) in K} x[i,j] >= b[j];
49.66 +/* satisfy demand at market j */
49.67 +
49.68 +solve;
49.69 +
49.70 +table tab_result{(i,j) in K} OUT "CSV" "result.csv" :
49.71 + i ~ plant, j ~ market, x[i,j] ~ shipment;
49.72 +
49.73 +end;
50.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
50.2 +++ b/examples/dbf/ForestMgt_Model_I_GIS_dbf.mod Mon Dec 06 13:09:21 2010 +0100
50.3 @@ -0,0 +1,226 @@
50.4 +# Model I Forest Estate Modelling using GLPK/MathProg
50.5 +# Reading and writing dbf files
50.6 +
50.7 +# by Noli Sicad --- nsicad@gmail.com
50.8 +# 18 December 2009
50.9 +
50.10 +# Forest Management 4th Edition
50.11 +# by Lawrence Davis, K. Norman Johnson, Pete Bettinger, Theodore Howard
50.12 +# Chapter 11 - Daniel Pickett
50.13 +# http://warnell.forestry.uga.edu/Warnell/Bettinger/mgtbook/index.htm
50.14 +
50.15 +# Model I Formulation
50.16 +
50.17 +/* Note: This is not the full LP model mentioned in the book.
50.18 +Some of the constraints are deliberately omitted in this model for the purpose of clarity.
50.19 +
50.20 +The features of MathProg in this example are:
50.21 +* reading and writing dbf from regular dbf files,
50.22 +* reading dbf file (database of shapefile (stands.shp)) (e.g. area parameter),
50.23 +* using the area data in the constraints and
50.24 +* writing dbf file from result of LP model.
50.25 +
50.26 +Model I - Harvest Scheduling formulation for Sustainable Forest Management (SFM)
50.27 +
50.28 +Features are:
50.29 +* Net Present Value for the objective function (Revenue - Cost)
50.30 +* Harvest Constraints by period - Sustainable Yield per Period
50.31 +* Even-Flow Constraint / Volume - Harvest Flow Constraint - Alpha (1-Apha)
50.32 +* Even-Flow Constraint / Volume - Harvest Flow Constraint - Beta (1 +Beta)
50.33 +* Forest / Land Constraint -- Total Area of the forest
50.34 +* Forest Stand Constraint -- Individual stands
50.35 +
50.36 +What is next? -- Forest Mgt Carbon Accounting for Climate Change
50.37 +
50.38 +Note: The model file that the data containing in
50.39 +the dbf files is public domain material (so it is compatible with the
50.40 +GNU GPL) and data can be found in
50.41 +http://warnell.forestry.uga.edu/Warnell/Bettinger/mgtbook/index.htm
50.42 +
50.43 +# Noli Sicad --- nsicad@gmail.com
50.44 +
50.45 +*/
50.46 +
50.47 +set G_STAND_TYPE; # A, B, C
50.48 +
50.49 +set I_CULTURAL_PRES;
50.50 +set J_MGT_YEAR;
50.51 +
50.52 +param K_PERIOD;
50.53 +param Forest_Cost{G_STAND_TYPE,I_CULTURAL_PRES, J_MGT_YEAR}; # cost
50.54 +
50.55 +param Yield_Table_Vol{G_STAND_TYPE, I_CULTURAL_PRES, J_MGT_YEAR, 1..K_PERIOD} >= 0;
50.56 +
50.57 +
50.58 +param Alpha >= 0;
50.59 +param Beta >= 0;
50.60 +
50.61 +param TCost_Table{G_STAND_TYPE, I_CULTURAL_PRES, J_MGT_YEAR, 1..K_PERIOD} >= 0;
50.62 +
50.63 +param NetRev_Table{G_STAND_TYPE, I_CULTURAL_PRES, J_MGT_YEAR, 1..K_PERIOD};
50.64 +
50.65 +
50.66 +var XForestLand{g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} >= 0;
50.67 +
50.68 +
50.69 +#reading dbf tables
50.70 +table tab IN "xBASE" "standtype.dbf": G_STAND_TYPE <- [STAND];
50.71 +display G_STAND_TYPE;
50.72 +
50.73 +
50.74 +table tab2 IN "xBASE" "cultural_pres.dbf": I_CULTURAL_PRES <- [CUL_PRES];
50.75 +display I_CULTURAL_PRES;
50.76 +
50.77 +table tab3 IN "xBASE" "mgt_year.dbf": J_MGT_YEAR <- [MGT_YEAR];
50.78 +display J_MGT_YEAR;
50.79 +
50.80 +/*
50.81 +param Forest_Cost{G_STAND_TYPE,I_CULTURAL_PRES, J_MGT_YEAR} default 0; # cost
50.82 +*/
50.83 +
50.84 +set S1, dimen 3;
50.85 +table tab4 IN "xBASE" "Forest_Cost.dbf": S1 <- [STAND, CUL_PRES, MGT_YEAR],Forest_Cost ~FCOST;
50.86 +display Forest_Cost;
50.87 +
50.88 +set S2, dimen 4;
50.89 +table tab5 IN "xBASE" "Yield_Table_Vol.dbf": S2 <- [STAND, CUL_PRES, MGT_YEAR, PERIOD],Yield_Table_Vol ~YIELD;
50.90 +display Yield_Table_Vol;
50.91 +
50.92 +set S3, dimen 4;
50.93 +table tab5 IN "xBASE" "TCost_Table.dbf": S3 <- [STAND, CUL_PRES, MGT_YEAR, PERIOD],TCost_Table ~TCOST;
50.94 +display TCost_Table;
50.95 +
50.96 +
50.97 +set S4, dimen 4;
50.98 +table tab5 IN "xBASE" "NetRev_Table.dbf": S4 <- [STAND, CUL_PRES, MGT_YEAR, PERIOD],NetRev_Table ~NETREV;
50.99 +display NetRev_Table;
50.100 +
50.101 +
50.102 +param MGT;
50.103 +
50.104 +param Area_Stand_Indi{g in G_STAND_TYPE, m in 1..MGT} default 0;
50.105 +
50.106 +set ST, dimen 2;
50.107 +table tab5 IN "xBASE" "stands.dbf": ST <- [VEG_TYPE, MGT], Area_Stand_Indi ~ACRES;
50.108 +display Area_Stand_Indi;
50.109 +
50.110 +param Area_Stand_Type{g in G_STAND_TYPE}:= sum {m in 1..MGT } Area_Stand_Indi[g,m];
50.111 +display Area_Stand_Type;
50.112 +
50.113 +
50.114 +param Total_Area := sum {g in G_STAND_TYPE, m in 1..MGT } Area_Stand_Indi[g,m];
50.115 +display Total_Area;
50.116 +
50.117 +param Harvest_Min_Vol_Period;
50.118 +
50.119 +
50.120 +var NetPresentValue;
50.121 +
50.122 +# Objective function
50.123 +maximize Net_Present_Value: NetPresentValue;
50.124 +
50.125 +subject to NPV:
50.126 + NetPresentValue = sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} Forest_Cost[g,i,j] * XForestLand[g,i,j];
50.127 +
50.128 +# Harvest Constraint by Period
50.129 +subject to Harvest_Period_H {k in 1..K_PERIOD}:
50.130 + sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k] * XForestLand[g,i,j] >= Harvest_Min_Vol_Period;
50.131 +
50.132 +
50.133 +#Even-Flow Constraint / Volume - Harvest Flow Constraint - Alpha
50.134 +subject to Even_Flow_Constaints_Alpha {k in 6..K_PERIOD-1}:
50.135 + (1 - Alpha) * sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k] * XForestLand[g,i,j] -
50.136 + sum {g in G_STAND_TYPE,i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k+1] * XForestLand[g,i,j] <= 0;
50.137 +
50.138 +# Even-Flow Constraint / Volume - Harvest Flow Constraint - Beta
50.139 +subject to Even_Flow_Constaints_Beta {k in 6..K_PERIOD-1}:
50.140 + (1 + Beta) * sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k] * XForestLand[g,i,j] -
50.141 + sum {g in G_STAND_TYPE,i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k+1] * XForestLand[g,i,j] >= 0;
50.142 +
50.143 +# Forest / Land Constraints
50.144 +subject to Total_Area_Constraint:
50.145 + sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} XForestLand[g,i,j] <= Total_Area;
50.146 +display Total_Area;
50.147 +
50.148 +# Forest / Land Constraints for A B C
50.149 +subject to Area {g in G_STAND_TYPE}:
50.150 + sum {i in I_CULTURAL_PRES,j in J_MGT_YEAR} XForestLand[g,i,j] = Area_Stand_Type[g];
50.151 +
50.152 +
50.153 +
50.154 +solve;
50.155 +#RESULT SECTION
50.156 +printf '#################################\n';
50.157 +printf 'Forest Management Model I - Noli Sicad\n';
50.158 +printf '\n';
50.159 +printf 'Net Present Value = %.2f\n', NetPresentValue;
50.160 +printf '\n';
50.161 +
50.162 +printf '\n';
50.163 +printf 'Variables\n';
50.164 +printf 'Stand_Type Age_Class Mgt_Presc Sign Value \n';
50.165 +printf{g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR}:'%5s %10s %11s = %10.2f\n', g,i,j, XForestLand[g,i,j];
50.166 +printf '\n';
50.167 +
50.168 +printf 'Constraints\n';
50.169 +printf 'Period Harvest Sign \n';
50.170 +for {k in 1..K_PERIOD} {
50.171 + printf '%5s %10.2f >= %.3f\n', k, sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k] * XForestLand[g,i,j], Harvest_Min_Vol_Period;
50.172 + }
50.173 +
50.174 +# xbase (dbf) output
50.175 +table Harvest{k in 1..K_PERIOD} OUT "xBASE" "HarvestArea1.dbf" "N(5)N(15,2)" : k ~ Period, (sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k] * XForestLand[g,i,j]) ~ H_Area;
50.176 +
50.177 +# xbase (dbf) read
50.178 +set S, dimen 2;
50.179 +table tab2 IN "xBASE" "HarvestArea1.dbf": S <- [Period, H_Area];
50.180 +display S;
50.181 +
50.182 +
50.183 +
50.184 +
50.185 +printf '\n';
50.186 +printf 'Constraint\n';
50.187 +printf 'Harvest Period\n';
50.188 +printf 'Type AgeClass PrescMgt Period Value\n';
50.189 +printf{g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR, k in 1..K_PERIOD}:'%5s %11s %11s %5s %10.2f\n', g,i,j, k, (Yield_Table_Vol[g,i,j,k] * XForestLand[g,i,j]);
50.190 +
50.191 +
50.192 +printf 'Even_Flow_Constaint_Alpha (1-Alpha)\n';
50.193 +printf 'Period Sign \n';
50.194 +for {k in 6..K_PERIOD-1} {
50.195 + printf "%s %10.2f <= %s\n", k, ((1 - Alpha) * sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k] * XForestLand[g,i,j] - sum {g in G_STAND_TYPE,i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k+1] * XForestLand[g,i,j]),0;
50.196 + }
50.197 +printf '\n';
50.198 +
50.199 +
50.200 +# Forest / Land Constraints
50.201 +printf '\n';
50.202 +printf 'Total Area Constraint\n';
50.203 +printf 'Type AgeClass PrescMgt Value Sign Total_Area \n';
50.204 +printf '%5s <= %.3f\n',sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} XForestLand[g,i,j], Total_Area;
50.205 +
50.206 +printf 'Area\n';
50.207 +printf 'Area Value Sign Areas_Stand\n';
50.208 +for {g in G_STAND_TYPE} {
50.209 + printf '%5s %10.2f <= %.3f\n', g, sum {i in I_CULTURAL_PRES,j in J_MGT_YEAR} XForestLand[g,i,j], Area_Stand_Type[g];
50.210 + }
50.211 +
50.212 +
50.213 +#DATA SECTION
50.214 +
50.215 +data;
50.216 +
50.217 +# Most of the data has been moved to dbf format
50.218 +
50.219 +param MGT:=31;
50.220 +
50.221 +param K_PERIOD:= 7;
50.222 +
50.223 +param Alpha:= 0.20;
50.224 +param Beta:= 0.20;
50.225 +
50.226 +param Harvest_Min_Vol_Period:= 12000;
50.227 +
50.228 +end;
50.229 +
51.1 Binary file examples/dbf/Forest_Cost.dbf has changed
52.1 Binary file examples/dbf/NetRev_Table.dbf has changed
53.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
53.2 +++ b/examples/dbf/README Mon Dec 06 13:09:21 2010 +0100
53.3 @@ -0,0 +1,2 @@
53.4 +This subdirectory contains an example MathProg model that demonstrates
53.5 +using data tables in DBF format.
54.1 Binary file examples/dbf/TCost_Table.dbf has changed
55.1 Binary file examples/dbf/Yield_Table_Vol.dbf has changed
56.1 Binary file examples/dbf/cultural_pres.dbf has changed
57.1 Binary file examples/dbf/mgt_year.dbf has changed
58.1 Binary file examples/dbf/stands.dbf has changed
59.1 Binary file examples/dbf/standtype.dbf has changed
60.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
60.2 +++ b/examples/dea.mod Mon Dec 06 13:09:21 2010 +0100
60.3 @@ -0,0 +1,222 @@
60.4 +/* Data Envelopment Analysis (DEA)
60.5 + *
60.6 + * DEA quantifies the relative efficiency of decision making units (DMUs) by
60.7 + * finding the efficient frontier in multiple input multiple output data. The
60.8 + * inputs are resources (eg. number of employees, available machines, ...),
60.9 + * the outputs are productive outputs (eg. contracts made, total sales, ...).
60.10 + * The method is non-parametric. More details are available in the paper
60.11 + * below.
60.12 + *
60.13 + * Models according to: Seiford, Threall, "Recent developments in DEA", 1990.
60.14 + *
60.15 + * Implementation: Sebastian Nowozin <nowozin@gmail.com>
60.16 + */
60.17 +
60.18 +### SETS ###
60.19 +
60.20 +set dmus; # Decision Making Units (DMU)
60.21 +set inputs; # Input parameters
60.22 +set outputs; # Output parameters
60.23 +
60.24 +
60.25 +### PARAMETERS ###
60.26 +
60.27 +param input_data{dmus,inputs} >= 0;
60.28 +param output_data{dmus,outputs} >= 0;
60.29 +
60.30 +
60.31 +### PROGRAM ###
60.32 +
60.33 +var theta{dmus} >= 0;
60.34 +var lambda{dmus,dmus} >= 0;
60.35 +
60.36 +minimize inefficiency: sum{td in dmus} theta[td];
60.37 +
60.38 +s.t. output_lower_limit{o in outputs, td in dmus}:
60.39 + sum{d in dmus} lambda[d,td]*output_data[d,o] >= output_data[td,o];
60.40 +s.t. input_upper_limit{i in inputs, td in dmus}:
60.41 + sum{d in dmus} lambda[d,td]*input_data[d,i] <= theta[td]*input_data[td,i];
60.42 +
60.43 + s.t. PI1{td in dmus}:
60.44 + sum{d in dmus} lambda[d,td] = 1;
60.45 +/*
60.46 +possibilities:
60.47 + i) (no constraint)
60.48 + ii) s.t. PI1{td in dmus}:
60.49 + sum{d in dmus} lambda[d,td] <= 1;
60.50 + iii) s.t. PI1{td in dmus}:
60.51 + sum{d in dmus} lambda[d,td] >= 1;
60.52 +*/
60.53 +
60.54 +
60.55 +### SOLVE AND PRINT SOLUTION ###
60.56 +
60.57 +solve;
60.58 +
60.59 +printf "DMU\tEfficiency\n";
60.60 +for {td in dmus} {
60.61 + printf "%s\t%1.4f\n", td, theta[td];
60.62 +}
60.63 +
60.64 +### DATA ###
60.65 +
60.66 +data;
60.67 +
60.68 +set dmus := 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
60.69 + 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
60.70 + 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
60.71 + 61 62 63 64 65 66 67 68 69 ;
60.72 +set inputs := AvgInventory LaborCost OperatingCost Population ;
60.73 +set outputs := PrescrVol kDollarValue ;
60.74 +
60.75 +param input_data default 0.0 :
60.76 +
60.77 + AvgInventory LaborCost OperatingCost Population :=
60.78 +
60.79 +1 8000 17030 1280 1410
60.80 +2 9000 25890 2779 1523
60.81 +3 13694 29076 2372 1354
60.82 +4 4250 17506 1385 822
60.83 +5 6500 23208 639 746
60.84 +6 7000 12946 802 1281
60.85 +7 4500 18001 1130 1016
60.86 +8 5000 14473 1097 1070
60.87 +9 27000 31760 5559 1694
60.88 +10 21560 50972 15010 1910
60.89 +11 15000 39523 4799 1745
60.90 +12 8500 13076 3489 1353
60.91 +13 35000 35427 1704 500
60.92 +14 18000 27554 2882 1016
60.93 +15 59750 53848 14208 2500
60.94 +16 19200 38253 1480 2293
60.95 +17 40000 109404 83016 2718
60.96 +18 8466 18198 1278 2877
60.97 +19 16000 40891 7599 4150
60.98 +20 10000 45444 5556 4421
60.99 +21 25000 35623 2121 3883
60.100 +22 14000 20192 5515 3519
60.101 +23 12500 34973 10475 32366
60.102 +24 17260 32284 14498 3393
60.103 +25 7000 17920 7585 4489
60.104 +26 14000 42094 3742 2217
60.105 +27 16400 35422 14236 4641
60.106 +28 13000 19100 3529 5968
60.107 +29 30000 72167 8656 8715
60.108 +30 12530 19970 1714 5968
60.109 +31 31500 39183 4919 5607
60.110 +32 10000 32048 3483 7324
60.111 +33 22000 68877 12279 8685
60.112 +34 10000 29812 3332 8685
60.113 +35 16000 47686 2507 5420
60.114 +36 10000 33415 4738 7703
60.115 +37 9000 12359 4603 4665
60.116 +38 16439 23614 2989 6317
60.117 +39 14500 36069 1793 31839
60.118 +40 39000 76307 9539 15619
60.119 +41 24927 40706 12661 30213
60.120 +42 13858 39267 4609 34719
60.121 +43 33375 29509 11323 31839
60.122 +44 29044 44482 5542 34719
60.123 +45 32257 61365 20550 32366
60.124 +46 8800 49671 3306 43561
60.125 +47 47000 40425 10396 31263
60.126 +48 12000 33034 4915 31263
60.127 +49 28000 69163 4688 15173
60.128 +50 13300 28931 16735 73064
60.129 +51 13500 29758 4260 62309
60.130 +52 24000 40927 8285 23166
60.131 +53 16000 40403 2131 99836
60.132 +54 17000 38730 2539 60348
60.133 +55 25000 35978 2502 99836
60.134 +56 16000 37509 6278 99836
60.135 +57 20000 46950 10715 85925
60.136 +58 14000 35966 3144 85925
60.137 +59 22000 68318 8015 108987
60.138 +60 21879 69537 7778 108987
60.139 +61 15000 25425 2812 201404
60.140 +62 10000 19508 2454 201404
60.141 +63 20000 28191 3367 201404
60.142 +64 18000 37073 8624 108987
60.143 +65 19051 23763 3496 201404
60.144 +66 15000 28642 3366 201404
60.145 +67 10000 35919 3868 201404
60.146 +68 24000 54653 26494 108987
60.147 +69 1800 6276 3413 60348
60.148 + ;
60.149 +
60.150 +param output_data default 0.0 :
60.151 +
60.152 + PrescrVol kDollarValue :=
60.153 +
60.154 +1 12293 61.00
60.155 +2 18400 92.00
60.156 +3 16789 92.65
60.157 +4 10700 45.00
60.158 +5 9800 50.00
60.159 +6 6500 29.00
60.160 +7 8200 56.00
60.161 +8 8680 45.00
60.162 +9 33800 183.00
60.163 +10 23710 156.00
60.164 +11 24000 120.00
60.165 +12 17500 75.00
60.166 +13 25000 130.00
60.167 +14 26000 122.00
60.168 +15 26830 178.513
60.169 +16 16600 106.00
60.170 +17 90000 450.00
60.171 +18 11140 73.624
60.172 +19 25868 136.00
60.173 +20 32700 191.295
60.174 +21 29117 152.864
60.175 +22 18000 100.00
60.176 +23 11100 60.00
60.177 +24 23030 137.778
60.178 +25 10656 58.00
60.179 +26 24682 152.095
60.180 +27 26908 120.00
60.181 +28 16464 80.00
60.182 +29 57000 321.00
60.183 +30 17532 94.747
60.184 +31 30035 168.00
60.185 +32 16000 100.00
60.186 +33 63700 277.00
60.187 +34 18000 90.00
60.188 +35 27339 139.134
60.189 +36 19500 116.00
60.190 +37 13000 80.00
60.191 +38 15370 102.00
60.192 +39 18446 90.00
60.193 +40 56000 260.00
60.194 +41 73845 364.951
60.195 +42 28600 145.00
60.196 +43 27000 243.00
60.197 +44 52423 279.816
60.198 +45 73759 363.388
60.199 +46 20500 80.00
60.200 +47 27100 115.00
60.201 +48 15000 110.00
60.202 +49 50895 277.852
60.203 +50 19707 128.00
60.204 +51 17994 78.80
60.205 +52 36135 167.222
60.206 +53 30000 153.00
60.207 +54 26195 125.00
60.208 +55 28000 216.00
60.209 +56 24658 152.551
60.210 +57 36850 190.00
60.211 +58 29250 183.69
60.212 +59 50000 250.00
60.213 +60 40078 265.443
60.214 +61 20200 110.00
60.215 +62 12500 75.00
60.216 +63 30890 195.00
60.217 +64 31000 175.00
60.218 +65 31277 192.992
60.219 +66 11500 75.00
60.220 +67 30000 175.668
60.221 +68 38383 190.00
60.222 +69 2075 8.650
60.223 + ;
60.224 +
60.225 +end;
61.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
61.2 +++ b/examples/diet.mod Mon Dec 06 13:09:21 2010 +0100
61.3 @@ -0,0 +1,99 @@
61.4 +# STIGLER'S NUTRITION MODEL
61.5 +#
61.6 +# This model determines a least cost diet which meets the daily
61.7 +# allowances of nutrients for a moderately active man weighing 154 lbs.
61.8 +#
61.9 +# References:
61.10 +# Dantzig G B, "Linear Programming and Extensions."
61.11 +# Princeton University Press, Princeton, New Jersey, 1963,
61.12 +# Chapter 27-1.
61.13 +
61.14 +set N;
61.15 +/* nutrients */
61.16 +
61.17 +set F;
61.18 +/* foods */
61.19 +
61.20 +param b{N};
61.21 +/* required daily allowances of nutrients */
61.22 +
61.23 +param a{F,N};
61.24 +/* nutritive value of foods (per dollar spent) */
61.25 +
61.26 +var x{f in F} >= 0;
61.27 +/* dollars of food f to be purchased daily */
61.28 +
61.29 +s.t. nb{n in N}: sum{f in F} a[f,n] * x[f] = b[n];
61.30 +/* nutrient balance (units) */
61.31 +
61.32 +minimize cost: sum{f in F} x[f];
61.33 +/* total food bill (dollars) */
61.34 +
61.35 +data;
61.36 +
61.37 +param : N : b :=
61.38 + Calorie 3 /* thousands */
61.39 + Protein 70 /* grams */
61.40 + Calcium 0.8 /* grams */
61.41 + Iron 12 /* milligrams */
61.42 + Vitamin-A 5 /* thousands IUs */
61.43 + Vitamin-B1 1.8 /* milligrams */
61.44 + Vitamin-B2 2.7 /* milligrams */
61.45 + Niacin 18 /* milligrams */
61.46 + Vitamin-C 75 /* milligrams */ ;
61.47 +
61.48 +set F := Wheat Cornmeal Cannedmilk Margarine Cheese Peanut-B Lard
61.49 + Liver Porkroast Salmon Greenbeans Cabbage Onions Potatoes
61.50 + Spinach Sweet-Pot Peaches Prunes Limabeans Navybeans;
61.51 +
61.52 +param a default 0
61.53 +
61.54 +: Calorie Protein Calcium Iron Vitamin-A Vitamin-B1 :=
61.55 +# (1000) (g) (g) (mg) (1000IU) (mg)
61.56 +
61.57 +Wheat 44.7 1411 2.0 365 . 55.4
61.58 +Cornmeal 36 897 1.7 99 30.9 17.4
61.59 +Cannedmilk 8.4 422 15.1 9 26 3
61.60 +Margarine 20.6 17 .6 6 55.8 .2
61.61 +Cheese 7.4 448 16.4 19 28.1 .8
61.62 +Peanut-B 15.7 661 1 48 . 9.6
61.63 +Lard 41.7 . . . .2 .
61.64 +Liver 2.2 333 .2 139 169.2 6.4
61.65 +Porkroast 4.4 249 .3 37 . 18.2
61.66 +Salmon 5.8 705 6.8 45 3.5 1
61.67 +Greenbeans 2.4 138 3.7 80 69 4.3
61.68 +Cabbage 2.6 125 4 36 7.2 9
61.69 +Onions 5.8 166 3.8 59 16.6 4.7
61.70 +Potatoes 14.3 336 1.8 118 6.7 29.4
61.71 +Spinach 1.1 106 . 138 918.4 5.7
61.72 +Sweet-Pot 9.6 138 2.7 54 290.7 8.4
61.73 +Peaches 8.5 87 1.7 173 86.8 1.2
61.74 +Prunes 12.8 99 2.5 154 85.7 3.9
61.75 +Limabeans 17.4 1055 3.7 459 5.1 26.9
61.76 +Navybeans 26.9 1691 11.4 792 . 38.4
61.77 +
61.78 +: Vitamin-B2 Niacin Vitamin-C :=
61.79 +# (mg) (mg) (mg)
61.80 +
61.81 +Wheat 33.3 441 .
61.82 +Cornmeal 7.9 106 .
61.83 +Cannedmilk 23.5 11 60
61.84 +Margarine . . .
61.85 +Cheese 10.3 4 .
61.86 +Peanut-B 8.1 471 .
61.87 +Lard .5 5 .
61.88 +Liver 50.8 316 525
61.89 +Porkroast 3.6 79 .
61.90 +Salmon 4.9 209 .
61.91 +Greenbeans 5.8 37 862
61.92 +Cabbage 4.5 26 5369
61.93 +Onions 5.9 21 1184
61.94 +Potatoes 7.1 198 2522
61.95 +Spinach 13.8 33 2755
61.96 +Sweet-Pot 5.4 83 1912
61.97 +Peaches 4.3 55 57
61.98 +Prunes 4.3 65 257
61.99 +Limabeans 38.2 93 .
61.100 +Navybeans 24.6 217 . ;
61.101 +
61.102 +end;
62.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
62.2 +++ b/examples/dist.mod Mon Dec 06 13:09:21 2010 +0100
62.3 @@ -0,0 +1,565 @@
62.4 +# DIST, a product distribution model
62.5 +#
62.6 +# References:
62.7 +# Robert Fourer, David M. Gay and Brian W. Kernighan, "A Modeling Language
62.8 +# for Mathematical Programming." Management Science 36 (1990) 519-554.
62.9 +
62.10 +### SHIPPING SETS AND PARAMETERS ###
62.11 +
62.12 +set whse 'warehouses'; # Locations from which demand is satisfied
62.13 +
62.14 +set dctr 'distribution centers' within whse;
62.15 +
62.16 + # Locations from which product may be shipped
62.17 +
62.18 +param sc 'shipping cost' {dctr,whse} >= 0;
62.19 +
62.20 + # Shipping costs, to whse from dctr, in $ / 100 lb
62.21 +
62.22 +param huge 'largest shipping cost' > 0;
62.23 +
62.24 + # Largest cost allowed for a usable shipping route
62.25 +
62.26 +param msr 'minimum size restriction' {dctr,whse} logical;
62.27 +
62.28 + # True indicates a minimum-size restriction on
62.29 + # direct shipments using this dctr --> whse route
62.30 +
62.31 +param dsr 'direct shipment requirement' {dctr} >= 0;
62.32 +
62.33 + # Minimum total demand, in pallets, needed to
62.34 + # allow shipment on routes subject to the
62.35 + # minimum size restriction
62.36 +
62.37 +### PLANT SETS AND PARAMETERS ###
62.38 +
62.39 +set fact 'factories' within dctr;
62.40 +
62.41 + # Locations where product is manufactured
62.42 +
62.43 +param rtmin 'regular-time total minimum' >= 0;
62.44 +
62.45 + # Lower limit on (average) total regular-time
62.46 + # crews employed at all factories
62.47 +
62.48 +param rtmax 'regular-time total maximum' >= rtmin;
62.49 +
62.50 + # Upper limit on (average) total regular-time
62.51 + # crews employed at all factories
62.52 +
62.53 +param otmin 'overtime total minimum' >= 0;
62.54 +
62.55 + # Lower limit on total overtime hours at all factories
62.56 +
62.57 +param otmax 'overtime total maximum' >= otmin;
62.58 +
62.59 + # Upper limit on total overtime hours at all factories
62.60 +
62.61 +param rmin 'regular-time minimums' {fact} >= 0;
62.62 +
62.63 + # Lower limits on (average) regular-time crews
62.64 +
62.65 +param rmax 'regular-time maximums' {f in fact} >= rmin[f];
62.66 +
62.67 + # Upper limits on (average) regular-time crews
62.68 +
62.69 +param omin 'overtime minimums' {fact} >= 0;
62.70 +
62.71 + # Lower limits on overtime hours
62.72 +
62.73 +param omax 'overtime maximums' {f in fact} >= omin[f];
62.74 +
62.75 + # Upper limits on overtime hours
62.76 +
62.77 +param hd 'hours per day' {fact} >= 0;
62.78 +
62.79 + # Regular-time hours per working day
62.80 +
62.81 +param dp 'days in period' {fact} > 0;
62.82 +
62.83 + # Working days in the current planning period
62.84 +
62.85 +### PRODUCT SETS AND PARAMETERS ###
62.86 +
62.87 +set prd 'products'; # Elements of the product group
62.88 +
62.89 +param wt 'weight' {prd} > 0;
62.90 +
62.91 + # Weight in 100 lb / 1000 cases
62.92 +
62.93 +param cpp 'cases per pallet' {prd} > 0;
62.94 +
62.95 + # Cases of product per shipping pallet
62.96 +
62.97 +param tc 'transshipment cost' {prd} >= 0;
62.98 +
62.99 + # Transshipment cost in $ / 1000 cases
62.100 +
62.101 +param pt 'production time' {prd,fact} >= 0;
62.102 +
62.103 + # Crew-hours to produce 1000 cases
62.104 +
62.105 +param rpc 'regular-time production cost' {prd,fact} >= 0;
62.106 +
62.107 + # Cost of production on regular time,
62.108 + # in $ / 1000 cases
62.109 +
62.110 +param opc 'overtime production cost' {prd,fact} >= 0;
62.111 +
62.112 + # Cost of production on overtime, in $ / 1000 cases
62.113 +
62.114 +### DEMAND SETS AND PARAMETERS ###
62.115 +
62.116 +param dt 'total demand' {prd} >= 0;
62.117 +
62.118 + # Total demands for products, in 1000s
62.119 +
62.120 +param ds 'demand shares' {prd,whse} >= 0.0, <= 1.0;
62.121 +
62.122 + # Historical demand data, from which each
62.123 + # warehouse's share of total demand is deduced
62.124 +
62.125 +param dstot {p in prd} := sum {w in whse} ds[p,w];
62.126 +
62.127 + # Total of demand shares; should be 1, but often isn't
62.128 +
62.129 +param dem 'demand' {p in prd, w in whse} := dt[p] * ds[p,w] / dstot[p];
62.130 +
62.131 + # Projected demands to be satisfied, in 1000s
62.132 +
62.133 +set rt 'shipping routes available' :=
62.134 +
62.135 + {d in dctr, w in whse:
62.136 + d <> w and sc[d,w] < huge and
62.137 + (w in dctr or sum {p in prd} dem[p,w] > 0) and
62.138 + not (msr[d,w] and sum {p in prd} 1000*dem[p,w]/cpp[p] < dsr[d]) };
62.139 +
62.140 + # List of ordered pairs that represent routes
62.141 + # on which shipments are allowed
62.142 +
62.143 +### VARIABLES ###
62.144 +
62.145 +var Rprd 'regular-time production' {prd,fact} >= 0;
62.146 +
62.147 + # Regular-time production of each product
62.148 + # at each factory, in 1000s of cases
62.149 +
62.150 +var Oprd 'overtime production' {prd,fact} >= 0;
62.151 +
62.152 + # Overtime production of each product
62.153 + # at each factory, in 1000s of cases
62.154 +
62.155 +var Ship 'shipments' {prd,rt} >= 0;
62.156 +
62.157 + # Shipments of each product on each allowed route,
62.158 + # in 1000s of cases
62.159 +
62.160 +var Trans 'transshipments' {prd,dctr} >= 0;
62.161 +
62.162 + # Transshipments of each product at each
62.163 + # distribution center, in 1000s of cases
62.164 +
62.165 +### OBJECTIVE ###
62.166 +
62.167 +minimize cost: sum {p in prd, f in fact} rpc[p,f] * Rprd[p,f] +
62.168 + sum {p in prd, f in fact} opc[p,f] * Oprd[p,f] +
62.169 + sum {p in prd, (d,w) in rt} sc[d,w] * wt[p] * Ship[p,d,w] +
62.170 + sum {p in prd, d in dctr} tc[p] * Trans[p,d];
62.171 +
62.172 + # Total cost: regular production, overtime
62.173 + # production, shipping, and transshipment
62.174 +
62.175 +### CONSTRAINTS ###
62.176 +
62.177 +rtlim 'regular-time total limits':
62.178 +
62.179 + rtmin <= sum {p in prd, f in fact}
62.180 + (pt[p,f] * Rprd[p,f]) / (dp[f] * hd[f]) <= rtmax;
62.181 +
62.182 + # Total crews must lie between limits
62.183 +
62.184 +otlim 'overtime total limits':
62.185 +
62.186 + otmin <= sum {p in prd, f in fact} pt[p,f] * Oprd[p,f] <= otmax;
62.187 +
62.188 + # Total overtime must lie between limits
62.189 +
62.190 +rlim 'regular-time limits' {f in fact}:
62.191 +
62.192 + rmin[f] <= sum {p in prd}
62.193 + (pt[p,f] * Rprd[p,f]) / (dp[f] * hd[f]) <= rmax[f];
62.194 +
62.195 + # Crews at each factory must lie between limits
62.196 +
62.197 +olim 'overtime limits' {f in fact}:
62.198 +
62.199 + omin[f] <= sum {p in prd} pt[p,f] * Oprd[p,f] <= omax[f];
62.200 +
62.201 + # Overtime at each factory must lie between limits
62.202 +
62.203 +noRprd 'no regular production' {p in prd, f in fact: rpc[p,f] = 0}:
62.204 +
62.205 + Rprd[p,f] = 0;
62.206 +
62.207 +noOprd 'no overtime production' {p in prd, f in fact: opc[p,f] = 0}:
62.208 +
62.209 + Oprd[p,f] = 0; # Do not produce where specified cost is zero
62.210 +
62.211 +bal 'material balance' {p in prd, w in whse}:
62.212 +
62.213 + sum {(v,w) in rt}
62.214 + Ship [p,v,w] + (if w in fact then Rprd[p,w] + Oprd[p,w]) =
62.215 +
62.216 + dem[p,w] + (if w in dctr then sum {(w,v) in rt} Ship[p,w,v]);
62.217 +
62.218 + # Demand is satisfied by shipment into warehouse
62.219 + # plus production (if it is a factory)
62.220 + # minus shipment out (if it is a distn. center)
62.221 +
62.222 +trdef 'transshipment definition' {p in prd, d in dctr}:
62.223 +
62.224 + Trans[p,d] >= sum {(d,w) in rt} Ship [p,d,w] -
62.225 + (if d in fact then Rprd[p,d] + Oprd[p,d]);
62.226 +
62.227 + # Transshipment at a distribution center is
62.228 + # shipments out less production (if any)
62.229 +
62.230 +### DATA -- 3 PRODUCTS ###
62.231 +
62.232 +data;
62.233 +
62.234 +set prd := 18REG 24REG 24PRO ;
62.235 +
62.236 +set whse := w01 w02 w03 w04 w05 w06 w08 w09 w12 w14 w15 w17
62.237 + w18 w19 w20 w21 w24 w25 w26 w27 w28 w29 w30 w31
62.238 + w32 w33 w34 w35 w36 w37 w38 w39 w40 w41 w42 w43
62.239 + w44 w45 w46 w47 w48 w49 w50 w51 w53 w54 w55 w56
62.240 + w57 w59 w60 w61 w62 w63 w64 w65 w66 w68 w69 w71
62.241 + w72 w73 w74 w75 w76 w77 w78 w79 w80 w81 w82 w83
62.242 + w84 w85 w86 w87 w89 w90 w91 w92 w93 w94 w95 w96
62.243 + w98 x22 x23 ;
62.244 +
62.245 +set dctr := w01 w02 w03 w04 w05 w62 w76 w96 ;
62.246 +
62.247 +set fact := w01 w05 w96 ;
62.248 +
62.249 +param huge := 99. ;
62.250 +
62.251 +param rtmin := 0.0 ;
62.252 +param rtmax := 8.0 ;
62.253 +
62.254 +param otmin := 0.0 ;
62.255 +param otmax := 96.0 ;
62.256 +
62.257 +param rmin := w01 0.00 w05 0.00 w96 0.00 ;
62.258 +param rmax := w01 3.00 w05 2.00 w96 3.00 ;
62.259 +
62.260 +param omin := w01 0.0 w05 0.0 w96 0.0 ;
62.261 +param omax := w01 48.0 w05 0.0 w96 48.0 ;
62.262 +
62.263 +param hd := w01 8.0 w05 8.0 w96 8.0 ;
62.264 +
62.265 +param dp := w01 19.0 w05 19.0 w96 19.0 ;
62.266 +
62.267 +param wt := 18REG 47.3 24REG 63.0 24PRO 63.0 ;
62.268 +
62.269 +param tc := 18REG 40.00 24REG 45.00 24PRO 45.00 ;
62.270 +
62.271 +param dt := 18REG 376.0 24REG 172.4 24PRO 316.3 ;
62.272 +
62.273 +param cpp := 18REG 102. 24REG 91. 24PRO 91. ;
62.274 +
62.275 +param dsr := w01 96. w02 96. w03 96. w04 96. w05 96.
62.276 + w62 96. w76 96. w96 96. ;
62.277 +
62.278 +param pt (tr) :
62.279 +
62.280 + 18REG 24REG 24PRO :=
62.281 +
62.282 +w01 1.194 1.429 1.429
62.283 +w05 1.194 1.509 1.509
62.284 +w96 0.000 1.600 1.600 ;
62.285 +
62.286 +param rpc (tr) :
62.287 +
62.288 + 18REG 24REG 24PRO :=
62.289 +
62.290 +w01 2119. 2653. 2617.
62.291 +w05 2489. 3182. 3176.
62.292 +w96 0. 2925. 2918. ;
62.293 +
62.294 +param opc (tr) :
62.295 +
62.296 + 18REG 24REG 24PRO :=
62.297 +
62.298 +w01 2903. 3585. 3579.
62.299 +w05 0. 0. 0.
62.300 +w96 0. 3629. 3622. ;
62.301 +
62.302 +param sc default 99.99 (tr) :
62.303 +
62.304 + w01 w02 w03 w04 w05 w62 w76 w96 :=
62.305 +
62.306 +w01 . 2.97 1.14 2.08 2.37 1.26 2.42 1.43
62.307 +w02 4.74 . 4.17 6.12 7.41 3.78 7.04 5.21
62.308 +w03 2.45 4.74 . 3.67 2.84 0.90 2.41 2.55
62.309 +w04 1.74 5.03 2.43 . 3.19 2.45 2.69 0.58
62.310 +w05 2.70 5.16 2.84 2.85 . 3.26 3.34 2.71
62.311 +w06 1.99 4.17 2.13 2.19 2.52 2.06 2.00 1.51
62.312 +w08 0.21 2.92 1.24 2.07 2.29 1.25 2.32 1.55
62.313 +w09 0.66 3.76 1.41 2.47 1.82 1.66 . 1.87
62.314 +w12 1.38 3.83 1.68 2.53 2.39 . 1.96 1.94
62.315 +w14 2.47 1.58 2.40 3.59 3.85 2.25 . 3.05
62.316 +w15 1.06 4.95 2.48 1.39 3.41 1.96 . 1.02
62.317 +w17 0.88 3.39 1.46 2.00 2.67 1.45 . 1.46
62.318 +w18 7.90 6.57 7.79 9.59 10.81 . . 6.70
62.319 +w19 1.42 4.12 1.96 1.99 3.52 1.88 . 1.26
62.320 +w20 3.03 1.59 2.34 4.76 3.98 1.88 . 3.73
62.321 +w24 1.58 2.80 2.27 2.87 3.19 1.31 . 2.05
62.322 +w25 1.51 5.05 2.74 0.57 2.98 . 2.95 0.27
62.323 +w26 1.75 3.61 2.70 1.54 4.07 3.52 . 1.03
62.324 +w27 2.48 6.87 3.17 1.59 2.08 3.45 . 0.99
62.325 +w28 2.05 6.83 2.97 1.13 2.91 . . 1.26
62.326 +w29 4.03 3.68 4.46 3.20 5.50 . . 3.20
62.327 +w30 2.48 5.78 2.99 2.24 1.79 3.10 . 1.39
62.328 +w31 2.34 5.41 2.87 1.67 1.66 . . 1.39
62.329 +w32 14.36 . . . . . . .
62.330 +w33 3.87 4.27 5.11 3.48 5.66 4.03 . 3.05
62.331 +w34 3.26 4.80 3.21 2.70 4.14 . . 1.77
62.332 +w35 2.34 2.84 2.89 3.35 3.78 2.68 . 2.52
62.333 +w36 2.43 5.69 2.96 2.95 1.02 2.61 1.07 2.54
62.334 +w37 2.23 4.64 2.41 1.99 4.30 2.61 . 1.44
62.335 +w38 4.66 4.36 5.23 3.04 4.46 . . 3.82
62.336 +w39 1.11 3.51 1.10 2.53 3.07 1.12 . 2.23
62.337 +w40 2.99 4.78 4.23 1.57 3.92 . . 1.80
62.338 +w41 4.93 4.00 5.43 4.45 6.31 . . 3.81
62.339 +w42 3.86 6.55 5.03 2.11 4.41 . . 2.63
62.340 +w43 4.61 4.45 3.77 1.22 4.31 . . 2.35
62.341 +w44 2.05 4.48 1.06 3.70 3.46 1.10 . 3.21
62.342 +w45 0.92 3.42 1.58 3.04 1.82 1.94 . 2.52
62.343 +w46 1.36 2.44 0.95 3.08 2.78 0.39 2.16 2.37
62.344 +w47 1.30 3.39 1.60 2.49 4.29 2.04 . 1.68
62.345 +w48 1.65 3.78 1.03 2.97 2.21 1.31 . 2.74
62.346 +w49 1.96 3.00 1.50 3.24 3.68 1.00 . 2.99
62.347 +w50 0.90 4.14 1.60 1.95 3.61 1.61 . 1.52
62.348 +w51 1.59 3.95 0.25 2.96 2.58 1.00 2.41 2.71
62.349 +w53 1.59 3.79 1.28 3.12 3.10 0.89 . 2.98
62.350 +w54 1.72 4.36 1.61 2.92 2.34 1.91 1.97 3.05
62.351 +w55 2.45 2.73 2.21 4.47 4.30 2.57 . 4.48
62.352 +w56 1.10 3.73 1.59 2.74 2.33 1.45 . 2.44
62.353 +w57 0.95 3.39 1.37 2.30 2.47 1.15 . 1.95
62.354 +w59 3.29 5.35 3.32 3.81 1.52 3.38 1.34 4.08
62.355 +w60 2.41 6.12 2.46 3.65 2.35 . 1.37 4.06
62.356 +w61 3.32 5.50 3.41 3.38 1.23 . 0.99 4.28
62.357 +w62 1.12 3.00 0.82 3.22 2.95 . 3.33 2.53
62.358 +w63 3.59 6.36 3.25 4.12 1.84 3.59 1.46 4.03
62.359 +w64 1.85 4.45 2.17 3.43 2.13 2.03 . 4.02
62.360 +w65 2.78 4.79 2.81 2.94 1.54 2.90 1.07 2.94
62.361 +w66 3.90 5.79 3.05 3.65 1.36 3.39 1.22 3.57
62.362 +w68 2.61 5.20 2.90 2.34 1.68 3.19 1.48 2.31
62.363 +w69 2.94 5.21 2.78 3.43 0.21 3.26 0.68 2.54
62.364 +w71 2.06 4.98 2.38 2.44 1.59 2.97 1.05 2.55
62.365 +w72 2.61 5.50 2.83 3.12 1.35 3.23 0.88 2.99
62.366 +w73 8.52 6.16 8.03 8.83 10.44 7.38 10.26 .
62.367 +w74 6.11 5.46 9.07 9.38 10.80 . . 8.25
62.368 +w75 2.66 4.94 2.87 3.69 1.52 3.15 1.24 4.00
62.369 +w76 1.99 5.26 2.23 3.36 0.58 3.17 . 2.50
62.370 +w77 4.32 3.07 5.05 3.88 6.04 . . 4.15
62.371 +w78 5.60 2.59 5.78 5.56 7.10 . . 5.60
62.372 +w79 4.25 2.32 4.93 4.57 6.04 . . 4.58
62.373 +w80 5.94 4.00 5.60 7.02 9.46 . . 7.51
62.374 +w81 5.39 2.21 5.10 6.22 6.46 . . 6.58
62.375 +w82 8.80 5.69 9.29 9.88 11.69 8.63 11.52 .
62.376 +w83 4.40 . 5.24 5.21 5.81 3.91 7.04 5.33
62.377 +w84 5.87 5.43 6.17 5.70 7.63 . . 5.70
62.378 +w85 3.90 3.65 3.38 4.57 5.64 3.05 . 5.04
62.379 +w86 5.48 2.10 5.70 6.37 7.33 . . 6.19
62.380 +w87 8.88 5.54 9.50 9.71 11.64 8.85 11.68 .
62.381 +w89 4.62 4.01 4.03 6.30 6.30 3.81 . 7.77
62.382 +w90 4.35 2.72 4.61 4.01 5.60 . . 3.20
62.383 +w91 7.61 4.42 7.83 6.85 8.79 . . 7.66
62.384 +w92 7.15 2.69 6.91 7.20 . . . 7.06
62.385 +w93 3.17 3.95 4.37 3.74 5.05 . . 2.40
62.386 +w94 1.21 3.07 0.90 2.74 3.17 . 2.63 2.39
62.387 +w95 5.82 3.29 6.55 7.06 11.47 . . 7.83
62.388 +w96 1.77 5.20 2.72 0.59 3.47 2.48 . .
62.389 +w98 3.04 1.92 3.64 3.70 4.90 3.05 . 3.88
62.390 +x22 4.08 6.25 4.15 4.30 1.77 . 1.77 .
62.391 +x23 3.39 5.74 3.55 4.08 1.69 . 1.47 . ;
62.392 +
62.393 +param msr (tr) :
62.394 +
62.395 + w01 w02 w03 w04 w05 w62 w76 w96 :=
62.396 +
62.397 +w01 0 0 0 0 0 0 1 0
62.398 +w02 0 0 0 0 0 0 1 0
62.399 +w03 0 0 0 0 0 0 1 0
62.400 +w04 0 0 0 0 0 0 1 0
62.401 +w05 0 0 0 0 0 0 0 0
62.402 +w06 0 1 1 1 1 1 1 1
62.403 +w08 0 1 1 1 1 1 1 1
62.404 +w09 0 1 1 1 1 1 0 1
62.405 +w12 0 1 1 1 1 0 1 1
62.406 +w14 1 1 1 1 1 0 0 1
62.407 +w15 0 1 1 1 1 1 0 1
62.408 +w17 0 1 1 1 1 1 0 1
62.409 +w18 0 1 1 1 1 0 0 1
62.410 +w19 0 1 1 1 1 0 0 1
62.411 +w20 1 1 1 1 1 0 0 1
62.412 +w24 0 1 1 1 1 0 0 1
62.413 +w25 0 1 1 1 1 0 1 0
62.414 +w26 1 1 1 0 1 1 0 1
62.415 +w27 1 1 1 0 1 1 0 1
62.416 +w28 1 1 1 0 1 0 0 1
62.417 +w29 0 1 1 1 1 0 0 1
62.418 +w30 1 1 1 0 1 1 0 1
62.419 +w31 1 1 1 0 1 0 0 1
62.420 +w32 0 0 0 0 0 0 0 0
62.421 +w33 1 0 1 1 1 1 0 1
62.422 +w34 1 1 1 0 1 0 0 1
62.423 +w35 1 1 1 1 1 0 0 1
62.424 +w36 0 1 1 1 0 1 1 1
62.425 +w37 1 1 1 0 1 1 0 1
62.426 +w38 1 1 1 0 1 0 0 1
62.427 +w39 0 1 1 1 1 1 0 1
62.428 +w40 1 1 1 0 1 0 0 1
62.429 +w41 1 0 1 1 1 0 0 1
62.430 +w42 1 1 1 0 1 0 0 1
62.431 +w43 1 1 1 0 1 0 0 1
62.432 +w44 1 1 1 1 1 0 0 1
62.433 +w45 0 1 1 1 1 1 0 1
62.434 +w46 0 1 1 1 1 0 1 1
62.435 +w47 0 1 1 1 1 1 0 1
62.436 +w48 0 1 1 1 1 0 0 1
62.437 +w49 1 1 1 1 1 0 0 1
62.438 +w50 0 1 1 1 1 1 0 1
62.439 +w51 0 1 1 1 1 0 1 1
62.440 +w53 1 1 1 1 1 0 0 1
62.441 +w54 0 1 1 1 1 1 1 1
62.442 +w55 0 1 1 1 1 0 0 1
62.443 +w56 0 1 1 1 1 1 0 1
62.444 +w57 0 1 1 1 1 1 0 1
62.445 +w59 0 1 1 1 0 1 1 1
62.446 +w60 0 1 1 1 1 0 1 1
62.447 +w61 0 1 1 1 0 0 1 1
62.448 +w62 0 0 0 0 0 0 1 0
62.449 +w63 0 1 1 1 0 1 1 1
62.450 +w64 0 1 1 1 1 1 0 1
62.451 +w65 0 1 1 1 0 1 1 1
62.452 +w66 0 1 1 1 0 1 1 1
62.453 +w68 0 1 1 1 0 1 1 1
62.454 +w69 0 1 1 1 0 1 1 1
62.455 +w71 0 1 1 1 0 1 1 1
62.456 +w72 0 1 1 1 0 1 1 1
62.457 +w73 0 1 1 1 0 1 1 0
62.458 +w74 0 1 1 1 0 0 0 1
62.459 +w75 0 1 1 1 0 1 1 1
62.460 +w76 0 0 0 0 0 0 0 0
62.461 +w77 1 0 1 1 1 0 0 1
62.462 +w78 1 0 1 1 1 0 0 1
62.463 +w79 1 0 1 1 1 0 0 1
62.464 +w80 1 0 1 1 1 0 0 1
62.465 +w81 1 0 1 1 1 0 0 1
62.466 +w82 1 0 1 1 1 1 1 0
62.467 +w83 1 0 1 1 1 0 1 1
62.468 +w84 1 0 1 1 1 0 0 1
62.469 +w85 1 1 1 1 1 0 0 1
62.470 +w86 1 0 1 1 1 0 0 1
62.471 +w87 1 0 1 1 1 1 1 0
62.472 +w89 1 0 1 1 1 1 0 1
62.473 +w90 0 1 1 1 1 0 0 1
62.474 +w91 1 0 1 1 1 0 0 1
62.475 +w92 1 0 1 1 1 0 0 1
62.476 +w93 1 1 1 0 1 0 0 1
62.477 +w94 0 0 1 1 1 0 1 1
62.478 +w95 1 0 1 1 1 0 0 1
62.479 +w96 0 0 0 0 0 0 0 0
62.480 +w98 1 0 1 1 1 1 0 1
62.481 +x22 1 1 1 1 0 0 1 0
62.482 +x23 1 1 1 1 0 0 1 0 ;
62.483 +
62.484 +param ds default 0.000 (tr) :
62.485 +
62.486 + 18REG 24REG 24PRO :=
62.487 +
62.488 +w01 0.000 0.000 0.008
62.489 +w02 0.004 0.000 0.000
62.490 +w03 0.000 0.000 0.000
62.491 +w04 0.010 0.002 0.000
62.492 +w05 0.000 0.000 0.000
62.493 +w06 0.010 0.008 0.008
62.494 +w08 0.030 0.024 0.024
62.495 +w09 0.014 0.018 0.020
62.496 +w12 0.014 0.012 0.010
62.497 +w14 0.007 0.007 0.012
62.498 +w15 0.010 0.019 0.018
62.499 +w17 0.013 0.010 0.011
62.500 +w19 0.015 0.012 0.009
62.501 +w20 0.012 0.021 0.022
62.502 +w21 0.000 0.000 0.000
62.503 +w24 0.012 0.022 0.018
62.504 +w25 0.019 0.025 0.020
62.505 +w26 0.006 0.015 0.021
62.506 +w27 0.008 0.010 0.015
62.507 +w28 0.011 0.016 0.019
62.508 +w29 0.008 0.020 0.013
62.509 +w30 0.011 0.013 0.015
62.510 +w31 0.011 0.013 0.017
62.511 +w32 0.006 0.000 0.000
62.512 +w33 0.000 0.015 0.014
62.513 +w34 0.008 0.007 0.005
62.514 +w35 0.002 0.006 0.014
62.515 +w36 0.015 0.013 0.005
62.516 +w37 0.017 0.016 0.015
62.517 +w38 0.015 0.009 0.012
62.518 +w39 0.007 0.017 0.022
62.519 +w40 0.009 0.014 0.020
62.520 +w41 0.003 0.014 0.011
62.521 +w42 0.017 0.011 0.012
62.522 +w43 0.009 0.013 0.011
62.523 +w44 0.002 0.012 0.012
62.524 +w45 0.016 0.025 0.028
62.525 +w46 0.038 0.062 0.040
62.526 +w47 0.007 0.010 0.010
62.527 +w48 0.003 0.015 0.016
62.528 +w49 0.005 0.016 0.017
62.529 +w50 0.011 0.008 0.007
62.530 +w51 0.010 0.022 0.021
62.531 +w53 0.004 0.026 0.020
62.532 +w54 0.020 0.017 0.025
62.533 +w55 0.004 0.019 0.028
62.534 +w56 0.004 0.010 0.008
62.535 +w57 0.014 0.020 0.018
62.536 +w59 0.012 0.006 0.007
62.537 +w60 0.019 0.010 0.009
62.538 +w61 0.028 0.010 0.012
62.539 +w62 0.000 0.000 0.000
62.540 +w63 0.070 0.027 0.037
62.541 +w64 0.009 0.004 0.005
62.542 +w65 0.022 0.015 0.016
62.543 +w66 0.046 0.017 0.020
62.544 +w68 0.005 0.012 0.016
62.545 +w69 0.085 0.036 0.039
62.546 +w71 0.011 0.013 0.010
62.547 +w72 0.089 0.031 0.034
62.548 +w75 0.026 0.012 0.010
62.549 +w77 0.001 0.004 0.002
62.550 +w78 0.002 0.004 0.002
62.551 +w79 0.001 0.004 0.002
62.552 +w80 0.001 0.001 0.002
62.553 +w81 0.001 0.003 0.002
62.554 +w83 0.009 0.010 0.008
62.555 +w84 0.001 0.002 0.002
62.556 +w85 0.001 0.004 0.005
62.557 +w86 0.001 0.002 0.002
62.558 +w87 0.002 0.003 0.000
62.559 +w89 0.001 0.001 0.002
62.560 +w90 0.006 0.017 0.013
62.561 +w91 0.002 0.010 0.013
62.562 +w92 0.000 0.003 0.002
62.563 +w93 0.002 0.006 0.007
62.564 +w95 0.001 0.007 0.007
62.565 +w96 0.000 0.000 0.000
62.566 +w98 0.006 0.005 0.002 ;
62.567 +
62.568 +end;
63.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
63.2 +++ b/examples/dragon.dat Mon Dec 06 13:09:21 2010 +0100
63.3 @@ -0,0 +1,55 @@
63.4 +/* dragon.dat, a hard Paint-By-Numbers puzzle */
63.5 +
63.6 +/* To reduce the solution time the clique cuts may be used. */
63.7 +
63.8 +data;
63.9 +
63.10 +param m := 20;
63.11 +
63.12 +param n := 20;
63.13 +
63.14 +param row : 1 2 3 4 5 :=
63.15 + 1 7 1 . . .
63.16 + 2 1 1 2 . .
63.17 + 3 2 1 2 . .
63.18 + 4 1 2 2 . .
63.19 + 5 4 2 3 . .
63.20 + 6 3 1 4 . .
63.21 + 7 3 1 3 . .
63.22 + 8 2 1 4 . .
63.23 + 9 2 9 . . .
63.24 + 10 2 1 5 . .
63.25 + 11 2 7 . . .
63.26 + 12 14 . . . .
63.27 + 13 8 2 . . .
63.28 + 14 6 2 2 . .
63.29 + 15 2 8 1 3 .
63.30 + 16 1 5 5 2 .
63.31 + 17 1 3 2 4 1
63.32 + 18 3 1 2 4 1
63.33 + 19 1 1 3 1 3
63.34 + 20 2 1 1 2 . ;
63.35 +
63.36 +param col : 1 2 3 4 5 :=
63.37 + 1 1 1 1 2 .
63.38 + 2 3 1 2 1 1
63.39 + 3 1 4 2 1 1
63.40 + 4 1 3 2 4 .
63.41 + 5 1 4 6 1 .
63.42 + 6 1 11 1 . .
63.43 + 7 5 1 6 2 .
63.44 + 8 14 . . . .
63.45 + 9 7 2 . . .
63.46 + 10 7 2 . . .
63.47 + 11 6 1 1 . .
63.48 + 12 9 2 . . .
63.49 + 13 3 1 1 1 .
63.50 + 14 3 1 3 . .
63.51 + 15 2 1 3 . .
63.52 + 16 2 1 5 . .
63.53 + 17 3 2 2 . .
63.54 + 18 3 3 2 . .
63.55 + 19 2 3 2 . .
63.56 + 20 2 6 . . . ;
63.57 +
63.58 +end;
64.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
64.2 +++ b/examples/egypt.mod Mon Dec 06 13:09:21 2010 +0100
64.3 @@ -0,0 +1,519 @@
64.4 +# EGYPT, a static model of fertilizer production
64.5 +#
64.6 +# References:
64.7 +# Robert Fourer, David M. Gay and Brian W. Kernighan, "A Modeling Language
64.8 +# for Mathematical Programming." Management Science 36 (1990) 519-554.
64.9 +
64.10 +### SETS ###
64.11 +
64.12 +set center; # Locations from which final product may be shipped
64.13 +set port within center; # Locations at which imports can be received
64.14 +set plant within center; # Locations of plants
64.15 +
64.16 +set region; # Demand regions
64.17 +
64.18 +set unit; # Productive units
64.19 +set proc; # Processes
64.20 +
64.21 +set nutr; # Nutrients
64.22 +
64.23 +set c_final; # Final products (fertilizers)
64.24 +set c_inter; # Intermediate products
64.25 +set c_ship within c_inter; # Intermediates for shipment
64.26 +set c_raw; # Domestic raw materials and miscellaneous inputs
64.27 +
64.28 +set commod := c_final union c_inter union c_raw;
64.29 +
64.30 + # All commodities
64.31 +
64.32 +### PARAMETERS ###
64.33 +
64.34 +param cf75 {region,c_final} >= 0;
64.35 +
64.36 + # Consumption of fertilizer 1974-75 (1000 tpy)
64.37 +
64.38 +param fn {c_final,nutr} >= 0;
64.39 +
64.40 + # Nutrient content of fertilizers
64.41 +
64.42 +param cn75 {r in region, n in nutr} := sum {c in c_final} cf75[r,c] * fn[c,n];
64.43 +
64.44 + # Consumption of nutrients 1974-75 (1000 tpy)
64.45 +
64.46 +param road {region,center} >= 0;
64.47 +
64.48 + # Road distances
64.49 +
64.50 +param rail_half {plant,plant} >= 0;
64.51 +param rail {p1 in plant, p2 in plant} :=
64.52 + if rail_half[p1,p2] > 0 then rail_half[p1,p2] else rail_half[p2,p1];
64.53 +
64.54 + # Interplant rail distances (kms)
64.55 +
64.56 +param impd_barg {plant} >= 0;
64.57 +param impd_road {plant} >= 0;
64.58 +
64.59 + # Import distances (kms) by barge and road
64.60 +
64.61 +param tran_final {pl in plant, r in region} :=
64.62 + if road[r,pl] > 0 then .5 + .0144 * road[r,pl] else 0;
64.63 +
64.64 +param tran_import {r in region, po in port} :=
64.65 + if road[r,po] > 0 then .5 + .0144 * road[r,po] else 0;
64.66 +
64.67 +param tran_inter {p1 in plant, p2 in plant} :=
64.68 + if rail[p1,p2] > 0 then 3.5 + .03 * rail[p1,p2] else 0;
64.69 +
64.70 +param tran_raw {pl in plant} :=
64.71 + (if impd_barg[pl] > 0 then 1.0 + .0030 * impd_barg[pl] else 0)
64.72 + + (if impd_road[pl] > 0 then 0.5 + .0144 * impd_road[pl] else 0);
64.73 +
64.74 + # Transport cost (le per ton) for:
64.75 + # final products, imported final products,
64.76 + # interplant shipment, imported raw materials
64.77 +
64.78 +param io {commod,proc}; # Input-output coefficients
64.79 +
64.80 +param util {unit,proc} >= 0;
64.81 +
64.82 + # Capacity utilization coefficients
64.83 +
64.84 +param p_imp {commod} >= 0; # Import Price (cif US$ per ton 1975)
64.85 +
64.86 +param p_r {c_raw} >= 0;
64.87 +param p_pr {plant,c_raw} >= 0;
64.88 +
64.89 +param p_dom {pl in plant, c in c_raw} :=
64.90 + if p_r[c] > 0 then p_r[c] else p_pr[pl,c];
64.91 +
64.92 + # Domestic raw material prices
64.93 +
64.94 +param dcap {plant,unit} >= 0;
64.95 +
64.96 + # Design capacity of plants (t/day)
64.97 +
64.98 +param icap {u in unit, pl in plant} := 0.33 * dcap[pl,u];
64.99 +
64.100 + # Initial capacity of plants (t/day)
64.101 +
64.102 +param exch := 0.4; # Exchange rate
64.103 +
64.104 +param util_pct := 0.85; # Utilization percent for initial capacity
64.105 +
64.106 +### DERIVED SETS OF "POSSIBILITIES" ###
64.107 +
64.108 +set m_pos {pl in plant} := {u in unit: icap[u,pl] > 0};
64.109 +
64.110 + # At each plant, set of units for which there is
64.111 + # initial capacity
64.112 +
64.113 +set p_cap {pl in plant} :=
64.114 + {pr in proc: forall {u in unit: util[u,pr] > 0} u in m_pos[pl] };
64.115 +
64.116 + # At each plant, set of processes for which
64.117 + # all necessary units have some initial capacity
64.118 +
64.119 +set p_except {plant} within proc;
64.120 +
64.121 + # At each plant, list of processes that are
64.122 + # arbitrarily ruled out
64.123 +
64.124 +set p_pos {pl in plant} := p_cap[pl] diff p_except[pl];
64.125 +
64.126 + # At each plant, set of possible processes
64.127 +
64.128 +set cp_pos {c in commod} := {pl in plant: sum {pr in p_pos[pl]} io[c,pr] > 0};
64.129 +
64.130 +set cc_pos {c in commod} := {pl in plant: sum {pr in p_pos[pl]} io[c,pr] < 0};
64.131 +
64.132 +set c_pos {c in commod} := cp_pos[c] union cc_pos[c];
64.133 +
64.134 + # For each commodity, set of plants that can
64.135 + # produce it (cp_pos) or consume it (cc_pos),
64.136 + # and their union (c_pos)
64.137 +
64.138 +### VARIABLES ###
64.139 +
64.140 +var Z {pl in plant, p_pos[pl]} >= 0;
64.141 +
64.142 + # Z[pl,pr] is level of process pr at plant pl
64.143 +
64.144 +var Xf {c in c_final, cp_pos[c], region} >= 0;
64.145 +
64.146 + # Xf[c,pl,r] is amount of final product c
64.147 + # shipped from plant pl to region r
64.148 +
64.149 +var Xi {c in c_ship, cp_pos[c], cc_pos[c]} >= 0;
64.150 +
64.151 + # Xi[c,p1,p2] is amount of intermediate c
64.152 + # shipped from plant p1 to plant p2
64.153 +
64.154 +var Vf {c_final,region,port} >= 0;
64.155 +
64.156 + # Vf[c,r,po] is amount of final product c
64.157 + # imported by region r from port po
64.158 +
64.159 +var Vr {c in c_raw, cc_pos[c]} >= 0;
64.160 +
64.161 + # Vr[c,pl] is amount of raw material c
64.162 + # imported for use at plant pl
64.163 +
64.164 +var U {c in c_raw, cc_pos[c]} >= 0;
64.165 +
64.166 + # U[c,pl] is amount of raw material c
64.167 + # purchased domestically for use at plant pl
64.168 +
64.169 +var Psip; # Domestic recurrent cost
64.170 +var Psil; # Transport cost
64.171 +var Psii; # Import cost
64.172 +
64.173 +### OBJECTIVE ###
64.174 +
64.175 +minimize Psi: Psip + Psil + Psii;
64.176 +
64.177 +### CONSTRAINTS ###
64.178 +
64.179 +subject to mbd {n in nutr, r in region}:
64.180 +
64.181 + sum {c in c_final} fn[c,n] *
64.182 + (sum {po in port} Vf[c,r,po] +
64.183 + sum {pl in cp_pos[c]} Xf[c,pl,r]) >= cn75[r,n];
64.184 +
64.185 + # Total nutrients supplied to a region by all
64.186 + # final products (sum of imports plus internal
64.187 + # shipments from plants) must meet requirements
64.188 +
64.189 +subject to mbdb {c in c_final, r in region: cf75[r,c] > 0}:
64.190 +
64.191 + sum {po in port} Vf[c,r,po] +
64.192 + sum {pl in cp_pos[c]} Xf[c,pl,r] >= cf75[r,c];
64.193 +
64.194 + # Total of each final product supplied to each
64.195 + # region (as in previous constraint) must meet
64.196 + # requirements
64.197 +
64.198 +subject to mb {c in commod, pl in plant}:
64.199 +
64.200 + sum {pr in p_pos[pl]} io[c,pr] * Z[pl,pr]
64.201 +
64.202 + + ( if c in c_ship then
64.203 + ( if pl in cp_pos[c] then sum {p2 in cc_pos[c]} Xi[c,pl,p2] )
64.204 + - ( if pl in cc_pos[c] then sum {p2 in cp_pos[c]} Xi[c,p2,pl] ))
64.205 +
64.206 + + ( if (c in c_raw and pl in cc_pos[c]) then
64.207 + (( if p_imp[c] > 0 then Vr[c,pl] )
64.208 + + ( if p_dom[pl,c] > 0 then U[c,pl] )))
64.209 +
64.210 + >= if (c in c_final and pl in cp_pos[c]) then sum {r in region} Xf[c,pl,r];
64.211 +
64.212 + # For each commodity at each plant: sum of
64.213 + # (1) production or consumption at plant,
64.214 + # (2) inter-plant shipments in or out,
64.215 + # (3) import and domestic purchases (raw only)
64.216 + # is >= 0 for raw materials and intermediates;
64.217 + # is >= the total shipped for final products
64.218 +
64.219 +subject to cc {pl in plant, u in m_pos[pl]}:
64.220 +
64.221 + sum {pr in p_pos[pl]} util[u,pr] * Z[pl,pr] <= util_pct * icap[u,pl];
64.222 +
64.223 + # For each productive unit at each plant,
64.224 + # total utilization by all processes
64.225 + # may not exceed the unit's capacity
64.226 +
64.227 +subject to ap:
64.228 +
64.229 + Psip = sum {c in c_raw, pl in cc_pos[c]} p_dom[pl,c] * U[c,pl];
64.230 +
64.231 + # Psip is the cost of domestic raw materials,
64.232 + # summed over all plants that consume them
64.233 +
64.234 +subject to al:
64.235 +
64.236 + Psil = sum {c in c_final} (
64.237 +
64.238 + sum {pl in cp_pos[c], r in region}
64.239 + tran_final[pl,r] * Xf[c,pl,r]
64.240 +
64.241 + + sum {po in port, r in region} tran_import[r,po] * Vf[c,r,po] )
64.242 +
64.243 + + sum {c in c_ship, p1 in cp_pos[c], p2 in cc_pos[c]}
64.244 + tran_inter[p1,p2] * Xi[c,p1,p2]
64.245 +
64.246 + + sum {c in c_raw, pl in cc_pos[c]: p_imp[c] > 0}
64.247 + tran_raw[pl] * Vr[c,pl];
64.248 +
64.249 + # Total transport cost is sum of shipping costs for
64.250 + # (1) all final products from all plants,
64.251 + # (2) all imports of final products,
64.252 + # (3) all intermediates shipped between plants,
64.253 + # (4) all imports of raw materials
64.254 +
64.255 +subject to ai:
64.256 +
64.257 + Psii / exch = sum {c in c_final, r in region, po in port}
64.258 + p_imp[c] * Vf[c,r,po]
64.259 +
64.260 + + sum {c in c_raw, pl in cc_pos[c]} p_imp[c] * Vr[c,pl];
64.261 +
64.262 + # Total import cost -- at exchange rate --
64.263 + # is sum of import costs for final products
64.264 + # in each region and raw materials at each plant
64.265 +
64.266 +### DATA ###
64.267 +
64.268 +data;
64.269 +
64.270 +set center := ASWAN HELWAN ASSIOUT KAFR_EL_ZT ABU_ZAABAL ABU_KIR TALKHA SUEZ ;
64.271 +
64.272 +set port := ABU_KIR ;
64.273 +
64.274 +set plant := ASWAN HELWAN ASSIOUT KAFR_EL_ZT ABU_ZAABAL ;
64.275 +
64.276 +set region := ALEXANDRIA BEHERA GHARBIA KAFR_EL_SH DAKAHLIA DAMIETTA
64.277 + SHARKIA ISMAILIA SUEZ MENOUFIA KALUBIA GIZA BENI_SUEF FAYOUM
64.278 + MINIA ASSIOUT NEW_VALLEY SOHAG QUENA ASWAN ;
64.279 +
64.280 +set unit := SULF_A_S SULF_A_P NITR_ACID AMM_ELEC AMM_C_GAS C_AMM_NITR
64.281 + AMM_SULF SSP ;
64.282 +
64.283 +set proc := SULF_A_S SULF_A_P NITR_ACID AMM_ELEC AMM_C_GAS CAN_310 CAN_335
64.284 + AMM_SULF SSP_155 ;
64.285 +
64.286 +set nutr := N P205 ;
64.287 +
64.288 +set c_final := UREA CAN_260 CAN_310 CAN_335 AMM_SULF DAP SSP_155 C_250_55
64.289 + C_300_100 ;
64.290 +
64.291 +set c_inter := AMMONIA NITR_ACID SULF_ACID ;
64.292 +
64.293 +set c_ship := AMMONIA SULF_ACID ;
64.294 +
64.295 +set c_raw := EL_ASWAN COKE_GAS PHOS_ROCK LIMESTONE EL_SULFUR PYRITES
64.296 + ELECTRIC BF_GAS WATER STEAM BAGS ;
64.297 +
64.298 +set p_except[ASWAN] := CAN_335 ;
64.299 +set p_except[HELWAN] := CAN_310 ;
64.300 +set p_except[ASSIOUT] := ;
64.301 +set p_except[KAFR_EL_ZT] := ;
64.302 +set p_except[ABU_ZAABAL] := ;
64.303 +
64.304 +param cf75 default 0.0 :
64.305 +
64.306 + CAN_260 CAN_310 CAN_335 AMM_SULF UREA :=
64.307 +
64.308 +ALEXANDRIA . . 5.0 3.0 1.0
64.309 +ASSIOUT 1.0 20.0 26.0 1.0 27.0
64.310 +ASWAN . 40.0 . . .
64.311 +BEHERA 1.0 . 25.0 90.0 35.0
64.312 +BENI_SUEF 1.0 . 15.0 1.0 20.0
64.313 +DAKAHLIA 1.0 . 26.0 60.0 20.0
64.314 +DAMIETTA . . 2.0 15.0 8.0
64.315 +FAYOUM 1.0 . 20.0 6.0 20.0
64.316 +GHARBIA . . 17.0 60.0 28.0
64.317 +GIZA . . 40.0 6.0 2.0
64.318 +ISMAILIA . . 4.0 6.0 2.0
64.319 +KAFR_EL_SH 1.0 . 10.0 45.0 22.0
64.320 +KALUBIA . . 25.0 16.0 7.0
64.321 +MENOUFIA 1.0 . 24.0 21.0 30.0
64.322 +MINIA 2.0 15.0 35.0 1.0 41.0
64.323 +NEW_VALLEY . . . . 1.0
64.324 +QUENA . 95.0 2.0 . 3.0
64.325 +SHARKIA 1.0 . 31.0 50.0 28.0
64.326 +SOHAG . 65.0 3.0 . 7.0
64.327 +SUEZ . . 1.0 . .
64.328 +
64.329 + : SSP_155 C_250_55 C_300_100 DAP :=
64.330 +
64.331 +ALEXANDRIA 8.0 . . .
64.332 +ASSIOUT 35.0 5.0 .1 .
64.333 +ASWAN 8.0 . . .
64.334 +BEHERA 64.0 1.0 .1 .1
64.335 +BENI_SUEF 13.0 3.0 . .
64.336 +DAKAHLIA 52.0 1.0 . .
64.337 +DAMIETTA 5.0 . . .
64.338 +FAYOUM 17.0 1.0 . .
64.339 +GHARBIA 57.0 1.0 .2 .1
64.340 +GIZA 14.0 1.0 .1 .
64.341 +ISMAILIA 4.0 . . .
64.342 +KAFR_EL_SH 25.0 2.0 .1 .
64.343 +KALUBIA 22.0 1.0 . .1
64.344 +MENOUFIA 33.0 2.0 .1 .1
64.345 +MINIA 50.0 3.0 .2 .1
64.346 +NEW_VALLEY 1.0 . . .
64.347 +QUENA 8.0 . . .
64.348 +SHARKIA 43.0 1.0 .1 .
64.349 +SOHAG 20.0 1.0 . .
64.350 +SUEZ 1.0 . . . ;
64.351 +
64.352 +param fn default 0.0 : N P205 :=
64.353 +
64.354 + AMM_SULF .206 .
64.355 + CAN_260 .26 .
64.356 + CAN_310 .31 .
64.357 + CAN_335 .335 .
64.358 + C_250_55 .25 .055
64.359 + C_300_100 .30 .10
64.360 + DAP .18 .46
64.361 + SSP_155 . .15
64.362 + UREA .46 . ;
64.363 +
64.364 +param road default 0.0 :
64.365 +
64.366 + ABU_KIR ABU_ZAABAL ASSIOUT ASWAN HELWAN KAFR_EL_ZT SUEZ TALKHA :=
64.367 +
64.368 +ALEXANDRIA 16 210 607 1135 244 119 362 187
64.369 +ASSIOUT 616 420 . 518 362 504 527 518
64.370 +ASWAN 1134 938 518 . 880 1022 1045 1036
64.371 +BEHERA 76 50 547 1065 184 42 288 120
64.372 +BENI_SUEF 359 163 257 775 105 248 270 261
64.373 +DAKAHLIA 208 138 515 1033 152 58 219 3
64.374 +DAMIETTA 267 216 596 1114 233 131 286 66
64.375 +FAYOUM 341 145 308 826 88 230 252 243
64.376 +GHARBIA 150 65 485 1003 122 20 226 55
64.377 +GIZA 287 48 372 890 .9 133 169 146
64.378 +ISMAILIA 365 142 536 1054 173 241 89 146
64.379 +KAFR_EL_SH 145 105 525 1043 162 20 266 35
64.380 +KALUBIA 190 97 439 957 76 66 180 81
64.381 +MENOUFIA 157 154 472 990 109 33 213 90
64.382 +MINIA 384 288 132 650 230 372 394 386
64.383 +NEW_VALLEY 815 619 199 519 561 703 726 717
64.384 +QUENA 858 662 242 276 604 746 769 760
64.385 +SHARKIA 240 60 473 991 110 78 214 58
64.386 +SOHAG 715 519 99 419 461 603 626 617
64.387 +SUEZ 370 224 541 1059 178 246 . 298 ;
64.388 +
64.389 +param rail_half default 0 :
64.390 +
64.391 + KAFR_EL_ZT ABU_ZAABAL HELWAN ASSIOUT :=
64.392 +
64.393 +ABU_ZAABAL 85 . . .
64.394 +HELWAN 142 57 . .
64.395 +ASSIOUT 504 420 362 .
64.396 +ASWAN 1022 938 880 518 ;
64.397 +
64.398 +param : impd_barg impd_road :=
64.399 +
64.400 +ABU_ZAABAL 210 .1
64.401 +ASSIOUT 583 0
64.402 +ASWAN 1087 10
64.403 +HELWAN 183 0
64.404 +KAFR_EL_ZT 104 6 ;
64.405 +
64.406 +param io default 0.0 :=
64.407 +
64.408 + [*,AMM_C_GAS] AMMONIA 1.0
64.409 + BF_GAS -609.
64.410 + COKE_GAS -2.0
64.411 + ELECTRIC -1960.
64.412 + STEAM -4.
64.413 + WATER -700.
64.414 +
64.415 + [*,AMM_ELEC] AMMONIA 1.0
64.416 + EL_ASWAN -12.0
64.417 +
64.418 + [*,AMM_SULF] AMMONIA -.26
64.419 + AMM_SULF 1.0
64.420 + BAGS -22.
64.421 + ELECTRIC -19.
64.422 + SULF_ACID -.76
64.423 + WATER -17.
64.424 +
64.425 + [*,CAN_310] AMMONIA -.20
64.426 + BAGS -23.
64.427 + CAN_310 1.0
64.428 + LIMESTONE -.12
64.429 + NITR_ACID -.71
64.430 + STEAM -.4
64.431 + WATER -49.
64.432 +
64.433 + [*,CAN_335] AMMONIA -.21
64.434 + BAGS -23.
64.435 + CAN_335 1.0
64.436 + LIMESTONE -.04
64.437 + NITR_ACID -.76
64.438 + STEAM -.4
64.439 + WATER -49.
64.440 +
64.441 + [*,NITR_ACID] AMMONIA -.292
64.442 + ELECTRIC -231.
64.443 + NITR_ACID 1.0
64.444 + WATER -.6
64.445 +
64.446 + [*,SSP_155] BAGS -22.
64.447 + ELECTRIC -14.
64.448 + PHOS_ROCK -.62
64.449 + SSP_155 1.0
64.450 + SULF_ACID -.41
64.451 + WATER -6.
64.452 +
64.453 + [*,SULF_A_P] ELECTRIC -75.
64.454 + PYRITES -.826
64.455 + SULF_ACID 1.0
64.456 + WATER -60.
64.457 +
64.458 + [*,SULF_A_S] ELECTRIC -50.
64.459 + EL_SULFUR -.334
64.460 + SULF_ACID 1.0
64.461 + WATER -20. ;
64.462 +
64.463 +param util default 0 :=
64.464 +
64.465 + [*,*] SULF_A_S SULF_A_S 1 SULF_A_P SULF_A_P 1
64.466 + NITR_ACID NITR_ACID 1 AMM_ELEC AMM_ELEC 1
64.467 + AMM_C_GAS AMM_C_GAS 1 SSP SSP_155 1
64.468 + C_AMM_NITR CAN_310 1 C_AMM_NITR CAN_335 1
64.469 + AMM_SULF AMM_SULF 1 ;
64.470 +
64.471 +param p_imp default 0.0 :=
64.472 +
64.473 + PYRITES 17.5 AMM_SULF 75.
64.474 + EL_SULFUR 55. DAP 175.
64.475 + UREA 150. SSP_155 80.
64.476 + CAN_260 75. C_250_55 100.
64.477 + CAN_310 90. C_300_100 130.
64.478 + CAN_335 100. ;
64.479 +
64.480 +param p_r default 0.0 :=
64.481 +
64.482 + ELECTRIC .007
64.483 + BF_GAS .007
64.484 + WATER .031
64.485 + STEAM 1.25
64.486 + BAGS .28 ;
64.487 +
64.488 +param p_pr default 0.0 :=
64.489 +
64.490 + [HELWAN,COKE_GAS] 16.0
64.491 + [ASWAN,EL_ASWAN] 1.0
64.492 +
64.493 + [*,LIMESTONE] ASWAN 1.2
64.494 + HELWAN 1.2
64.495 +
64.496 + [*,PHOS_ROCK] ABU_ZAABAL 4.0
64.497 + ASSIOUT 3.5
64.498 + KAFR_EL_ZT 5.0 ;
64.499 +
64.500 +param dcap default 0.0 :=
64.501 +
64.502 + [ABU_ZAABAL,*] SSP 600
64.503 + SULF_A_P 227
64.504 + SULF_A_S 242
64.505 +
64.506 + [ASSIOUT,*] SSP 600
64.507 + SULF_A_S 250
64.508 +
64.509 + [ASWAN,*] AMM_ELEC 450
64.510 + C_AMM_NITR 1100
64.511 + NITR_ACID 800
64.512 +
64.513 + [HELWAN,*] AMM_C_GAS 172
64.514 + AMM_SULF 24
64.515 + C_AMM_NITR 364
64.516 + NITR_ACID 282
64.517 +
64.518 + [KAFR_EL_ZT,*] SSP 600
64.519 + SULF_A_P 50
64.520 + SULF_A_S 200 ;
64.521 +
64.522 +end;
65.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
65.2 +++ b/examples/fctp.mod Mon Dec 06 13:09:21 2010 +0100
65.3 @@ -0,0 +1,93 @@
65.4 +/* FCTP, Fixed-Charge Transportation Problem */
65.5 +
65.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
65.7 +
65.8 +/* The Fixed-Charge Transportation Problem (FCTP) is obtained from
65.9 + classical transportation problem by imposing a fixed cost on each
65.10 + transportation link if there is a positive flow on that link. */
65.11 +
65.12 +param m, integer, > 0;
65.13 +/* number of sources */
65.14 +
65.15 +param n, integer, > 0;
65.16 +/* number of customers */
65.17 +
65.18 +set I := 1..m;
65.19 +/* set of sources */
65.20 +
65.21 +set J := 1..n;
65.22 +/* set of customers */
65.23 +
65.24 +param supply{i in I}, >= 0;
65.25 +/* supply at source i */
65.26 +
65.27 +param demand{j in J}, >= 0;
65.28 +/* demand at customer j */
65.29 +
65.30 +param varcost{i in I, j in J}, >= 0;
65.31 +/* variable cost (a cost per one unit shipped from i to j) */
65.32 +
65.33 +param fixcost{i in I, j in J}, >= 0;
65.34 +/* fixed cost (a cost for shipping any amount from i to j) */
65.35 +
65.36 +var x{i in I, j in J}, >= 0;
65.37 +/* amount shipped from source i to customer j */
65.38 +
65.39 +s.t. f{i in I}: sum{j in J} x[i,j] = supply[i];
65.40 +/* observe supply at source i */
65.41 +
65.42 +s.t. g{j in J}: sum{i in I} x[i,j] = demand[j];
65.43 +/* satisfy demand at customer j */
65.44 +
65.45 +var y{i in I, j in J}, binary;
65.46 +/* y[i,j] = 1 means some amount is shipped from i to j */
65.47 +
65.48 +s.t. h{i in I, j in J}: x[i,j] <= min(supply[i], demand[j]) * y[i,j];
65.49 +/* if y[i,j] is 0, force x[i,j] to be 0 (may note that supply[i] and
65.50 + demand[j] are implicit upper bounds for x[i,j] as follows from the
65.51 + constraints f[i] and g[j]) */
65.52 +
65.53 +minimize cost: sum{i in I, j in J} varcost[i,j] * x[i,j] +
65.54 + sum{i in I, j in J} fixcost[i,j] * y[i,j];
65.55 +/* total transportation costs */
65.56 +
65.57 +data;
65.58 +
65.59 +/* These data correspond to the instance bal8x12 from [Balinski]. */
65.60 +
65.61 +/* The optimal solution is 471.55 */
65.62 +
65.63 +param m := 8;
65.64 +
65.65 +param n := 12;
65.66 +
65.67 +param supply := 1 15.00, 2 20.00, 3 45.00, 4 35.00,
65.68 + 5 25.00, 6 35.00, 7 10.00, 8 25.00;
65.69 +
65.70 +param demand := 1 20.00, 2 15.00, 3 20.00, 4 15.00,
65.71 + 5 5.00, 6 20.00, 7 30.00, 8 10.00,
65.72 + 9 35.00, 10 25.00, 11 10.00, 12 5.00;
65.73 +
65.74 +param varcost
65.75 + : 1 2 3 4 5 6 7 8 9 10 11 12 :=
65.76 + 1 0.69 0.64 0.71 0.79 1.70 2.83 2.02 5.64 5.94 5.94 5.94 7.68
65.77 + 2 1.01 0.75 0.88 0.59 1.50 2.63 2.26 5.64 5.85 5.62 5.85 4.94
65.78 + 3 1.05 1.06 1.08 0.64 1.22 2.37 1.66 5.64 5.91 5.62 5.91 4.94
65.79 + 4 1.94 1.50 1.56 1.22 1.98 1.98 1.36 6.99 6.99 6.99 6.99 3.68
65.80 + 5 1.61 1.40 1.61 1.33 1.68 2.83 1.54 4.26 4.26 4.26 4.26 2.99
65.81 + 6 5.29 5.94 6.08 5.29 5.96 6.77 5.08 0.31 0.21 0.17 0.31 1.53
65.82 + 7 5.29 5.94 6.08 5.29 5.96 6.77 5.08 0.55 0.35 0.40 0.19 1.53
65.83 + 8 5.29 6.08 6.08 5.29 5.96 6.45 5.08 2.43 2.30 2.33 1.81 2.50 ;
65.84 +
65.85 +param fixcost
65.86 + : 1 2 3 4 5 6 7 8 9 10 11 12 :=
65.87 + 1 11.0 16.0 18.0 17.0 10.0 20.0 17.0 13.0 15.0 12.0 14.0 14.0
65.88 + 2 14.0 17.0 17.0 13.0 15.0 13.0 16.0 11.0 20.0 11.0 15.0 10.0
65.89 + 3 12.0 13.0 20.0 17.0 13.0 15.0 16.0 13.0 12.0 13.0 10.0 18.0
65.90 + 4 16.0 19.0 16.0 11.0 15.0 12.0 18.0 12.0 18.0 13.0 13.0 14.0
65.91 + 5 19.0 18.0 15.0 16.0 12.0 14.0 20.0 19.0 11.0 17.0 16.0 18.0
65.92 + 6 13.0 20.0 20.0 17.0 15.0 12.0 14.0 11.0 12.0 19.0 15.0 16.0
65.93 + 7 11.0 12.0 15.0 10.0 17.0 11.0 11.0 16.0 10.0 18.0 17.0 12.0
65.94 + 8 17.0 10.0 20.0 12.0 17.0 20.0 16.0 15.0 10.0 12.0 16.0 18.0 ;
65.95 +
65.96 +end;
66.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
66.2 +++ b/examples/food.mod Mon Dec 06 13:09:21 2010 +0100
66.3 @@ -0,0 +1,127 @@
66.4 +/* Food Manufacture 1, section 12.1 in
66.5 + * Williams, "Model Building in Mathematical Programming"
66.6 + *
66.7 + * Sebastian Nowozin <nowozin@gmail.com>
66.8 + */
66.9 +
66.10 +set oils;
66.11 +set month;
66.12 +
66.13 +/* Buying prices of the raw oils in the next six month. */
66.14 +param buyingprices{month,oils};
66.15 +
66.16 +/* Actual amount bought in each month. */
66.17 +var buys{month,oils} >= 0;
66.18 +
66.19 +/* Stock for each oil. */
66.20 +var stock{month,oils} >= 0;
66.21 +
66.22 +/* Price of the produced product */
66.23 +param productprice >= 0;
66.24 +param storagecost;
66.25 +
66.26 +param oilhardness{oils} >= 0;
66.27 +
66.28 +/* Actual amount of output oil produced in each month */
66.29 +var production{m in month} >= 0;
66.30 +var useoil{m in month, o in oils} >= 0;
66.31 +
66.32 +maximize totalprofit:
66.33 + sum{m in month} productprice*production[m]
66.34 + - sum{m in month, o in oils} buyingprices[m,o]*buys[m,o]
66.35 + - sum{m in month, o in oils} storagecost*stock[m,o];
66.36 +
66.37 +/* Constraints */
66.38 +
66.39 +/* 1. Starting stock */
66.40 +s.t. startstock{o in oils}:
66.41 + stock[1,o] = 500;
66.42 +s.t. endstock{o in oils}:
66.43 + stock[6,o] + buys[6,o] - useoil[6,o] >= 500;
66.44 +
66.45 +/* 2. Stock constraints */
66.46 +s.t. stocklimit{m in month, o in oils}:
66.47 + stock[m,o] <= 1000;
66.48 +
66.49 +s.t. production1{m in month, o in oils}:
66.50 + useoil[m,o] <= stock[m,o] + buys[m,o];
66.51 +s.t. production2{m1 in month, m2 in month, o in oils : m2 = m1+1}:
66.52 + stock[m2,o] = stock[m1,o] + buys[m1,o] - useoil[m1,o];
66.53 +
66.54 +s.t. production3a{m in month}:
66.55 + sum{o in oils} oilhardness[o]*useoil[m,o] >= 3*production[m];
66.56 +s.t. production3b{m in month}:
66.57 + sum{o in oils} oilhardness[o]*useoil[m,o] <= 6*production[m];
66.58 +
66.59 +s.t. production4{m in month}:
66.60 + production[m] = sum{o in oils} useoil[m,o];
66.61 +
66.62 +/* 3. Refining constraints */
66.63 +s.t. refine1{m in month}:
66.64 + useoil[m,"VEG1"]+useoil[m,"VEG2"] <= 200;
66.65 +s.t. refine2{m in month}:
66.66 + useoil[m,"OIL1"]+useoil[m,"OIL2"]+useoil[m,"OIL3"] <= 250;
66.67 +
66.68 +solve;
66.69 +
66.70 +for {m in month} {
66.71 + printf "Month %d\n", m;
66.72 + printf "PRODUCE %4.2f tons, hardness %4.2f\n", production[m],
66.73 + (sum{o in oils} oilhardness[o]*useoil[m,o]) / (sum{o in oils} useoil[m,o]);
66.74 +
66.75 + printf "\tVEG1\tVEG2\tOIL1\tOIL2\tOIL3\n";
66.76 + printf "STOCK";
66.77 + printf "%d", m;
66.78 + for {o in oils} {
66.79 + printf "\t%4.2f", stock[m,o];
66.80 + }
66.81 + printf "\nBUY";
66.82 + for {o in oils} {
66.83 + printf "\t%4.2f", buys[m,o];
66.84 + }
66.85 + printf "\nUSE";
66.86 + printf "%d", m;
66.87 + for {o in oils} {
66.88 + printf "\t%4.2f", useoil[m,o];
66.89 + }
66.90 + printf "\n";
66.91 + printf "\n";
66.92 +}
66.93 +printf "Total profit: %4.2f\n",
66.94 + (sum{m in month} productprice*production[m]
66.95 + - sum{m in month, o in oils} buyingprices[m,o]*buys[m,o]
66.96 + - sum{m in month, o in oils} storagecost*stock[m,o]);
66.97 +printf " turnover: %4.2f\n",
66.98 + sum{m in month} productprice*production[m];
66.99 +printf " buying costs: %4.2f\n",
66.100 + sum{m in month, o in oils} buyingprices[m,o]*buys[m,o];
66.101 +printf " storage costs: %4.2f\n",
66.102 + sum{m in month, o in oils} storagecost*stock[m,o];
66.103 +
66.104 +
66.105 +data;
66.106 +
66.107 +param : oils : oilhardness :=
66.108 + VEG1 8.8
66.109 + VEG2 6.1
66.110 + OIL1 2.0
66.111 + OIL2 4.2
66.112 + OIL3 5.0 ;
66.113 +
66.114 +set month := 1 2 3 4 5 6;
66.115 +
66.116 +param buyingprices
66.117 +
66.118 +: VEG1 VEG2 OIL1 OIL2 OIL3 :=
66.119 +
66.120 +1 110 120 130 110 115
66.121 +2 130 130 110 90 115
66.122 +3 110 140 130 100 95
66.123 +4 120 110 120 120 125
66.124 +5 100 120 150 110 105
66.125 +6 90 100 140 80 135 ;
66.126 +
66.127 +param productprice := 150;
66.128 +param storagecost := 5;
66.129 +
66.130 +end;
67.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
67.2 +++ b/examples/food2.mod Mon Dec 06 13:09:21 2010 +0100
67.3 @@ -0,0 +1,150 @@
67.4 +/* Food Manufacture 2, section 12.2 in
67.5 + * Williams, "Model Building in Mathematical Programming"
67.6 + *
67.7 + * Sebastian Nowozin <nowozin@gmail.com>
67.8 + */
67.9 +
67.10 +set oils;
67.11 +set month;
67.12 +
67.13 +/* Buying prices of the raw oils in the next six month. */
67.14 +param buyingprices{month,oils};
67.15 +
67.16 +/* Actual amount bought in each month. */
67.17 +var buys{month,oils} >= 0;
67.18 +
67.19 +/* Stock for each oil. */
67.20 +var stock{month,oils} >= 0;
67.21 +
67.22 +/* Price of the produced product */
67.23 +param productprice >= 0;
67.24 +param storagecost;
67.25 +
67.26 +param oilhardness{oils} >= 0;
67.27 +param M >= 0;
67.28 +
67.29 +/* Actual amount of output oil produced in each month */
67.30 +var production{m in month} >= 0;
67.31 +var useoil{m in month, o in oils} >= 0, <= M;
67.32 +var useoilb{m in month, o in oils}, binary;
67.33 +
67.34 +maximize totalprofit:
67.35 + sum{m in month} productprice*production[m]
67.36 + - sum{m in month, o in oils} buyingprices[m,o]*buys[m,o]
67.37 + - sum{m in month, o in oils} storagecost*stock[m,o];
67.38 +
67.39 +/* Constraints */
67.40 +
67.41 +/* 1. Starting stock */
67.42 +s.t. startstock{o in oils}:
67.43 + stock[1,o] = 500;
67.44 +s.t. endstock{o in oils}:
67.45 + stock[6,o] + buys[6,o] - useoil[6,o] >= 500;
67.46 +
67.47 +/* 2. Stock constraints */
67.48 +s.t. stocklimit{m in month, o in oils}:
67.49 + stock[m,o] <= 1000;
67.50 +
67.51 +s.t. production1{m in month, o in oils}:
67.52 + useoil[m,o] <= stock[m,o] + buys[m,o];
67.53 +s.t. production2{m1 in month, m2 in month, o in oils : m2 = m1+1}:
67.54 + stock[m2,o] = stock[m1,o] + buys[m1,o] - useoil[m1,o];
67.55 +
67.56 +s.t. production3a{m in month}:
67.57 + sum{o in oils} oilhardness[o]*useoil[m,o] >= 3*production[m];
67.58 +s.t. production3b{m in month}:
67.59 + sum{o in oils} oilhardness[o]*useoil[m,o] <= 6*production[m];
67.60 +
67.61 +s.t. production4{m in month}:
67.62 + production[m] = sum{o in oils} useoil[m,o];
67.63 +
67.64 +/* 3. Refining constraints */
67.65 +s.t. refine1{m in month}:
67.66 + useoil[m,"VEG1"]+useoil[m,"VEG2"] <= 200;
67.67 +s.t. refine2{m in month}:
67.68 + useoil[m,"OIL1"]+useoil[m,"OIL2"]+useoil[m,"OIL3"] <= 250;
67.69 +
67.70 +/* 4. Additional conditions:
67.71 + * i) The food may never be made up of more than three oils every month
67.72 + */
67.73 +s.t. useoilb_calc{m in month, o in oils}:
67.74 + M*useoilb[m,o] >= useoil[m,o];
67.75 +s.t. useoilb_limit{m in month}:
67.76 + sum{o in oils} useoilb[m,o] <= 3;
67.77 +
67.78 +/* ii) If an oil is used in a month, at least 20 tons must be used.
67.79 + */
67.80 +s.t. useminimum{m in month, o in oils}:
67.81 + 20*useoilb[m,o] <= useoil[m,o];
67.82 +
67.83 +/* iii) If either of VEG1 or VEG2 is used in a month, OIL2 must also be used
67.84 + */
67.85 +s.t. use_oil2a{m in month}:
67.86 + useoilb[m,"VEG1"] <= useoilb[m,"OIL3"];
67.87 +s.t. use_oil2b{m in month}:
67.88 + useoilb[m,"VEG2"] <= useoilb[m,"OIL3"];
67.89 +
67.90 +solve;
67.91 +
67.92 +for {m in month} {
67.93 + printf "Month %d\n", m;
67.94 + printf "PRODUCE %4.2f tons, hardness %4.2f\n", production[m],
67.95 + (sum{o in oils} oilhardness[o]*useoil[m,o]) / (sum{o in oils} useoil[m,o]);
67.96 +
67.97 + printf "\tVEG1\tVEG2\tOIL1\tOIL2\tOIL3\n";
67.98 + printf "STOCK";
67.99 + printf "%d", m;
67.100 + for {o in oils} {
67.101 + printf "\t%4.2f", stock[m,o];
67.102 + }
67.103 + printf "\nBUY";
67.104 + for {o in oils} {
67.105 + printf "\t%4.2f", buys[m,o];
67.106 + }
67.107 + printf "\nUSE";
67.108 + printf "%d", m;
67.109 + for {o in oils} {
67.110 + printf "\t%4.2f", useoil[m,o];
67.111 + }
67.112 + printf "\n";
67.113 + printf "\n";
67.114 +}
67.115 +printf "Total profit: %4.2f\n",
67.116 + (sum{m in month} productprice*production[m]
67.117 + - sum{m in month, o in oils} buyingprices[m,o]*buys[m,o]
67.118 + - sum{m in month, o in oils} storagecost*stock[m,o]);
67.119 +printf " turnover: %4.2f\n",
67.120 + sum{m in month} productprice*production[m];
67.121 +printf " buying costs: %4.2f\n",
67.122 + sum{m in month, o in oils} buyingprices[m,o]*buys[m,o];
67.123 +printf " storage costs: %4.2f\n",
67.124 + sum{m in month, o in oils} storagecost*stock[m,o];
67.125 +
67.126 +
67.127 +data;
67.128 +
67.129 +param : oils : oilhardness :=
67.130 + VEG1 8.8
67.131 + VEG2 6.1
67.132 + OIL1 2.0
67.133 + OIL2 4.2
67.134 + OIL3 5.0 ;
67.135 +
67.136 +set month := 1 2 3 4 5 6;
67.137 +
67.138 +param buyingprices
67.139 +
67.140 +: VEG1 VEG2 OIL1 OIL2 OIL3 :=
67.141 +
67.142 +1 110 120 130 110 115
67.143 +2 130 130 110 90 115
67.144 +3 110 140 130 100 95
67.145 +4 120 110 120 120 125
67.146 +5 100 120 150 110 105
67.147 +6 90 100 140 80 135 ;
67.148 +
67.149 +param productprice := 150;
67.150 +param storagecost := 5;
67.151 +param M := 1000;
67.152 +
67.153 +end;
68.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
68.2 +++ b/examples/gap.mod Mon Dec 06 13:09:21 2010 +0100
68.3 @@ -0,0 +1,79 @@
68.4 +/* GAP, Generalized Assignment Problem */
68.5 +
68.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
68.7 +
68.8 +/* The Generalized Assignment Problem (GAP) is to assign a set of jobs
68.9 + to a set of agents subject to the constraints that each job must be
68.10 + assigned exactly to one agent and the total resources consumed by all
68.11 + jobs assigned to an agent must not exceed the agent's capacity. */
68.12 +
68.13 +param m, integer, > 0;
68.14 +/* number of agents */
68.15 +
68.16 +param n, integer, > 0;
68.17 +/* number of jobs */
68.18 +
68.19 +set I := 1..m;
68.20 +/* set of agents */
68.21 +
68.22 +set J := 1..n;
68.23 +/* set of jobs */
68.24 +
68.25 +param a{i in I, j in J}, >= 0;
68.26 +/* resource consumed in allocating job j to agent i */
68.27 +
68.28 +param b{i in I}, >= 0;
68.29 +/* resource capacity of agent i */
68.30 +
68.31 +param c{i in I, j in J}, >= 0;
68.32 +/* cost of allocating job j to agent i */
68.33 +
68.34 +var x{i in I, j in J}, binary;
68.35 +/* x[i,j] = 1 means job j is assigned to agent i */
68.36 +
68.37 +s.t. one{j in J}: sum{i in I} x[i,j] = 1;
68.38 +/* job j must be assigned exactly to one agent */
68.39 +
68.40 +s.t. lim{i in I}: sum{j in J} a[i,j] * x[i,j] <= b[i];
68.41 +/* total amount of resources consumed by all jobs assigned to agent i
68.42 + must not exceed the agent's capacity */
68.43 +
68.44 +minimize obj: sum{i in I, j in J} c[i,j] * x[i,j];
68.45 +/* the objective is to find cheapest assignment (note that gap can also
68.46 + be formulated as maximization problem) */
68.47 +
68.48 +data;
68.49 +
68.50 +/* These data correspond to the instance c515-1 (gap1) from:
68.51 +
68.52 + I.H. Osman, "Heuristics for the Generalised Assignment Problem:
68.53 + Simulated Annealing and Tabu Search Approaches", OR Spektrum, Volume
68.54 + 17, 211-225, 1995
68.55 +
68.56 + D. Cattrysse, M. Salomon and L.N. Van Wassenhove, "A set partitioning
68.57 + heuristic for the generalized assignment problem", European Journal
68.58 + of Operational Research, Volume 72, 167-174, 1994 */
68.59 +
68.60 +/* The optimal solution is 261 (minimization) or 336 (maximization) */
68.61 +
68.62 +param m := 5;
68.63 +
68.64 +param n := 15;
68.65 +
68.66 +param a : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 :=
68.67 + 1 8 15 14 23 8 16 8 25 9 17 25 15 10 8 24
68.68 + 2 15 7 23 22 11 11 12 10 17 16 7 16 10 18 22
68.69 + 3 21 20 6 22 24 10 24 9 21 14 11 14 11 19 16
68.70 + 4 20 11 8 14 9 5 6 19 19 7 6 6 13 9 18
68.71 + 5 8 13 13 13 10 20 25 16 16 17 10 10 5 12 23 ;
68.72 +
68.73 +param b := 1 36, 2 34, 3 38, 4 27, 5 33;
68.74 +
68.75 +param c : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 :=
68.76 + 1 17 21 22 18 24 15 20 18 19 18 16 22 24 24 16
68.77 + 2 23 16 21 16 17 16 19 25 18 21 17 15 25 17 24
68.78 + 3 16 20 16 25 24 16 17 19 19 18 20 16 17 21 24
68.79 + 4 19 19 22 22 20 16 19 17 21 19 25 23 25 25 25
68.80 + 5 18 19 15 15 21 25 16 16 23 15 22 17 19 22 24 ;
68.81 +
68.82 +end;
69.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
69.2 +++ b/examples/glpsol.c Mon Dec 06 13:09:21 2010 +0100
69.3 @@ -0,0 +1,10 @@
69.4 +/* glpsol.c */
69.5 +
69.6 +#include <glpk.h>
69.7 +
69.8 +int main(int argc, const char *argv[])
69.9 +{ /* stand-alone LP/MIP solver */
69.10 + return glp_main(argc, argv);
69.11 +}
69.12 +
69.13 +/* eof */
70.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
70.2 +++ b/examples/graph.mod Mon Dec 06 13:09:21 2010 +0100
70.3 @@ -0,0 +1,98 @@
70.4 +/* graph.mod - graph visualization */
70.5 +
70.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
70.7 +
70.8 +/* This model creates a picture in EPS format to visualize a graph. */
70.9 +
70.10 +param file, symbolic, default "graph.eps";
70.11 +/* output file to write the picture */
70.12 +
70.13 +param R, default 2;
70.14 +/* radius to draw vertices, in mm */
70.15 +
70.16 +param n, integer, > 0;
70.17 +/* number of vertices */
70.18 +
70.19 +set V, default 1..n;
70.20 +/* set of vertices */
70.21 +
70.22 +set E, within V cross V;
70.23 +/* set of edges */
70.24 +
70.25 +param x{i in V}, default 50 * cos((i - 1) / card(V) * 8 * atan(1));
70.26 +param y{i in V}, default 50 * sin((i - 1) / card(V) * 8 * atan(1));
70.27 +/* x[i] and y[i] are coordinates of node i, in mm */
70.28 +
70.29 +param x0 := (min{i in V} x[i]) - R - 3.0;
70.30 +param y0 := (min{i in V} y[i]) - R - 3.0;
70.31 +param x1 := (max{i in V} x[i]) + R + 3.0;
70.32 +param y1 := (max{i in V} y[i]) + R + 3.0;
70.33 +
70.34 +printf "%%!PS-Adobe-3.0 EPSF-3.0\n" > file;
70.35 +printf "%%%%BoundingBox: 0 0 %d %d\n",
70.36 + (72 / 25.4) * (x1 - x0), (72 / 25.4) * (y1 - y0) >> file;
70.37 +printf "/Helvetica findfont 6 scalefont setfont\n" >> file;
70.38 +printf "/mm { 72 mul 25.4 div } def\n" >> file;
70.39 +
70.40 +for {(i,j) in E}
70.41 +{ printf "newpath\n" >> file;
70.42 + printf "%g mm %g mm moveto\n", x[i] - x0, y[i] - y0 >> file;
70.43 + printf "%g mm %g mm lineto\n", x[j] - x0, y[j] - y0 >> file;
70.44 + printf "closepath\n" >> file;
70.45 + printf "stroke\n" >> file;
70.46 +}
70.47 +
70.48 +for {i in V}
70.49 +{ printf "newpath\n" >> file;
70.50 + printf "%g mm %g mm %g mm 0 360 arc\n",
70.51 + x[i] - x0, y[i] - y0, R >> file;
70.52 + printf "closepath\n" >> file;
70.53 + printf "gsave 1 1 1 setrgbcolor fill grestore\n" >> file;
70.54 + printf "stroke\n" >> file;
70.55 + printf "%g mm %g mm moveto\n",
70.56 + x[i] - (if i <= 9 then 1.2 else 1.8) - x0,
70.57 + y[i] - 0.8 - y0 >> file;
70.58 + printf "( %d ) show\n", i >> file;
70.59 +}
70.60 +
70.61 +printf "showpage\n" >> file;
70.62 +printf "%%%%EOF\n" >> file;
70.63 +
70.64 +data;
70.65 +
70.66 +param
70.67 +: V : x y :=
70.68 + 1 0 40
70.69 + 2 38 12
70.70 + 3 24 -32
70.71 + 4 -24 -32
70.72 + 5 -38 12
70.73 + 6 -19 26
70.74 + 7 19 26
70.75 + 8 31 -10
70.76 + 9 0 -32
70.77 + 10 -31 -10
70.78 + 11 -9 12
70.79 + 12 9 12
70.80 + 13 14 -5
70.81 + 14 0 -15
70.82 + 15 -14 -5
70.83 + 16 0 0 ;
70.84 +
70.85 +set E :=
70.86 + (1,*) 6 10 16 12 7
70.87 + (2,*) 7 6 16 13 8
70.88 + (3,*) 8 7 16 14 9
70.89 + (4,*) 9 8 16 15 10
70.90 + (5,*) 10 9 16 11 6
70.91 + (6,*) 14
70.92 + (7,*) 15
70.93 + (8,*) 11
70.94 + (9,*) 12
70.95 + (10,*) 13
70.96 + (11,*) 12 15
70.97 + (12,*) 13
70.98 + (13,*) 14
70.99 + (14,*) 15 ;
70.100 +
70.101 +end;
71.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
71.2 +++ b/examples/hashi.mod Mon Dec 06 13:09:21 2010 +0100
71.3 @@ -0,0 +1,168 @@
71.4 +/* A solver for the Japanese number-puzzle Hashiwokakero
71.5 + * (http://en.wikipedia.org/wiki/Hashiwokakero)
71.6 + *
71.7 + * Sebastian Nowozin <nowozin@gmail.com>, 13th January 2009
71.8 + */
71.9 +
71.10 +param n := 25;
71.11 +set rows := 1..n;
71.12 +set cols := 1..n;
71.13 +param givens{rows, cols}, integer, >= 0, <= 8, default 0;
71.14 +
71.15 +/* Set of vertices as (row,col) coordinates */
71.16 +set V := { (i,j) in { rows, cols }: givens[i,j] != 0 };
71.17 +
71.18 +/* Set of feasible horizontal edges from (i,j) to (k,l) rightwards */
71.19 +set Eh := { (i,j,k,l) in { V, V }:
71.20 + i = k and j < l and # Same row and left to right
71.21 + card({ (s,t) in V: s = i and t > j and t < l }) = 0 # No vertex inbetween
71.22 + };
71.23 +
71.24 +/* Set of feasible vertical edges from (i,j) to (k,l) downwards */
71.25 +set Ev := { (i,j,k,l) in { V, V }:
71.26 + j = l and i < k and # Same column and top to bottom
71.27 + card({ (s,t) in V: t = j and s > i and s < k }) = 0 # No vertex inbetween
71.28 + };
71.29 +
71.30 +set E := Eh union Ev;
71.31 +
71.32 +/* Indicators: use edge once/twice */
71.33 +var xe1{E}, binary;
71.34 +var xe2{E}, binary;
71.35 +
71.36 +/* Constraint: Do not use edge or do use once or do use twice */
71.37 +s.t. edge_sel{(i,j,k,l) in E}:
71.38 + xe1[i,j,k,l] + xe2[i,j,k,l] <= 1;
71.39 +
71.40 +/* Constraint: There must be as many edges used as the node value */
71.41 +s.t. satisfy_vertex_demand{(s,t) in V}:
71.42 + sum{(i,j,k,l) in E: (i = s and j = t) or (k = s and l = t)}
71.43 + (xe1[i,j,k,l] + 2.0*xe2[i,j,k,l]) = givens[s,t];
71.44 +
71.45 +/* Constraint: No crossings */
71.46 +s.t. no_crossing1{(i,j,k,l) in Eh, (s,t,u,v) in Ev:
71.47 + s < i and u > i and j < t and l > t}:
71.48 + xe1[i,j,k,l] + xe1[s,t,u,v] <= 1;
71.49 +s.t. no_crossing2{(i,j,k,l) in Eh, (s,t,u,v) in Ev:
71.50 + s < i and u > i and j < t and l > t}:
71.51 + xe1[i,j,k,l] + xe2[s,t,u,v] <= 1;
71.52 +s.t. no_crossing3{(i,j,k,l) in Eh, (s,t,u,v) in Ev:
71.53 + s < i and u > i and j < t and l > t}:
71.54 + xe2[i,j,k,l] + xe1[s,t,u,v] <= 1;
71.55 +s.t. no_crossing4{(i,j,k,l) in Eh, (s,t,u,v) in Ev:
71.56 + s < i and u > i and j < t and l > t}:
71.57 + xe2[i,j,k,l] + xe2[s,t,u,v] <= 1;
71.58 +
71.59 +
71.60 +/* Model connectivity by auxiliary network flow problem:
71.61 + * One vertex becomes a target node and all other vertices send a unit flow
71.62 + * to it. The edge selection variables xe1/xe2 are VUB constraints and
71.63 + * therefore xe1/xe2 select the feasible graph for the max-flow problems.
71.64 + */
71.65 +set node_target := { (s,t) in V:
71.66 + card({ (i,j) in V: i < s or (i = s and j < t) }) = 0};
71.67 +set node_sources := { (s,t) in V: (s,t) not in node_target };
71.68 +
71.69 +var flow_forward{ E }, >= 0;
71.70 +var flow_backward{ E }, >= 0;
71.71 +s.t. flow_conservation{ (s,t) in node_target, (p,q) in V }:
71.72 + /* All incoming flows */
71.73 + - sum{(i,j,k,l) in E: k = p and l = q} flow_forward[i,j,k,l]
71.74 + - sum{(i,j,k,l) in E: i = p and j = q} flow_backward[i,j,k,l]
71.75 + /* All outgoing flows */
71.76 + + sum{(i,j,k,l) in E: k = p and l = q} flow_backward[i,j,k,l]
71.77 + + sum{(i,j,k,l) in E: i = p and j = q} flow_forward[i,j,k,l]
71.78 + = 0 + (if (p = s and q = t) then card(node_sources) else -1);
71.79 +
71.80 +/* Variable-Upper-Bound (VUB) constraints: xe1/xe2 bound the flows.
71.81 + */
71.82 +s.t. connectivity_vub1{(i,j,k,l) in E}:
71.83 + flow_forward[i,j,k,l] <= card(node_sources)*(xe1[i,j,k,l] + xe2[i,j,k,l]);
71.84 +s.t. connectivity_vub2{(i,j,k,l) in E}:
71.85 + flow_backward[i,j,k,l] <= card(node_sources)*(xe1[i,j,k,l] + xe2[i,j,k,l]);
71.86 +
71.87 +/* A feasible solution is enough
71.88 + */
71.89 +minimize cost: 0;
71.90 +
71.91 +solve;
71.92 +
71.93 +/* Output solution graphically */
71.94 +printf "\nSolution:\n";
71.95 +for { row in rows } {
71.96 + for { col in cols } {
71.97 + /* First print this cell information: givens or space */
71.98 + printf{0..0: givens[row,col] != 0} "%d", givens[row,col];
71.99 + printf{0..0: givens[row,col] = 0 and
71.100 + card({(i,j,k,l) in Eh: i = row and col >= j and col < l and
71.101 + xe1[i,j,k,l] = 1}) = 1} "-";
71.102 + printf{0..0: givens[row,col] = 0 and
71.103 + card({(i,j,k,l) in Eh: i = row and col >= j and col < l and
71.104 + xe2[i,j,k,l] = 1}) = 1} "=";
71.105 + printf{0..0: givens[row,col] = 0
71.106 + and card({(i,j,k,l) in Ev: j = col and row >= i and row < k and
71.107 + xe1[i,j,k,l] = 1}) = 1} "|";
71.108 + printf{0..0: givens[row,col] = 0
71.109 + and card({(i,j,k,l) in Ev: j = col and row >= i and row < k and
71.110 + xe2[i,j,k,l] = 1}) = 1} '"';
71.111 + printf{0..0: givens[row,col] = 0
71.112 + and card({(i,j,k,l) in Eh: i = row and col >= j and col < l and
71.113 + (xe1[i,j,k,l] = 1 or xe2[i,j,k,l] = 1)}) = 0
71.114 + and card({(i,j,k,l) in Ev: j = col and row >= i and row < k and
71.115 + (xe1[i,j,k,l] = 1 or xe2[i,j,k,l] = 1)}) = 0} " ";
71.116 +
71.117 + /* Now print any edges */
71.118 + printf{(i,j,k,l) in Eh: i = row and col >= j and col < l and xe1[i,j,k,l] = 1} "-";
71.119 + printf{(i,j,k,l) in Eh: i = row and col >= j and col < l and xe2[i,j,k,l] = 1} "=";
71.120 +
71.121 + printf{(i,j,k,l) in Eh: i = row and col >= j and col < l and
71.122 + xe1[i,j,k,l] = 0 and xe2[i,j,k,l] = 0} " ";
71.123 + printf{0..0: card({(i,j,k,l) in Eh: i = row and col >= j and col < l}) = 0} " ";
71.124 + }
71.125 + printf "\n";
71.126 + for { col in cols } {
71.127 + printf{(i,j,k,l) in Ev: j = col and row >= i and row < k and xe1[i,j,k,l] = 1} "|";
71.128 + printf{(i,j,k,l) in Ev: j = col and row >= i and row < k and xe2[i,j,k,l] = 1} '"';
71.129 + printf{(i,j,k,l) in Ev: j = col and row >= i and row < k and
71.130 + xe1[i,j,k,l] = 0 and xe2[i,j,k,l] = 0} " ";
71.131 + /* No vertical edges: skip also a field */
71.132 + printf{0..0: card({(i,j,k,l) in Ev: j = col and row >= i and row < k}) = 0} " ";
71.133 + printf " ";
71.134 + }
71.135 + printf "\n";
71.136 +}
71.137 +
71.138 +data;
71.139 +
71.140 +/* This is a difficult 25x25 Hashiwokakero.
71.141 + */
71.142 +param givens : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
71.143 +25 :=
71.144 + 1 2 . 2 . 2 . . 2 . 2 . . 2 . . . . 2 . 2 . 2 . 2 .
71.145 + 2 . 1 . . . . 2 . . . 4 . . 5 . 2 . . 1 . 2 . 2 . 1
71.146 + 3 2 . . 5 . 4 . . 3 . . . . . 1 . . 4 . 5 . 1 . 1 .
71.147 + 4 . . . . . . . . . . . 1 . 3 . . 1 . . . . . . . .
71.148 + 5 2 . . 6 . 6 . . 8 . 5 . 2 . . 3 . 5 . 7 . . 2 . .
71.149 + 6 . 1 . . . . . . . . . 1 . . 2 . . . . . 1 . . . 3
71.150 + 7 2 . . . . 5 . . 6 . 4 . . 2 . . . 2 . 5 . 4 . 2 .
71.151 + 8 . 2 . 2 . . . . . . . . . . . 3 . . 3 . . . 1 . 2
71.152 + 9 . . . . . . . . . . 4 . 2 . 2 . . 1 . . . 3 . 1 .
71.153 + 10 2 . 3 . . 6 . . 2 . . . . . . . . . . 3 . . . . .
71.154 + 11 . . . . 1 . . 2 . . 5 . . 1 . 4 . 3 . . . . 2 . 4
71.155 + 12 . . 2 . . 1 . . . . . . 5 . 4 . . . . 4 . 3 . . .
71.156 + 13 2 . . . 3 . 1 . . . . . . . . 3 . . 5 . 5 . . 2 .
71.157 + 14 . . . . . 2 . 5 . . 7 . 5 . 3 . 1 . . 1 . . 1 . 4
71.158 + 15 2 . 5 . 3 . . . . 1 . 2 . 1 . . . . 2 . 4 . . 2 .
71.159 + 16 . . . . . 1 . . . . . . . . . . 2 . . 2 . 1 . . 3
71.160 + 17 2 . 6 . 6 . . 2 . . 2 . 2 . 5 . . . . . 2 . . . .
71.161 + 18 . . . . . 1 . . . 3 . . . . . 1 . . 1 . . 4 . 3 .
71.162 + 19 . . 4 . 5 . . 2 . . . 2 . . 6 . 6 . . 3 . . . . 3
71.163 + 20 2 . . . . . . . . . 2 . . 1 . . . . . . 1 . . 1 .
71.164 + 21 . . 3 . . 3 . 5 . 5 . . 4 . 6 . 7 . . 4 . 6 . . 4
71.165 + 22 2 . . . 3 . 5 . 2 . 1 . . . . . . . . . . . . . .
71.166 + 23 . . . . . . . . . 1 . . . . . . 3 . 2 . . 5 . . 5
71.167 + 24 2 . 3 . 3 . 5 . 4 . 3 . 3 . 4 . . 2 . 2 . . . 1 .
71.168 + 25 . 1 . 2 . 2 . . . 2 . 2 . . . 2 . . . . 2 . 2 . 2
71.169 + ;
71.170 +
71.171 +end;
72.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
72.2 +++ b/examples/huge.mod Mon Dec 06 13:09:21 2010 +0100
72.3 @@ -0,0 +1,25 @@
72.4 +/*Arithmetic Mean of a large number of Integers
72.5 + - or - solve a very large constraint matrix
72.6 + over 1 million rows and columns
72.7 + Nigel_Galloway@operamail.com
72.8 + March 18th., 2008.
72.9 +*/
72.10 +
72.11 +param e := 20;
72.12 +/* set Sample := {-2**e..2**e-1}; */
72.13 +set Sample := {1..2**e-1};
72.14 +
72.15 +var Mean;
72.16 +var E{z in Sample};
72.17 +
72.18 +/* sum of variances is zero */
72.19 +zumVariance: sum{z in Sample} E[z] = 0;
72.20 +
72.21 +/* Mean + variance[n] = Sample[n] */
72.22 +variances{z in Sample}: Mean + E[z] = z;
72.23 +
72.24 +solve;
72.25 +
72.26 +printf "The arithmetic mean of the integers from 1 to %d is %f\n", 2**e-1, Mean;
72.27 +
72.28 +end;
73.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
73.2 +++ b/examples/iptsamp.c Mon Dec 06 13:09:21 2010 +0100
73.3 @@ -0,0 +1,17 @@
73.4 +/* iptsamp.c */
73.5 +
73.6 +#include <stdio.h>
73.7 +#include <stdlib.h>
73.8 +#include <glpk.h>
73.9 +
73.10 +int main(void)
73.11 +{ glp_prob *P;
73.12 + P = glp_create_prob();
73.13 + glp_read_mps(P, GLP_MPS_DECK, NULL, "25fv47.mps");
73.14 + glp_interior(P, NULL);
73.15 + glp_print_ipt(P, "25fv47.txt");
73.16 + glp_delete_prob(P);
73.17 + return 0;
73.18 +}
73.19 +
73.20 +/* eof */
74.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
74.2 +++ b/examples/jssp.mod Mon Dec 06 13:09:21 2010 +0100
74.3 @@ -0,0 +1,114 @@
74.4 +/* JSSP, Job-Shop Scheduling Problem */
74.5 +
74.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
74.7 +
74.8 +/* The Job-Shop Scheduling Problem (JSSP) is to schedule a set of jobs
74.9 + on a set of machines, subject to the constraint that each machine can
74.10 + handle at most one job at a time and the fact that each job has a
74.11 + specified processing order through the machines. The objective is to
74.12 + schedule the jobs so as to minimize the maximum of their completion
74.13 + times.
74.14 +
74.15 + Reference:
74.16 + D. Applegate and W. Cook, "A Computational Study of the Job-Shop
74.17 + Scheduling Problem", ORSA J. On Comput., Vol. 3, No. 2, Spring 1991,
74.18 + pp. 149-156. */
74.19 +
74.20 +param n, integer, > 0;
74.21 +/* number of jobs */
74.22 +
74.23 +param m, integer, > 0;
74.24 +/* number of machines */
74.25 +
74.26 +set J := 1..n;
74.27 +/* set of jobs */
74.28 +
74.29 +set M := 1..m;
74.30 +/* set of machines */
74.31 +
74.32 +param sigma{j in J, t in 1..m}, in M;
74.33 +/* permutation of the machines, which represents the processing order
74.34 + of j through the machines: j must be processed first on sigma[j,1],
74.35 + then on sigma[j,2], etc. */
74.36 +
74.37 +check{j in J, t1 in 1..m, t2 in 1..m: t1 <> t2}:
74.38 + sigma[j,t1] != sigma[j,t2];
74.39 +/* sigma must be permutation */
74.40 +
74.41 +param p{j in J, a in M}, >= 0;
74.42 +/* processing time of j on a */
74.43 +
74.44 +var x{j in J, a in M}, >= 0;
74.45 +/* starting time of j on a */
74.46 +
74.47 +s.t. ord{j in J, t in 2..m}:
74.48 + x[j, sigma[j,t]] >= x[j, sigma[j,t-1]] + p[j, sigma[j,t-1]];
74.49 +/* j can be processed on sigma[j,t] only after it has been completely
74.50 + processed on sigma[j,t-1] */
74.51 +
74.52 +/* The disjunctive condition that each machine can handle at most one
74.53 + job at a time is the following:
74.54 +
74.55 + x[i,a] >= x[j,a] + p[j,a] or x[j,a] >= x[i,a] + p[i,a]
74.56 +
74.57 + for all i, j in J, a in M. This condition is modeled through binary
74.58 + variables Y as shown below. */
74.59 +
74.60 +var Y{i in J, j in J, a in M}, binary;
74.61 +/* Y[i,j,a] is 1 if i scheduled before j on machine a, and 0 if j is
74.62 + scheduled before i */
74.63 +
74.64 +param K := sum{j in J, a in M} p[j,a];
74.65 +/* some large constant */
74.66 +
74.67 +display K;
74.68 +
74.69 +s.t. phi{i in J, j in J, a in M: i <> j}:
74.70 + x[i,a] >= x[j,a] + p[j,a] - K * Y[i,j,a];
74.71 +/* x[i,a] >= x[j,a] + p[j,a] iff Y[i,j,a] is 0 */
74.72 +
74.73 +s.t. psi{i in J, j in J, a in M: i <> j}:
74.74 + x[j,a] >= x[i,a] + p[i,a] - K * (1 - Y[i,j,a]);
74.75 +/* x[j,a] >= x[i,a] + p[i,a] iff Y[i,j,a] is 1 */
74.76 +
74.77 +var z;
74.78 +/* so-called makespan */
74.79 +
74.80 +s.t. fin{j in J}: z >= x[j, sigma[j,m]] + p[j, sigma[j,m]];
74.81 +/* which is the maximum of the completion times of all the jobs */
74.82 +
74.83 +minimize obj: z;
74.84 +/* the objective is to make z as small as possible */
74.85 +
74.86 +data;
74.87 +
74.88 +/* These data correspond to the instance ft06 (mt06) from:
74.89 +
74.90 + H. Fisher, G.L. Thompson (1963), Probabilistic learning combinations
74.91 + of local job-shop scheduling rules, J.F. Muth, G.L. Thompson (eds.),
74.92 + Industrial Scheduling, Prentice Hall, Englewood Cliffs, New Jersey,
74.93 + 225-251 */
74.94 +
74.95 +/* The optimal solution is 55 */
74.96 +
74.97 +param n := 6;
74.98 +
74.99 +param m := 6;
74.100 +
74.101 +param sigma : 1 2 3 4 5 6 :=
74.102 + 1 3 1 2 4 6 5
74.103 + 2 2 3 5 6 1 4
74.104 + 3 3 4 6 1 2 5
74.105 + 4 2 1 3 4 5 6
74.106 + 5 3 2 5 6 1 4
74.107 + 6 2 4 6 1 5 3 ;
74.108 +
74.109 +param p : 1 2 3 4 5 6 :=
74.110 + 1 3 6 1 7 6 3
74.111 + 2 10 8 5 4 10 10
74.112 + 3 9 1 5 4 7 8
74.113 + 4 5 5 5 3 8 9
74.114 + 5 3 3 9 1 5 4
74.115 + 6 10 3 1 3 4 9 ;
74.116 +
74.117 +end;
75.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
75.2 +++ b/examples/magic.mod Mon Dec 06 13:09:21 2010 +0100
75.3 @@ -0,0 +1,54 @@
75.4 +/* MAGIC, Magic Square */
75.5 +
75.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
75.7 +
75.8 +/* In recreational mathematics, a magic square of order n is an
75.9 + arrangement of n^2 numbers, usually distinct integers, in a square,
75.10 + such that n numbers in all rows, all columns, and both diagonals sum
75.11 + to the same constant. A normal magic square contains the integers
75.12 + from 1 to n^2.
75.13 +
75.14 + (From Wikipedia, the free encyclopedia.) */
75.15 +
75.16 +param n, integer, > 0, default 4;
75.17 +/* square order */
75.18 +
75.19 +set N := 1..n^2;
75.20 +/* integers to be placed */
75.21 +
75.22 +var x{i in 1..n, j in 1..n, k in N}, binary;
75.23 +/* x[i,j,k] = 1 means that cell (i,j) contains integer k */
75.24 +
75.25 +s.t. a{i in 1..n, j in 1..n}: sum{k in N} x[i,j,k] = 1;
75.26 +/* each cell must be assigned exactly one integer */
75.27 +
75.28 +s.t. b{k in N}: sum{i in 1..n, j in 1..n} x[i,j,k] = 1;
75.29 +/* each integer must be assigned exactly to one cell */
75.30 +
75.31 +var s;
75.32 +/* the magic sum */
75.33 +
75.34 +s.t. r{i in 1..n}: sum{j in 1..n, k in N} k * x[i,j,k] = s;
75.35 +/* the sum in each row must be the magic sum */
75.36 +
75.37 +s.t. c{j in 1..n}: sum{i in 1..n, k in N} k * x[i,j,k] = s;
75.38 +/* the sum in each column must be the magic sum */
75.39 +
75.40 +s.t. d: sum{i in 1..n, k in N} k * x[i,i,k] = s;
75.41 +/* the sum in the diagonal must be the magic sum */
75.42 +
75.43 +s.t. e: sum{i in 1..n, k in N} k * x[i,n-i+1,k] = s;
75.44 +/* the sum in the co-diagonal must be the magic sum */
75.45 +
75.46 +solve;
75.47 +
75.48 +printf "\n";
75.49 +printf "Magic sum is %d\n", s;
75.50 +printf "\n";
75.51 +for{i in 1..n}
75.52 +{ printf{j in 1..n} "%3d", sum{k in N} k * x[i,j,k];
75.53 + printf "\n";
75.54 +}
75.55 +printf "\n";
75.56 +
75.57 +end;
76.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
76.2 +++ b/examples/maxcut.mod Mon Dec 06 13:09:21 2010 +0100
76.3 @@ -0,0 +1,85 @@
76.4 +/* MAXCUT, Maximum Cut Problem */
76.5 +
76.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
76.7 +
76.8 +/* The Maximum Cut Problem in a network G = (V, E), where V is a set
76.9 + of nodes, E is a set of edges, is to find the partition of V into
76.10 + disjoint sets V1 and V2, which maximizes the sum of edge weights
76.11 + w(e), where edge e has one endpoint in V1 and other endpoint in V2.
76.12 +
76.13 + Reference:
76.14 + Garey, M.R., and Johnson, D.S. (1979), Computers and Intractability:
76.15 + A guide to the theory of NP-completeness [Network design, Cuts and
76.16 + Connectivity, Maximum Cut, ND16]. */
76.17 +
76.18 +set E, dimen 2;
76.19 +/* set of edges */
76.20 +
76.21 +param w{(i,j) in E}, >= 0, default 1;
76.22 +/* w[i,j] is weight of edge (i,j) */
76.23 +
76.24 +set V := (setof{(i,j) in E} i) union (setof{(i,j) in E} j);
76.25 +/* set of nodes */
76.26 +
76.27 +var x{i in V}, binary;
76.28 +/* x[i] = 0 means that node i is in set V1
76.29 + x[i] = 1 means that node i is in set V2 */
76.30 +
76.31 +/* We need to include in the objective function only that edges (i,j)
76.32 + from E, for which x[i] != x[j]. This can be modeled through binary
76.33 + variables s[i,j] as follows:
76.34 +
76.35 + s[i,j] = x[i] xor x[j] = (x[i] + x[j]) mod 2, (1)
76.36 +
76.37 + where s[i,j] = 1 iff x[i] != x[j], that leads to the following
76.38 + objective function:
76.39 +
76.40 + z = sum{(i,j) in E} w[i,j] * s[i,j]. (2)
76.41 +
76.42 + To describe "exclusive or" (1) we could think that s[i,j] is a minor
76.43 + bit of the sum x[i] + x[j]. Then introducing binary variables t[i,j],
76.44 + which represent a major bit of the sum x[i] + x[j], we can write:
76.45 +
76.46 + x[i] + x[j] = s[i,j] + 2 * t[i,j]. (3)
76.47 +
76.48 + An easy check shows that conditions (1) and (3) are equivalent.
76.49 +
76.50 + Note that condition (3) can be simplified by eliminating variables
76.51 + s[i,j]. Indeed, from (3) it follows that:
76.52 +
76.53 + s[i,j] = x[i] + x[j] - 2 * t[i,j]. (4)
76.54 +
76.55 + Since the expression in the right-hand side of (4) is integral, this
76.56 + condition can be rewritten in the equivalent form:
76.57 +
76.58 + 0 <= x[i] + x[j] - 2 * t[i,j] <= 1. (5)
76.59 +
76.60 + (One might note that (5) means t[i,j] = x[i] and x[j].)
76.61 +
76.62 + Substituting s[i,j] from (4) to (2) leads to the following objective
76.63 + function:
76.64 +
76.65 + z = sum{(i,j) in E} w[i,j] * (x[i] + x[j] - 2 * t[i,j]), (6)
76.66 +
76.67 + which does not include variables s[i,j]. */
76.68 +
76.69 +var t{(i,j) in E}, binary;
76.70 +/* t[i,j] = x[i] and x[j] = (x[i] + x[j]) div 2 */
76.71 +
76.72 +s.t. xor{(i,j) in E}: 0 <= x[i] + x[j] - 2 * t[i,j] <= 1;
76.73 +/* see (4) */
76.74 +
76.75 +maximize z: sum{(i,j) in E} w[i,j] * (x[i] + x[j] - 2 * t[i,j]);
76.76 +/* see (6) */
76.77 +
76.78 +data;
76.79 +
76.80 +/* In this example the network has 15 nodes and 22 edges. */
76.81 +
76.82 +/* Optimal solution is 20 */
76.83 +
76.84 +set E :=
76.85 + 1 2, 1 5, 2 3, 2 6, 3 4, 3 8, 4 9, 5 6, 5 7, 6 8, 7 8, 7 12, 8 9,
76.86 + 8 12, 9 10, 9 14, 10 11, 10 14, 11 15, 12 13, 13 14, 14 15;
76.87 +
76.88 +end;
77.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
77.2 +++ b/examples/maxflow.mod Mon Dec 06 13:09:21 2010 +0100
77.3 @@ -0,0 +1,83 @@
77.4 +/* MAXFLOW, Maximum Flow Problem */
77.5 +
77.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
77.7 +
77.8 +/* The Maximum Flow Problem in a network G = (V, E), where V is a set
77.9 + of nodes, E within V x V is a set of arcs, is to maximize the flow
77.10 + from one given node s (source) to another given node t (sink) subject
77.11 + to conservation of flow constraints at each node and flow capacities
77.12 + on each arc. */
77.13 +
77.14 +param n, integer, >= 2;
77.15 +/* number of nodes */
77.16 +
77.17 +set V, default {1..n};
77.18 +/* set of nodes */
77.19 +
77.20 +set E, within V cross V;
77.21 +/* set of arcs */
77.22 +
77.23 +param a{(i,j) in E}, > 0;
77.24 +/* a[i,j] is capacity of arc (i,j) */
77.25 +
77.26 +param s, symbolic, in V, default 1;
77.27 +/* source node */
77.28 +
77.29 +param t, symbolic, in V, != s, default n;
77.30 +/* sink node */
77.31 +
77.32 +var x{(i,j) in E}, >= 0, <= a[i,j];
77.33 +/* x[i,j] is elementary flow through arc (i,j) to be found */
77.34 +
77.35 +var flow, >= 0;
77.36 +/* total flow from s to t */
77.37 +
77.38 +s.t. node{i in V}:
77.39 +/* node[i] is conservation constraint for node i */
77.40 +
77.41 + sum{(j,i) in E} x[j,i] + (if i = s then flow)
77.42 + /* summary flow into node i through all ingoing arcs */
77.43 +
77.44 + = /* must be equal to */
77.45 +
77.46 + sum{(i,j) in E} x[i,j] + (if i = t then flow);
77.47 + /* summary flow from node i through all outgoing arcs */
77.48 +
77.49 +maximize obj: flow;
77.50 +/* objective is to maximize the total flow through the network */
77.51 +
77.52 +solve;
77.53 +
77.54 +printf{1..56} "="; printf "\n";
77.55 +printf "Maximum flow from node %s to node %s is %g\n\n", s, t, flow;
77.56 +printf "Starting node Ending node Arc capacity Flow in arc\n";
77.57 +printf "------------- ----------- ------------ -----------\n";
77.58 +printf{(i,j) in E: x[i,j] != 0}: "%13s %11s %12g %11g\n", i, j,
77.59 + a[i,j], x[i,j];
77.60 +printf{1..56} "="; printf "\n";
77.61 +
77.62 +data;
77.63 +
77.64 +/* These data correspond to an example from [Christofides]. */
77.65 +
77.66 +/* Optimal solution is 29 */
77.67 +
77.68 +param n := 9;
77.69 +
77.70 +param : E : a :=
77.71 + 1 2 14
77.72 + 1 4 23
77.73 + 2 3 10
77.74 + 2 4 9
77.75 + 3 5 12
77.76 + 3 8 18
77.77 + 4 5 26
77.78 + 5 2 11
77.79 + 5 6 25
77.80 + 5 7 4
77.81 + 6 7 7
77.82 + 6 8 8
77.83 + 7 9 15
77.84 + 8 9 20;
77.85 +
77.86 +end;
78.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
78.2 +++ b/examples/mfasp.mod Mon Dec 06 13:09:21 2010 +0100
78.3 @@ -0,0 +1,62 @@
78.4 +/* MFASP, Minimum Feedback Arc Set Problem */
78.5 +
78.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
78.7 +
78.8 +/* The Minimum Feedback Arc Set Problem for a given directed graph
78.9 + G = (V, E), where V is a set of vertices and E is a set of arcs, is
78.10 + to find a minimal subset of arcs, which being removed from the graph
78.11 + make it acyclic.
78.12 +
78.13 + Reference:
78.14 + Garey, M.R., and Johnson, D.S. (1979), Computers and Intractability:
78.15 + A guide to the theory of NP-completeness [Graph Theory, Covering and
78.16 + Partitioning, Minimum Feedback Arc Set, GT9]. */
78.17 +
78.18 +param n, integer, >= 0;
78.19 +/* number of vertices */
78.20 +
78.21 +set V, default 1..n;
78.22 +/* set of vertices */
78.23 +
78.24 +set E, within V cross V,
78.25 +default setof{i in V, j in V: i <> j and Uniform(0,1) <= 0.15} (i,j);
78.26 +/* set of arcs */
78.27 +
78.28 +printf "Graph has %d vertices and %d arcs\n", card(V), card(E);
78.29 +
78.30 +var x{(i,j) in E}, binary;
78.31 +/* x[i,j] = 1 means that (i->j) is a feedback arc */
78.32 +
78.33 +/* It is known that a digraph G = (V, E) is acyclic if and only if its
78.34 + vertices can be assigned numbers from 1 to |V| in such a way that
78.35 + k[i] + 1 <= k[j] for every arc (i->j) in E, where k[i] is a number
78.36 + assigned to vertex i. We may use this condition to require that the
78.37 + digraph G = (V, E \ E'), where E' is a subset of feedback arcs, is
78.38 + acyclic. */
78.39 +
78.40 +var k{i in V}, >= 1, <= card(V);
78.41 +/* k[i] is a number assigned to vertex i */
78.42 +
78.43 +s.t. r{(i,j) in E}: k[j] - k[i] >= 1 - card(V) * x[i,j];
78.44 +/* note that x[i,j] = 1 leads to a redundant constraint */
78.45 +
78.46 +minimize obj: sum{(i,j) in E} x[i,j];
78.47 +/* the objective is to minimize the cardinality of a subset of feedback
78.48 + arcs */
78.49 +
78.50 +solve;
78.51 +
78.52 +printf "Minimum feedback arc set:\n";
78.53 +printf{(i,j) in E: x[i,j]} "%d %d\n", i, j;
78.54 +
78.55 +data;
78.56 +
78.57 +/* The optimal solution is 3 */
78.58 +
78.59 +param n := 15;
78.60 +
78.61 +set E := 1 2, 2 3, 3 4, 3 8, 4 9, 5 1, 6 5, 7 5, 8 6, 8 7, 8 9, 9 10,
78.62 + 10 11, 10 14, 11 15, 12 7, 12 8, 12 13, 13 8, 13 12, 13 14,
78.63 + 14 9, 15 14;
78.64 +
78.65 +end;
79.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
79.2 +++ b/examples/mfvsp.mod Mon Dec 06 13:09:21 2010 +0100
79.3 @@ -0,0 +1,62 @@
79.4 +/* MFVSP, Minimum Feedback Vertex Set Problem */
79.5 +
79.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
79.7 +
79.8 +/* The Minimum Feedback Vertex Set Problem for a given directed graph
79.9 + G = (V, E), where V is a set of vertices and E is a set of arcs, is
79.10 + to find a minimal subset of vertices, which being removed from the
79.11 + graph make it acyclic.
79.12 +
79.13 + Reference:
79.14 + Garey, M.R., and Johnson, D.S. (1979), Computers and Intractability:
79.15 + A guide to the theory of NP-completeness [Graph Theory, Covering and
79.16 + Partitioning, Minimum Feedback Vertex Set, GT8]. */
79.17 +
79.18 +param n, integer, >= 0;
79.19 +/* number of vertices */
79.20 +
79.21 +set V, default 1..n;
79.22 +/* set of vertices */
79.23 +
79.24 +set E, within V cross V,
79.25 +default setof{i in V, j in V: i <> j and Uniform(0,1) <= 0.15} (i,j);
79.26 +/* set of arcs */
79.27 +
79.28 +printf "Graph has %d vertices and %d arcs\n", card(V), card(E);
79.29 +
79.30 +var x{i in V}, binary;
79.31 +/* x[i] = 1 means that i is a feedback vertex */
79.32 +
79.33 +/* It is known that a digraph G = (V, E) is acyclic if and only if its
79.34 + vertices can be assigned numbers from 1 to |V| in such a way that
79.35 + k[i] + 1 <= k[j] for every arc (i->j) in E, where k[i] is a number
79.36 + assigned to vertex i. We may use this condition to require that the
79.37 + digraph G = (V, E \ E'), where E' is a subset of feedback arcs, is
79.38 + acyclic. */
79.39 +
79.40 +var k{i in V}, >= 1, <= card(V);
79.41 +/* k[i] is a number assigned to vertex i */
79.42 +
79.43 +s.t. r{(i,j) in E}: k[j] - k[i] >= 1 - card(V) * (x[i] + x[j]);
79.44 +/* note that x[i] = 1 or x[j] = 1 leads to a redundant constraint */
79.45 +
79.46 +minimize obj: sum{i in V} x[i];
79.47 +/* the objective is to minimize the cardinality of a subset of feedback
79.48 + vertices */
79.49 +
79.50 +solve;
79.51 +
79.52 +printf "Minimum feedback vertex set:\n";
79.53 +printf{i in V: x[i]} "%d\n", i;
79.54 +
79.55 +data;
79.56 +
79.57 +/* The optimal solution is 3 */
79.58 +
79.59 +param n := 15;
79.60 +
79.61 +set E := 1 2, 2 3, 3 4, 3 8, 4 9, 5 1, 6 5, 7 5, 8 6, 8 7, 8 9, 9 10,
79.62 + 10 11, 10 14, 11 15, 12 7, 12 8, 12 13, 13 8, 13 12, 13 14,
79.63 + 14 9, 15 14;
79.64 +
79.65 +end;
80.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
80.2 +++ b/examples/min01ks.mod Mon Dec 06 13:09:21 2010 +0100
80.3 @@ -0,0 +1,111 @@
80.4 +/* min01ks.mod - finding minimal equivalent 0-1 knapsack inequality */
80.5 +
80.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
80.7 +
80.8 +/* It is obvious that for a given 0-1 knapsack inequality
80.9 +
80.10 + a[1] x[1] + ... + a[n] x[n] <= b, x[j] in {0, 1} (1)
80.11 +
80.12 + there exist infinitely many equivalent inequalities with exactly the
80.13 + same feasible solutions.
80.14 +
80.15 + Given a[j]'s and b this model allows to find an inequality
80.16 +
80.17 + alfa[1] x[1] + ... + alfa[n] x[n] <= beta, x[j] in {0, 1}, (2)
80.18 +
80.19 + which is equivalent to (1) and where alfa[j]'s and beta are smallest
80.20 + non-negative integers.
80.21 +
80.22 + This model has the following formulation:
80.23 +
80.24 + minimize
80.25 +
80.26 + z = |alfa[1]| + ... + |alfa[n]| + |beta| = (3)
80.27 +
80.28 + = alfa[1] + ... + alfa[n] + beta
80.29 +
80.30 + subject to
80.31 +
80.32 + alfa[1] x[1] + ... + alfa[n] x[n] <= beta (4)
80.33 +
80.34 + for all x satisfying to (1)
80.35 +
80.36 + alfa[1] x[1] + ... + alfa[n] x[n] >= beta + 1 (5)
80.37 +
80.38 + for all x not satisfying to (1)
80.39 +
80.40 + alfa[1], ..., alfa[n], beta are non-negative integers.
80.41 +
80.42 + Note that this model has n+1 variables and 2^n constraints.
80.43 +
80.44 + It is interesting, as noticed in [1] and explained in [2], that
80.45 + in most cases LP relaxation of the MIP formulation above has integer
80.46 + optimal solution.
80.47 +
80.48 + References
80.49 +
80.50 + 1. G.H.Bradley, P.L.Hammer, L.Wolsey, "Coefficient Reduction for
80.51 + Inequalities in 0-1 Variables", Math.Prog.7 (1974), 263-282.
80.52 +
80.53 + 2. G.J.Koehler, "A Study on Coefficient Reduction of Binary Knapsack
80.54 + Inequalities", University of Florida, 2001. */
80.55 +
80.56 +param n, integer, > 0;
80.57 +/* number of variables in the knapsack inequality */
80.58 +
80.59 +set N := 1..n;
80.60 +/* set of knapsack items */
80.61 +
80.62 +/* all binary n-vectors are numbered by 0, 1, ..., 2^n-1, where vector
80.63 + 0 is 00...00, vector 1 is 00...01, etc. */
80.64 +
80.65 +set U := 0..2^n-1;
80.66 +/* set of numbers of all binary n-vectors */
80.67 +
80.68 +param x{i in U, j in N}, binary, := (i div 2^(j-1)) mod 2;
80.69 +/* x[i,j] is j-th component of i-th binary n-vector */
80.70 +
80.71 +param a{j in N}, >= 0;
80.72 +/* original coefficients */
80.73 +
80.74 +param b, >= 0;
80.75 +/* original right-hand side */
80.76 +
80.77 +set D := setof{i in U: sum{j in N} a[j] * x[i,j] <= b} i;
80.78 +/* set of numbers of binary n-vectors, which (vectors) are feasible,
80.79 + i.e. satisfy to the original knapsack inequality (1) */
80.80 +
80.81 +var alfa{j in N}, integer, >= 0;
80.82 +/* coefficients to be found */
80.83 +
80.84 +var beta, integer, >= 0;
80.85 +/* right-hand side to be found */
80.86 +
80.87 +minimize z: sum{j in N} alfa[j] + beta; /* (3) */
80.88 +
80.89 +phi{i in D}: sum{j in N} alfa[j] * x[i,j] <= beta; /* (4) */
80.90 +
80.91 +psi{i in U diff D}: sum{j in N} alfa[j] * x[i,j] >= beta + 1; /* (5) */
80.92 +
80.93 +solve;
80.94 +
80.95 +printf "\nOriginal 0-1 knapsack inequality:\n";
80.96 +for {j in 1..n} printf (if j = 1 then "" else " + ") & "%g x%d",
80.97 + a[j], j;
80.98 +printf " <= %g\n", b;
80.99 +printf "\nMinimized equivalent inequality:\n";
80.100 +for {j in 1..n} printf (if j = 1 then "" else " + ") & "%g x%d",
80.101 + alfa[j], j;
80.102 +printf " <= %g\n\n", beta;
80.103 +
80.104 +data;
80.105 +
80.106 +/* These data correspond to the very first example from [1]. */
80.107 +
80.108 +param n := 8;
80.109 +
80.110 +param a := [1]65, [2]64, [3]41, [4]22, [5]13, [6]12, [7]8, [8]2;
80.111 +
80.112 +param b := 80;
80.113 +
80.114 +end;
81.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
81.2 +++ b/examples/misp.mod Mon Dec 06 13:09:21 2010 +0100
81.3 @@ -0,0 +1,665 @@
81.4 +/* MISP, Maximum Independent Set Problem */
81.5 +
81.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
81.7 +
81.8 +/* Let G = (V,E) be an undirected graph with vertex set V and edge set
81.9 + E. Vertices u, v in V are non-adjacent if (u,v) not in E. A subset
81.10 + of the vertices S within V is independent if all vertices in S are
81.11 + pairwise non-adjacent. The Maximum Independent Set Problem (MISP) is
81.12 + to find an independent set having the largest cardinality. */
81.13 +
81.14 +param n, integer, > 0;
81.15 +/* number of vertices */
81.16 +
81.17 +set V := 1..n;
81.18 +/* set of vertices */
81.19 +
81.20 +set E within V cross V;
81.21 +/* set of edges */
81.22 +
81.23 +var x{i in V}, binary;
81.24 +/* x[i] = 1 means vertex i belongs to independent set */
81.25 +
81.26 +s.t. edge{(i,j) in E}: x[i] + x[j] <= 1;
81.27 +/* if there is edge (i,j), vertices i and j cannot belong to the same
81.28 + independent set */
81.29 +
81.30 +maximize obj: sum{i in V} x[i];
81.31 +/* the objective is to maximize the cardinality of independent set */
81.32 +
81.33 +data;
81.34 +
81.35 +/* These data corresponds to the test instance from:
81.36 +
81.37 + M.G.C. Resende, T.A.Feo, S.H.Smith, "Algorithm 787 -- FORTRAN
81.38 + subroutines for approximate solution of the maximum independent set
81.39 + problem using GRASP," Trans. on Math. Softw., Vol. 24, No. 4,
81.40 + December 1998, pp. 386-394. */
81.41 +
81.42 +/* The optimal solution is 7 */
81.43 +
81.44 +param n := 50;
81.45 +
81.46 +set E :=
81.47 + 1 2
81.48 + 1 3
81.49 + 1 5
81.50 + 1 7
81.51 + 1 8
81.52 + 1 12
81.53 + 1 15
81.54 + 1 16
81.55 + 1 19
81.56 + 1 20
81.57 + 1 21
81.58 + 1 22
81.59 + 1 28
81.60 + 1 30
81.61 + 1 34
81.62 + 1 35
81.63 + 1 37
81.64 + 1 41
81.65 + 1 42
81.66 + 1 47
81.67 + 1 50
81.68 + 2 3
81.69 + 2 5
81.70 + 2 6
81.71 + 2 7
81.72 + 2 8
81.73 + 2 9
81.74 + 2 10
81.75 + 2 13
81.76 + 2 17
81.77 + 2 19
81.78 + 2 20
81.79 + 2 21
81.80 + 2 23
81.81 + 2 25
81.82 + 2 26
81.83 + 2 29
81.84 + 2 31
81.85 + 2 35
81.86 + 2 36
81.87 + 2 44
81.88 + 2 45
81.89 + 2 46
81.90 + 2 50
81.91 + 3 5
81.92 + 3 6
81.93 + 3 8
81.94 + 3 9
81.95 + 3 10
81.96 + 3 11
81.97 + 3 14
81.98 + 3 16
81.99 + 3 23
81.100 + 3 24
81.101 + 3 26
81.102 + 3 27
81.103 + 3 28
81.104 + 3 29
81.105 + 3 30
81.106 + 3 31
81.107 + 3 34
81.108 + 3 35
81.109 + 3 36
81.110 + 3 39
81.111 + 3 41
81.112 + 3 42
81.113 + 3 43
81.114 + 3 44
81.115 + 3 50
81.116 + 4 6
81.117 + 4 7
81.118 + 4 9
81.119 + 4 10
81.120 + 4 11
81.121 + 4 13
81.122 + 4 14
81.123 + 4 15
81.124 + 4 17
81.125 + 4 21
81.126 + 4 22
81.127 + 4 23
81.128 + 4 24
81.129 + 4 25
81.130 + 4 27
81.131 + 4 28
81.132 + 4 30
81.133 + 4 31
81.134 + 4 33
81.135 + 4 34
81.136 + 4 35
81.137 + 4 36
81.138 + 4 37
81.139 + 4 38
81.140 + 4 40
81.141 + 4 41
81.142 + 4 42
81.143 + 4 46
81.144 + 4 49
81.145 + 5 6
81.146 + 5 11
81.147 + 5 14
81.148 + 5 21
81.149 + 5 24
81.150 + 5 25
81.151 + 5 28
81.152 + 5 35
81.153 + 5 38
81.154 + 5 39
81.155 + 5 41
81.156 + 5 44
81.157 + 5 49
81.158 + 5 50
81.159 + 6 8
81.160 + 6 9
81.161 + 6 10
81.162 + 6 13
81.163 + 6 14
81.164 + 6 16
81.165 + 6 17
81.166 + 6 19
81.167 + 6 22
81.168 + 6 23
81.169 + 6 26
81.170 + 6 27
81.171 + 6 30
81.172 + 6 34
81.173 + 6 35
81.174 + 6 38
81.175 + 6 39
81.176 + 6 40
81.177 + 6 41
81.178 + 6 44
81.179 + 6 45
81.180 + 6 47
81.181 + 6 50
81.182 + 7 8
81.183 + 7 9
81.184 + 7 10
81.185 + 7 11
81.186 + 7 13
81.187 + 7 15
81.188 + 7 16
81.189 + 7 18
81.190 + 7 20
81.191 + 7 22
81.192 + 7 23
81.193 + 7 24
81.194 + 7 25
81.195 + 7 33
81.196 + 7 35
81.197 + 7 36
81.198 + 7 38
81.199 + 7 43
81.200 + 7 45
81.201 + 7 46
81.202 + 7 47
81.203 + 8 10
81.204 + 8 11
81.205 + 8 13
81.206 + 8 16
81.207 + 8 17
81.208 + 8 18
81.209 + 8 19
81.210 + 8 20
81.211 + 8 21
81.212 + 8 22
81.213 + 8 23
81.214 + 8 24
81.215 + 8 25
81.216 + 8 26
81.217 + 8 33
81.218 + 8 35
81.219 + 8 36
81.220 + 8 39
81.221 + 8 42
81.222 + 8 44
81.223 + 8 48
81.224 + 8 49
81.225 + 9 12
81.226 + 9 14
81.227 + 9 17
81.228 + 9 19
81.229 + 9 20
81.230 + 9 23
81.231 + 9 28
81.232 + 9 30
81.233 + 9 31
81.234 + 9 32
81.235 + 9 33
81.236 + 9 34
81.237 + 9 38
81.238 + 9 39
81.239 + 9 42
81.240 + 9 44
81.241 + 9 45
81.242 + 9 46
81.243 + 10 11
81.244 + 10 13
81.245 + 10 15
81.246 + 10 16
81.247 + 10 17
81.248 + 10 20
81.249 + 10 21
81.250 + 10 22
81.251 + 10 23
81.252 + 10 25
81.253 + 10 26
81.254 + 10 27
81.255 + 10 28
81.256 + 10 30
81.257 + 10 31
81.258 + 10 32
81.259 + 10 37
81.260 + 10 38
81.261 + 10 41
81.262 + 10 43
81.263 + 10 44
81.264 + 10 45
81.265 + 10 50
81.266 + 11 12
81.267 + 11 14
81.268 + 11 15
81.269 + 11 18
81.270 + 11 21
81.271 + 11 24
81.272 + 11 25
81.273 + 11 26
81.274 + 11 29
81.275 + 11 32
81.276 + 11 33
81.277 + 11 35
81.278 + 11 36
81.279 + 11 37
81.280 + 11 39
81.281 + 11 40
81.282 + 11 42
81.283 + 11 43
81.284 + 11 45
81.285 + 11 47
81.286 + 11 49
81.287 + 11 50
81.288 + 12 13
81.289 + 12 16
81.290 + 12 17
81.291 + 12 19
81.292 + 12 24
81.293 + 12 25
81.294 + 12 26
81.295 + 12 30
81.296 + 12 31
81.297 + 12 32
81.298 + 12 34
81.299 + 12 36
81.300 + 12 37
81.301 + 12 39
81.302 + 12 41
81.303 + 12 44
81.304 + 12 47
81.305 + 12 48
81.306 + 12 49
81.307 + 13 15
81.308 + 13 16
81.309 + 13 18
81.310 + 13 19
81.311 + 13 20
81.312 + 13 22
81.313 + 13 23
81.314 + 13 24
81.315 + 13 27
81.316 + 13 28
81.317 + 13 29
81.318 + 13 31
81.319 + 13 33
81.320 + 13 35
81.321 + 13 36
81.322 + 13 37
81.323 + 13 44
81.324 + 13 47
81.325 + 13 49
81.326 + 13 50
81.327 + 14 15
81.328 + 14 16
81.329 + 14 17
81.330 + 14 18
81.331 + 14 19
81.332 + 14 20
81.333 + 14 21
81.334 + 14 26
81.335 + 14 28
81.336 + 14 29
81.337 + 14 30
81.338 + 14 31
81.339 + 14 32
81.340 + 14 34
81.341 + 14 35
81.342 + 14 36
81.343 + 14 38
81.344 + 14 39
81.345 + 14 41
81.346 + 14 44
81.347 + 14 46
81.348 + 14 47
81.349 + 14 48
81.350 + 15 18
81.351 + 15 21
81.352 + 15 22
81.353 + 15 23
81.354 + 15 25
81.355 + 15 28
81.356 + 15 29
81.357 + 15 30
81.358 + 15 33
81.359 + 15 34
81.360 + 15 36
81.361 + 15 37
81.362 + 15 38
81.363 + 15 39
81.364 + 15 40
81.365 + 15 43
81.366 + 15 44
81.367 + 15 46
81.368 + 15 50
81.369 + 16 17
81.370 + 16 19
81.371 + 16 20
81.372 + 16 25
81.373 + 16 26
81.374 + 16 29
81.375 + 16 35
81.376 + 16 38
81.377 + 16 39
81.378 + 16 40
81.379 + 16 41
81.380 + 16 42
81.381 + 16 44
81.382 + 17 18
81.383 + 17 19
81.384 + 17 21
81.385 + 17 22
81.386 + 17 23
81.387 + 17 25
81.388 + 17 26
81.389 + 17 28
81.390 + 17 29
81.391 + 17 33
81.392 + 17 37
81.393 + 17 44
81.394 + 17 45
81.395 + 17 48
81.396 + 18 20
81.397 + 18 24
81.398 + 18 27
81.399 + 18 28
81.400 + 18 31
81.401 + 18 32
81.402 + 18 34
81.403 + 18 35
81.404 + 18 36
81.405 + 18 37
81.406 + 18 38
81.407 + 18 45
81.408 + 18 48
81.409 + 18 49
81.410 + 18 50
81.411 + 19 22
81.412 + 19 24
81.413 + 19 28
81.414 + 19 29
81.415 + 19 36
81.416 + 19 37
81.417 + 19 39
81.418 + 19 41
81.419 + 19 43
81.420 + 19 45
81.421 + 19 48
81.422 + 19 49
81.423 + 20 21
81.424 + 20 22
81.425 + 20 24
81.426 + 20 25
81.427 + 20 26
81.428 + 20 27
81.429 + 20 29
81.430 + 20 30
81.431 + 20 31
81.432 + 20 33
81.433 + 20 34
81.434 + 20 35
81.435 + 20 38
81.436 + 20 39
81.437 + 20 41
81.438 + 20 42
81.439 + 20 43
81.440 + 20 44
81.441 + 20 45
81.442 + 20 46
81.443 + 20 48
81.444 + 20 49
81.445 + 21 22
81.446 + 21 23
81.447 + 21 29
81.448 + 21 31
81.449 + 21 35
81.450 + 21 38
81.451 + 21 42
81.452 + 21 46
81.453 + 21 47
81.454 + 22 23
81.455 + 22 26
81.456 + 22 27
81.457 + 22 28
81.458 + 22 29
81.459 + 22 30
81.460 + 22 39
81.461 + 22 40
81.462 + 22 41
81.463 + 22 42
81.464 + 22 44
81.465 + 22 45
81.466 + 22 46
81.467 + 22 47
81.468 + 22 49
81.469 + 22 50
81.470 + 23 28
81.471 + 23 31
81.472 + 23 32
81.473 + 23 33
81.474 + 23 34
81.475 + 23 35
81.476 + 23 36
81.477 + 23 39
81.478 + 23 40
81.479 + 23 41
81.480 + 23 42
81.481 + 23 44
81.482 + 23 45
81.483 + 23 48
81.484 + 23 49
81.485 + 23 50
81.486 + 24 25
81.487 + 24 27
81.488 + 24 29
81.489 + 24 30
81.490 + 24 31
81.491 + 24 33
81.492 + 24 34
81.493 + 24 38
81.494 + 24 42
81.495 + 24 43
81.496 + 24 44
81.497 + 24 49
81.498 + 24 50
81.499 + 25 26
81.500 + 25 27
81.501 + 25 29
81.502 + 25 30
81.503 + 25 33
81.504 + 25 34
81.505 + 25 36
81.506 + 25 38
81.507 + 25 40
81.508 + 25 41
81.509 + 25 42
81.510 + 25 44
81.511 + 25 46
81.512 + 25 47
81.513 + 25 48
81.514 + 25 49
81.515 + 26 28
81.516 + 26 31
81.517 + 26 32
81.518 + 26 33
81.519 + 26 37
81.520 + 26 38
81.521 + 26 39
81.522 + 26 40
81.523 + 26 41
81.524 + 26 42
81.525 + 26 45
81.526 + 26 47
81.527 + 26 48
81.528 + 26 49
81.529 + 27 29
81.530 + 27 30
81.531 + 27 33
81.532 + 27 34
81.533 + 27 35
81.534 + 27 39
81.535 + 27 40
81.536 + 27 46
81.537 + 27 48
81.538 + 28 29
81.539 + 28 37
81.540 + 28 40
81.541 + 28 42
81.542 + 28 44
81.543 + 28 46
81.544 + 28 47
81.545 + 28 50
81.546 + 29 35
81.547 + 29 38
81.548 + 29 39
81.549 + 29 41
81.550 + 29 42
81.551 + 29 48
81.552 + 30 31
81.553 + 30 32
81.554 + 30 35
81.555 + 30 37
81.556 + 30 38
81.557 + 30 40
81.558 + 30 43
81.559 + 30 45
81.560 + 30 46
81.561 + 30 47
81.562 + 30 48
81.563 + 31 33
81.564 + 31 35
81.565 + 31 38
81.566 + 31 40
81.567 + 31 41
81.568 + 31 42
81.569 + 31 44
81.570 + 31 46
81.571 + 31 47
81.572 + 31 50
81.573 + 32 33
81.574 + 32 35
81.575 + 32 39
81.576 + 32 40
81.577 + 32 46
81.578 + 32 49
81.579 + 32 50
81.580 + 33 34
81.581 + 33 36
81.582 + 33 37
81.583 + 33 40
81.584 + 33 42
81.585 + 33 43
81.586 + 33 44
81.587 + 33 45
81.588 + 33 50
81.589 + 34 35
81.590 + 34 36
81.591 + 34 37
81.592 + 34 38
81.593 + 34 40
81.594 + 34 43
81.595 + 34 44
81.596 + 34 49
81.597 + 34 50
81.598 + 35 36
81.599 + 35 38
81.600 + 35 41
81.601 + 35 42
81.602 + 35 43
81.603 + 35 45
81.604 + 35 46
81.605 + 35 47
81.606 + 35 49
81.607 + 35 50
81.608 + 36 37
81.609 + 36 39
81.610 + 36 40
81.611 + 36 41
81.612 + 36 42
81.613 + 36 43
81.614 + 36 48
81.615 + 36 50
81.616 + 37 38
81.617 + 37 41
81.618 + 37 43
81.619 + 37 46
81.620 + 37 47
81.621 + 37 48
81.622 + 37 49
81.623 + 37 50
81.624 + 38 41
81.625 + 38 45
81.626 + 38 46
81.627 + 38 48
81.628 + 38 49
81.629 + 38 50
81.630 + 39 43
81.631 + 39 46
81.632 + 39 47
81.633 + 39 48
81.634 + 39 49
81.635 + 40 43
81.636 + 40 45
81.637 + 40 48
81.638 + 40 50
81.639 + 41 42
81.640 + 41 43
81.641 + 41 44
81.642 + 41 45
81.643 + 41 46
81.644 + 41 48
81.645 + 41 49
81.646 + 42 43
81.647 + 42 44
81.648 + 42 46
81.649 + 42 48
81.650 + 42 49
81.651 + 43 45
81.652 + 43 46
81.653 + 43 48
81.654 + 43 50
81.655 + 44 45
81.656 + 44 48
81.657 + 45 46
81.658 + 45 47
81.659 + 45 48
81.660 + 46 49
81.661 + 47 49
81.662 + 47 50
81.663 + 48 49
81.664 + 48 50
81.665 + 49 50
81.666 +;
81.667 +
81.668 +end;
82.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
82.2 +++ b/examples/money.mod Mon Dec 06 13:09:21 2010 +0100
82.3 @@ -0,0 +1,62 @@
82.4 +/* MONEY, a crypto-arithmetic puzzle */
82.5 +
82.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
82.7 +
82.8 +/* This is the classic example of a crypto-arithmetic puzzle published
82.9 + in the Strand Magazine by Henry Dudeney:
82.10 +
82.11 + S E N D
82.12 + +
82.13 + M O R E
82.14 + ---------
82.15 + M O N E Y
82.16 +
82.17 + In this puzzle the same letters mean the same digits. The question
82.18 + is: how to replace all the letters with the respective digits that
82.19 + makes the calculation correct?
82.20 +
82.21 + The solution to this puzzle is:
82.22 + O = 0, M = 1, Y = 2, E = 5, N = 6, D = 7, R = 8, and S = 9.
82.23 +
82.24 + References:
82.25 + H. E. Dudeney, in Strand Magazine vol. 68 (July 1924), pp. 97, 214.
82.26 +
82.27 + (From Wikipedia, the free encyclopedia.) */
82.28 +
82.29 +set LETTERS := { 'D', 'E', 'M', 'N', 'O', 'R', 'S', 'Y' };
82.30 +/* set of letters */
82.31 +
82.32 +set DIGITS := 0..9;
82.33 +/* set of digits */
82.34 +
82.35 +var x{i in LETTERS, d in DIGITS}, binary;
82.36 +/* x[i,d] = 1 means that letter i is digit d */
82.37 +
82.38 +s.t. one{i in LETTERS}: sum{d in DIGITS} x[i,d] = 1;
82.39 +/* each letter must correspond exactly to one digit */
82.40 +
82.41 +s.t. alldiff{d in DIGITS}: sum{i in LETTERS} x[i,d] <= 1;
82.42 +/* different letters must correspond to different digits; note that
82.43 + some digits may not correspond to any letters at all */
82.44 +
82.45 +var dig{i in LETTERS};
82.46 +/* dig[i] is a digit corresponding to letter i */
82.47 +
82.48 +s.t. map{i in LETTERS}: dig[i] = sum{d in DIGITS} d * x[i,d];
82.49 +
82.50 +var carry{1..3}, binary;
82.51 +/* carry bits */
82.52 +
82.53 +s.t. sum1: dig['D'] + dig['E'] = dig['Y'] + 10 * carry[1];
82.54 +s.t. sum2: dig['N'] + dig['R'] + carry[1] = dig['E'] + 10 * carry[2];
82.55 +s.t. sum3: dig['E'] + dig['O'] + carry[2] = dig['N'] + 10 * carry[3];
82.56 +s.t. sum4: dig['S'] + dig['M'] + carry[3] = dig['O'] + 10 * dig['M'];
82.57 +s.t. note: dig['M'] >= 1; /* M must not be 0 */
82.58 +
82.59 +solve;
82.60 +/* solve the puzzle */
82.61 +
82.62 +display dig;
82.63 +/* and display its solution */
82.64 +
82.65 +end;
83.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
83.2 +++ b/examples/mplsamp1.c Mon Dec 06 13:09:21 2010 +0100
83.3 @@ -0,0 +1,32 @@
83.4 +/* mplsamp1.c */
83.5 +
83.6 +#include <stdio.h>
83.7 +#include <stdlib.h>
83.8 +#include <glpk.h>
83.9 +
83.10 +int main(void)
83.11 +{ glp_prob *lp;
83.12 + glp_tran *tran;
83.13 + int ret;
83.14 + lp = glp_create_prob();
83.15 + tran = glp_mpl_alloc_wksp();
83.16 + ret = glp_mpl_read_model(tran, "egypt.mod", 0);
83.17 + if (ret != 0)
83.18 + { fprintf(stderr, "Error on translating model\n");
83.19 + goto skip;
83.20 + }
83.21 + ret = glp_mpl_generate(tran, NULL);
83.22 + if (ret != 0)
83.23 + { fprintf(stderr, "Error on generating model\n");
83.24 + goto skip;
83.25 + }
83.26 + glp_mpl_build_prob(tran, lp);
83.27 + ret = glp_write_mps(lp, GLP_MPS_FILE, NULL, "egypt.mps");
83.28 + if (ret != 0)
83.29 + fprintf(stderr, "Error on writing MPS file\n");
83.30 +skip: glp_mpl_free_wksp(tran);
83.31 + glp_delete_prob(lp);
83.32 + return 0;
83.33 +}
83.34 +
83.35 +/* eof */
84.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
84.2 +++ b/examples/mplsamp2.c Mon Dec 06 13:09:21 2010 +0100
84.3 @@ -0,0 +1,39 @@
84.4 +/* mplsamp2.c */
84.5 +
84.6 +#include <stdio.h>
84.7 +#include <stdlib.h>
84.8 +#include <glpk.h>
84.9 +
84.10 +int main(void)
84.11 +{ glp_prob *mip;
84.12 + glp_tran *tran;
84.13 + int ret;
84.14 + mip = glp_create_prob();
84.15 + tran = glp_mpl_alloc_wksp();
84.16 + ret = glp_mpl_read_model(tran, "sudoku.mod", 1);
84.17 + if (ret != 0)
84.18 + { fprintf(stderr, "Error on translating model\n");
84.19 + goto skip;
84.20 + }
84.21 + ret = glp_mpl_read_data(tran, "sudoku.dat");
84.22 + if (ret != 0)
84.23 + { fprintf(stderr, "Error on translating data\n");
84.24 + goto skip;
84.25 + }
84.26 + ret = glp_mpl_generate(tran, NULL);
84.27 + if (ret != 0)
84.28 + { fprintf(stderr, "Error on generating model\n");
84.29 + goto skip;
84.30 + }
84.31 + glp_mpl_build_prob(tran, mip);
84.32 + glp_simplex(mip, NULL);
84.33 + glp_intopt(mip, NULL);
84.34 + ret = glp_mpl_postsolve(tran, mip, GLP_MIP);
84.35 + if (ret != 0)
84.36 + fprintf(stderr, "Error on postsolving model\n");
84.37 +skip: glp_mpl_free_wksp(tran);
84.38 + glp_delete_prob(mip);
84.39 + return 0;
84.40 +}
84.41 +
84.42 +/* eof */
85.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
85.2 +++ b/examples/murtagh.mps Mon Dec 06 13:09:21 2010 +0100
85.3 @@ -0,0 +1,600 @@
85.4 +*NAME: OIL
85.5 +*ROWS: 74
85.6 +*COLUMNS: 81
85.7 +*NONZERO: 504
85.8 +*OPT SOLN: 126.057
85.9 +*SOURCE: Bruce Murtagh, "Advanced Linear Programming"
85.10 +*APPLICATION: oil refinery model
85.11 +*COMMENTS: problem is maximization
85.12 +*
85.13 +NAME OIL REFINERY EXAMPLE
85.14 +ROWS
85.15 + N PROFIT
85.16 + L MVOLBOL
85.17 + L MVOLCOL
85.18 + E MVOLLNC
85.19 + E MVOLLNB
85.20 + E MVOLSRK
85.21 + E MVOLSRD
85.22 + E MVOLVBB
85.23 + E MVOLVBC
85.24 + E MVOLRCR
85.25 + E MVOLHVO
85.26 + E UBALKWH
85.27 + E UBALH2O
85.28 + E UBALSTM
85.29 + E UBALFUL
85.30 + E MVOLB95
85.31 + E MVOLB90
85.32 + E MVOLLHG
85.33 + E MVOLC3S
85.34 + E MVOLNC4
85.35 + E MVOLLSR
85.36 + E MVOLHSR
85.37 + E MVOLIC4
85.38 + L VCAPSGP
85.39 + E MVOLRFG
85.40 + E MSCFHYL
85.41 + E MVOLR90
85.42 + E MVOLR95
85.43 + E MVOLF90
85.44 + E MVOLF95
85.45 + L VCAPRFG
85.46 + E MVOLLCO
85.47 + E MVOLHHG
85.48 + E MVOLHCD
85.49 + L VCAPHVO
85.50 + L VCAPHOL
85.51 + E MVOLC3U
85.52 + E MVOLC4U
85.53 + E MVOLFCG
85.54 + E MVOLSLR
85.55 + L VCAPCCU
85.56 + E MVOLLA3
85.57 + E MVOLLA4
85.58 + L VCAPALK
85.59 + L XLPRPRE
85.60 + L XHPRPRE
85.61 + L XTELPRE
85.62 + L XRVPPRE
85.63 + L X200PRE
85.64 + L X230PRE
85.65 + E EVOLPRE
85.66 + L XPSCPRE
85.67 + L XRSCREG
85.68 + L XLPRINT
85.69 + L XHPRINT
85.70 + L XTELINT
85.71 + L XRVPINT
85.72 + L X200INT
85.73 + L X230INT
85.74 + E EVOLINT
85.75 + L XLPRREG
85.76 + L XHPRREG
85.77 + L XTELREG
85.78 + L XRVPREG
85.79 + L X200REG
85.80 + L X230REG
85.81 + E EVOLREG
85.82 + E EVOLLPG
85.83 + E EVOLJP4
85.84 + L XRVXJP4
85.85 + L XRVNJP4
85.86 + E EVOLDSL
85.87 + E EVOLRSD
85.88 + L XVISRSD
85.89 +COLUMNS
85.90 + VCRDBOL MVOLBOL 1.0
85.91 + VCRDBOL MVOLLNB -.537
85.92 + VCRDBOL MVOLSRK -.131
85.93 + VCRDBOL MVOLSRD -.1155
85.94 + VCRDBOL MVOLVBB -.037
85.95 + VCRDBOL MVOLRCR -.0365
85.96 + VCRDBOL MVOLHVO -.143
85.97 + VCRDBOL UBALKWH .302
85.98 + VCRDBOL UBALH2O .150
85.99 + VCRDBOL UBALSTM .003
85.100 + VCRDBOL UBALFUL .0587
85.101 + VCRDBOL PROFIT -12.8
85.102 + VCRDCOL MVOLCOL 1.
85.103 + VCRDCOL MVOLLNC -.2931
85.104 + VCRDCOL MVOLSRK -.1170
85.105 + VCRDCOL MVOLSRD -.0649
85.106 + VCRDCOL MVOLVBC -.18
85.107 + VCRDCOL MVOLRCR -.1233
85.108 + VCRDCOL MVOLHVO -.2217
85.109 + VCRDCOL UBALKWH .384
85.110 + VCRDCOL UBALH2O .185
85.111 + VCRDCOL UBALSTM .003
85.112 + VCRDCOL UBALFUL .1053
85.113 + VCRDCOL PROFIT -11.48
85.114 + VSGPLNC MVOLLNC 1.
85.115 + VSGPLNC MVOLC3S -.0112
85.116 + VSGPLNC MVOLNC4 -.0378
85.117 + VSGPLNC MVOLLSR -.1502
85.118 + VSGPLNC MVOLHSR -.7953
85.119 + VSGPLNC MVOLIC4 -.0099
85.120 + VSGPLNC UBALKWH .721
85.121 + VSGPLNC UBALH2O .185
85.122 + VSGPLNC UBALSTM .013
85.123 + VSGPLNC UBALFUL .0488
85.124 + VSGPLNC VCAPSGP 1.
85.125 + VSGPLNB MVOLLNB 1.
85.126 + VSGPLNB MVOLC3S -.0277
85.127 + VSGPLNB MVOLNC4 -.0563
85.128 + VSGPLNB MVOLLSR -.199
85.129 + VSGPLNB MVOLHSR -.6873
85.130 + VSGPLNB MVOLIC4 -.017
85.131 + VSGPLNB UBALKWH .495
85.132 + VSGPLNB UBALH2O .209
85.133 + VSGPLNB UBALSTM .013
85.134 + VSGPLNB UBALFUL .0506
85.135 + VSGPLNB VCAPSGP 1.
85.136 + VSGPLHG MVOLLHG 1.0
85.137 + VSGPLHG MVOLC3S -.175
85.138 + VSGPLHG MVOLNC4 -.27
85.139 + VSGPLHG MVOLLSR -.028
85.140 + VSGPLHG MVOLIC4 -.455
85.141 + VSGPLHG UBALKWH .495
85.142 + VSGPLHG UBALH2O .209
85.143 + VSGPLHG UBALSTM .013
85.144 + VSGPLHG UBALFUL .0448
85.145 + VSGPB95 MVOLB95 1.
85.146 + VSGPB95 MVOLC3S -.2836
85.147 + VSGPB95 MVOLNC4 -.3285
85.148 + VSGPB95 MVOLLSR -.0241
85.149 + VSGPB95 MVOLIC4 -.2502
85.150 + VSGPB95 UBALKWH .495
85.151 + VSGPB95 UBALH2O .209
85.152 + VSGPB95 UBALSTM .013
85.153 + VSGPB95 UBALFUL .0506
85.154 + VSGPB90 MVOLB90 1.
85.155 + VSGPB90 MVOLC3S -.271
85.156 + VSGPB90 MVOLNC4 -.3289
85.157 + VSGPB90 MVOLLSR -.0255
85.158 + VSGPB90 MVOLIC4 -.2656
85.159 + VSGPB90 UBALKWH .495
85.160 + VSGPB90 UBALH2O .209
85.161 + VSGPB90 UBALSTM .013
85.162 + VSGPB90 UBALFUL .0506
85.163 + VH2RHSR MVOLHSR 1.
85.164 + VH2RHSR MVOLRFG -1.
85.165 + VH2RHSR MSCFHYL .0327
85.166 + VH2RHSR UBALKWH .793
85.167 + VH2RHSR UBALH2O .045
85.168 + VH2RHSR UBALFUL .094
85.169 + VH2RHSR PROFIT -.0176
85.170 + VRFFRF1 MVOLRFG 1.0
85.171 + VRFFRF1 MVOLR90 -1.0
85.172 + VRFFRF2 MVOLRFG 1.0
85.173 + VRFFRF2 MVOLR95 -1.0
85.174 + VRFFHH1 MVOLR90 -1.0
85.175 + VRFFHH1 MVOLHHG 1.0
85.176 + VRFFHH2 MVOLR95 -1.0
85.177 + VRFFHH2 MVOLHHG 1.0
85.178 + VRFGR90 MVOLR90 1.0
85.179 + VRFGR90 MVOLB90 -.0404
85.180 + VRFGR90 MVOLF90 -0.8564
85.181 + VRFGR90 MSCFHYL -0.8239
85.182 + VRFGR90 UBALKWH .792
85.183 + VRFGR90 UBALH2O .297
85.184 + VRFGR90 UBALSTM 0.0063
85.185 + VRFGR90 UBALFUL -0.156
85.186 + VRFGR90 VCAPRFG 1.0
85.187 + VRFGR90 PROFIT -0.1512
85.188 + VRFGR95 MVOLR95 1.0
85.189 + VRFGR95 MVOLB95 -0.0588
85.190 + VRFGR95 MVOLF95 -0.8145
85.191 + VRFGR95 MSCFHYL -.7689
85.192 + VRFGR95 UBALKWH 1.03
85.193 + VRFGR95 UBALH2O .387
85.194 + VRFGR95 UBALSTM 0.008
85.195 + VRFGR95 UBALFUL -.2112
85.196 + VRFGR95 VCAPRFG 1.3
85.197 + VRFGR95 PROFIT -0.304
85.198 + VHOLLCO MVOLLCO 1.0
85.199 + VHOLLCO MVOLHHG -.6627
85.200 + VHOLLCO MVOLLHG -0.2414
85.201 + VHOLLCO MVOLHCD -.2930
85.202 + VHOLLCO MSCFHYL 2.3
85.203 + VHOLLCO UBALFUL -.2054
85.204 + VHOLLCO UBALH2O 0.826
85.205 + VHOLLCO UBALKWH 14.61
85.206 + VHOLLCO VCAPHOL 1.0
85.207 + VHOLLCO PROFIT -0.2112
85.208 + VHOLSRD MVOLSRD 1.0
85.209 + VHOLSRD MVOLHHG -.6627
85.210 + VHOLSRD MVOLLHG -0.2414
85.211 + VHOLSRD MVOLHCD -.2930
85.212 + VHOLSRD MSCFHYL 2.3
85.213 + VHOLSRD UBALFUL -.2054
85.214 + VHOLSRD UBALH2O 0.826
85.215 + VHOLSRD UBALKWH 14.61
85.216 + VHOLSRD VCAPHOL 1.0
85.217 + VHOLSRD PROFIT -0.2112
85.218 + VHOLRCR MVOLRCR 1.0
85.219 + VHOLRCR MVOLHHG -.5875
85.220 + VHOLRCR MVOLLHG -0.3321
85.221 + VHOLRCR MVOLHCD -.3620
85.222 + VHOLRCR MSCFHYL 2.3
85.223 + VHOLRCR UBALFUL -.2054
85.224 + VHOLRCR UBALH2O 0.826
85.225 + VHOLRCR UBALKWH 14.61
85.226 + VHOLRCR VCAPHOL 1.0
85.227 + VHOLRCR PROFIT -0.2112
85.228 + VHOLHVO MVOLHVO 1.0
85.229 + VHOLHVO MVOLHHG -.5875
85.230 + VHOLHVO MVOLLHG -0.3321
85.231 + VHOLHVO MVOLHCD -.3620
85.232 + VHOLHVO MSCFHYL 2.3
85.233 + VHOLHVO UBALFUL -.2054
85.234 + VHOLHVO UBALH2O 0.826
85.235 + VHOLHVO UBALKWH 14.61
85.236 + VHOLHVO VCAPHVO 1.0
85.237 + VHOLHVO VCAPHOL 1.0
85.238 + VHOLHVO PROFIT -0.2112
85.239 + VCCUSRK MVOLSRK 1.0
85.240 + VCCUSRK MVOLNC4 -0.0184
85.241 + VCCUSRK MVOLC3S -0.0303
85.242 + VCCUSRK MVOLIC4 -0.0564
85.243 + VCCUSRK MVOLC3U -0.0655
85.244 + VCCUSRK MVOLC4U -0.0780
85.245 + VCCUSRK MVOLFCG -0.4750
85.246 + VCCUSRK MVOLLCO -0.3050
85.247 + VCCUSRK UBALSTM -.0654
85.248 + VCCUSRK UBALFUL -.2703
85.249 + VCCUSRK UBALH2O .632
85.250 + VCCUSRK UBALKWH .6807
85.251 + VCCUSRK VCAPCCU 1.
85.252 + VCCUSRK PROFIT -.2112
85.253 + VCCUSRD MVOLSRD 1.
85.254 + VCCUSRD MVOLNC4 -.0184
85.255 + VCCUSRD MVOLC3S -.0303
85.256 + VCCUSRD MVOLIC4 -.0564
85.257 + VCCUSRD MVOLC3U -.0655
85.258 + VCCUSRD MVOLC4U -.0780
85.259 + VCCUSRD MVOLFCG -.4750
85.260 + VCCUSRD MVOLLCO -.3050
85.261 + VCCUSRD UBALSTM -.0654
85.262 + VCCUSRD UBALFUL -.2703
85.263 + VCCUSRD UBALH2O 0.632
85.264 + VCCUSRD UBALKWH .6807
85.265 + VCCUSRD VCAPCCU 1.
85.266 + VCCUSRD PROFIT -.2112
85.267 + VCCURCR MVOLRCR 1.0
85.268 + VCCURCR MVOLNC4 -.0185
85.269 + VCCURCR MVOLC3S -.0328
85.270 + VCCURCR MVOLIC4 -.0568
85.271 + VCCURCR MVOLC3U -.0658
85.272 + VCCURCR MVOLC4U -.0806
85.273 + VCCURCR MVOLFCG -.4934
85.274 + VCCURCR MVOLLCO -.2922
85.275 + VCCURCR MVOLSLR -.0096
85.276 + VCCURCR UBALSTM -.0654
85.277 + VCCURCR UBALFUL -.2703
85.278 + VCCURCR UBALH2O 0.632
85.279 + VCCURCR UBALKWH .6807
85.280 + VCCURCR VCAPCCU 1.
85.281 + VCCURCR PROFIT -.2112
85.282 + VCCUHVO MVOLHVO 1.0
85.283 + VCCUHVO MVOLNC4 -.0185
85.284 + VCCUHVO MVOLC3S -.0328
85.285 + VCCUHVO MVOLIC4 -.0568
85.286 + VCCUHVO MVOLC3U -.0658
85.287 + VCCUHVO MVOLC4U -.0806
85.288 + VCCUHVO MVOLFCG -.4934
85.289 + VCCUHVO MVOLLCO -.2922
85.290 + VCCUHVO MVOLSLR -.0096
85.291 + VCCUHVO UBALSTM -.0654
85.292 + VCCUHVO UBALFUL -.2703
85.293 + VCCUHVO UBALH2O 0.632
85.294 + VCCUHVO UBALKWH .6807
85.295 + VCCUHVO VCAPHVO 1.
85.296 + VCCUHVO VCAPCCU 1.
85.297 + VCCUHVO PROFIT -.2112
85.298 + VALKLA3 MVOLIC4 .7600
85.299 + VALKLA3 MVOLC3U .5714
85.300 + VALKLA3 MVOLLA3 -1.0
85.301 + VALKLA3 UBALSTM .1869
85.302 + VALKLA3 UBALFUL .2796
85.303 + VALKLA3 UBALH2O 2.241
85.304 + VALKLA3 UBALKWH 2.766
85.305 + VALKLA3 VCAPALK 1.0
85.306 + VALKLA3 PROFIT -.512
85.307 + VALKLA4 MVOLIC4 .6571
85.308 + VALKLA4 MVOLC4U .5714
85.309 + VALKLA4 MVOLC3S -.0571
85.310 + VALKLA4 MVOLNC4 -.0114
85.311 + VALKLA4 MVOLLA4 -1.0
85.312 + VALKLA4 UBALSTM .1724
85.313 + VALKLA4 UBALFUL .2579
85.314 + VALKLA4 UBALH2O 2.067
85.315 + VALKLA4 UBALKWH 2.552
85.316 + VALKLA4 VCAPALK 1.0
85.317 + VALKLA4 PROFIT -.472
85.318 + VALKIC4 MVOLIC4 1.0
85.319 + VALKIC4 MVOLNC4 -1.0
85.320 + VALKC3U MVOLC3U 1.0
85.321 + VALKC3U MVOLC3S -1.0
85.322 + VALKC4U MVOLC4U 1.0
85.323 + VALKC4U MVOLNC4 -1.0
85.324 + UTILC3S MVOLC3S 1.
85.325 + UTILC3S UBALFUL -3.814
85.326 + UTILNC4 MVOLNC4 1.
85.327 + UTILNC4 UBALFUL -4.316
85.328 + UTILIC4 MVOLIC4 1.
85.329 + UTILIC4 UBALFUL -4.153
85.330 + UTILC3U MVOLC3U 1.
85.331 + UTILC3U UBALFUL -3.808
85.332 + UTILC4U MVOLC4U 1.
85.333 + UTILC4U UBALFUL -4.44
85.334 + UTILHYL MSCFHYL 1.
85.335 + UTILHYL UBALFUL -.305
85.336 + UTILSTM UBALSTM -1.
85.337 + UTILSTM UBALFUL 1.42
85.338 + UTILSTM PROFIT -.16
85.339 + PURCPC4 MVOLIC4 -.5
85.340 + PURCPC4 MVOLNC4 -.5
85.341 + PURCPC4 PROFIT -12.
85.342 + PURCH2O UBALH2O -1.
85.343 + PURCH2O PROFIT -.0528
85.344 + PURCKWH UBALKWH -1.
85.345 + PURCKWH PROFIT -.04
85.346 + PURCFUL UBALFUL -1.
85.347 + PURCFUL PROFIT -1.6
85.348 + PURCFLR UBALFUL 1.
85.349 + BLPGC3S MVOLC3S 1.0
85.350 + BLPGC3S EVOLLPG -1.0
85.351 + BLPGNC4 MVOLNC4 1.0
85.352 + BLPGNC4 EVOLLPG -1.0
85.353 + SELLLPG EVOLLPG 1.0
85.354 + SELLLPG PROFIT 11.0
85.355 + BUP4LSR MVOLLSR 1.0
85.356 + BUP4LSR EVOLJP4 -1.0
85.357 + BUP4LSR XRVXJP4 14.0
85.358 + BUP4LSR XRVNJP4 -14.0
85.359 + BUP4HSR MVOLHSR 1.0
85.360 + BUP4HSR EVOLJP4 -1.0
85.361 + BUP4HSR XRVXJP4 0.8
85.362 + BUP4HSR XRVNJP4 -0.8
85.363 + SELLJP4 EVOLJP4 1.0
85.364 + SELLJP4 XRVXJP4 -3.0
85.365 + SELLJP4 XRVNJP4 2.0
85.366 + SELLJP4 PROFIT 16.8
85.367 + BDSLSRK MVOLSRK 1.0
85.368 + BDSLSRK EVOLDSL -1.0
85.369 + BDSLSRD MVOLSRD 1.0
85.370 + BDSLSRD EVOLDSL -1.0
85.371 + SELLDSL EVOLDSL 1.0
85.372 + SELLDSL PROFIT 14.4
85.373 + BPRELSR MVOLLSR 1.
85.374 + BPRELSR XLPRPRE -7.95
85.375 + BPRELSR XHPRPRE -8.70
85.376 + BPRELSR XTELPRE -3.00
85.377 + BPRELSR XRVPPRE 14.00
85.378 + BPRELSR X200PRE 1.
85.379 + BPRELSR X230PRE -1.
85.380 + BPRELSR EVOLPRE -1.
85.381 + BPREHCD MVOLHCD 1.0
85.382 + BPREHCD XLPRPRE -8.84
85.383 + BPREHCD XHPRPRE -9.45
85.384 + BPREHCD XTELPRE -3.00
85.385 + BPREHCD XRVPPRE 12.00
85.386 + BPREHCD X200PRE 1.
85.387 + BPREHCD X230PRE -1.
85.388 + BPREHCD EVOLPRE -1.
85.389 + BPREF95 MVOLF95 1.0
85.390 + BPREF95 XLPRPRE -9.43
85.391 + BPREF95 XHPRPRE -9.57
85.392 + BPREF95 XTELPRE -3.
85.393 + BPREF95 XRVPPRE 3.5
85.394 + BPREF95 X200PRE .233
85.395 + BPREF95 X230PRE -.358
85.396 + BPREF95 EVOLPRE -1.
85.397 + BPREF90 MVOLF90 1.0
85.398 + BPREF90 XLPRPRE -9.03
85.399 + BPREF90 XHPRPRE -9.32
85.400 + BPREF90 XTELPRE -3.0
85.401 + BPREF90 XRVPPRE 3.5
85.402 + BPREF90 X200PRE .205
85.403 + BPREF90 X230PRE -.333
85.404 + BPREF90 EVOLPRE -1.
85.405 + BPREFCG MVOLFCG 1.0
85.406 + BPREFCG XLPRPRE -9.23
85.407 + BPREFCG XHPRPRE -9.22
85.408 + BPREFCG XTELPRE -3.
85.409 + BPREFCG XRVPPRE 6.
85.410 + BPREFCG X200PRE .381
85.411 + BPREFCG X230PRE -.509
85.412 + BPREFCG EVOLPRE -1.
85.413 + BPRELA3 MVOLLA3 1.0
85.414 + BPRELA3 XLPRPRE -9.4
85.415 + BPRELA3 XHPRPRE -9.85
85.416 + BPRELA3 XTELPRE -3.0
85.417 + BPRELA3 XRVPPRE 2.5
85.418 + BPRELA3 X200PRE 0.39
85.419 + BPRELA3 X230PRE -0.77
85.420 + BPRELA3 EVOLPRE -1.0
85.421 + BPRELA4 MVOLLA4 1.0
85.422 + BPRELA4 XLPRPRE -9.74
85.423 + BPRELA4 XHPRPRE -10.1
85.424 + BPRELA4 XTELPRE -3.0
85.425 + BPRELA4 XRVPPRE 3.3
85.426 + BPRELA4 X200PRE 0.233
85.427 + BPRELA4 X230PRE -0.58
85.428 + BPRELA4 EVOLPRE -1.0
85.429 + BPRENC4 MVOLNC4 1.0
85.430 + BPRENC4 XLPRPRE -9.74
85.431 + BPRENC4 XHPRPRE -9.9
85.432 + BPRENC4 XTELPRE -3.0
85.433 + BPRENC4 XRVPPRE 66.0
85.434 + BPRENC4 X200PRE 1.0
85.435 + BPRENC4 X230PRE -1.0
85.436 + BPRENC4 EVOLPRE -1.0
85.437 + BPRETEL XLPRPRE -0.493
85.438 + BPRETEL XHPRPRE -0.165
85.439 + BPRETEL XTELPRE 1.0
85.440 + BPRETEL PROFIT -0.3696
85.441 + SELLPRE XLPRPRE 10.03
85.442 + SELLPRE XHPRPRE 10.03
85.443 + SELLPRE XRVPPRE -9.5
85.444 + SELLPRE X200PRE -0.5
85.445 + SELLPRE X230PRE 0.5
85.446 + SELLPRE XPSCPRE 0.64
85.447 + SELLPRE XRSCREG 0.35
85.448 + SELLPRE EVOLPRE 1.0
85.449 + SELLPRE PROFIT 21.44
85.450 + BINTLSR MVOLLSR 1.0
85.451 + BINTLSR XLPRINT -7.98
85.452 + BINTLSR XHPRINT -8.58
85.453 + BINTLSR XTELINT -3.0
85.454 + BINTLSR XRVPINT 14.0
85.455 + BINTLSR X200INT 1.0
85.456 + BINTLSR X230INT -1.0
85.457 + BINTLSR EVOLINT -1.0
85.458 + BINTHCD MVOLHCD 1.
85.459 + BINTHCD XLPRINT -8.87
85.460 + BINTHCD XHPRINT -9.33
85.461 + BINTHCD XTELINT -3.0
85.462 + BINTHCD XRVPINT 12.0
85.463 + BINTHCD X200INT 1.0
85.464 + BINTHCD X230INT -1.
85.465 + BINTHCD EVOLINT -1.0
85.466 + BINTF95 MVOLF95 1.
85.467 + BINTF95 XLPRINT -9.46
85.468 + BINTF95 XHPRINT -9.45
85.469 + BINTF95 XTELINT -3.0
85.470 + BINTF95 XRVPINT 3.5
85.471 + BINTF95 X200INT .233
85.472 + BINTF95 X230INT -.358
85.473 + BINTF95 EVOLINT -1.0
85.474 + BINTF90 MVOLF90 1.
85.475 + BINTF90 XLPRINT -9.06
85.476 + BINTF90 XHPRINT -9.20
85.477 + BINTF90 XTELINT -3.0
85.478 + BINTF90 XRVPINT 3.5
85.479 + BINTF90 X200INT .205
85.480 + BINTF90 X230INT -.333
85.481 + BINTF90 EVOLINT -1.0
85.482 + BINTFCG MVOLFCG 1.
85.483 + BINTFCG XLPRINT -9.26
85.484 + BINTFCG XHPRINT -9.13
85.485 + BINTFCG XTELINT -3.0
85.486 + BINTFCG XRVPINT 6.
85.487 + BINTFCG X200INT .318
85.488 + BINTFCG X230INT -.509
85.489 + BINTFCG EVOLINT -1.0
85.490 + BINTNC4 MVOLNC4 1.
85.491 + BINTNC4 XLPRINT -9.77
85.492 + BINTNC4 XHPRINT -9.78
85.493 + BINTNC4 XTELINT -3.0
85.494 + BINTNC4 XRVPINT 66.
85.495 + BINTNC4 X200INT 1.0
85.496 + BINTNC4 X230INT -1.
85.497 + BINTNC4 EVOLINT -1.0
85.498 + BINTTEL XLPRINT -.435
85.499 + BINTTEL XHPRINT -.208
85.500 + BINTTEL XTELINT 1.
85.501 + BINTTEL PROFIT -.3696
85.502 + SELLINT XLPRINT 9.65
85.503 + SELLINT XHPRINT 9.65
85.504 + SELLINT XRVPINT -9.5
85.505 + SELLINT X200INT -0.5
85.506 + SELLINT X230INT 0.5
85.507 + SELLINT XPSCPRE -.36
85.508 + SELLINT XRSCREG 0.35
85.509 + SELLINT EVOLINT 1.0
85.510 + SELLINT PROFIT 20.32
85.511 + BREGLSR MVOLLSR 1.0
85.512 + BREGLSR XLPRREG -7.99
85.513 + BREGLSR XHPRREG -8.59
85.514 + BREGLSR XTELREG -3.0
85.515 + BREGLSR XRVPREG 14.0
85.516 + BREGLSR X200REG 1.0
85.517 + BREGLSR X230REG -1.0
85.518 + BREGLSR EVOLREG -1.0
85.519 + BREGHCD MVOLHCD 1.0
85.520 + BREGHCD XLPRREG -8.88
85.521 + BREGHCD XHPRREG -9.34
85.522 + BREGHCD XTELREG -3.0
85.523 + BREGHCD XRVPREG 12.0
85.524 + BREGHCD X200REG 1.0
85.525 + BREGHCD X230REG -1.0
85.526 + BREGHCD EVOLREG -1.0
85.527 + BREGF95 MVOLF95 1.0
85.528 + BREGF95 XLPRREG -9.47
85.529 + BREGF95 XHPRREG -9.46
85.530 + BREGF95 XTELREG -3.0
85.531 + BREGF95 XRVPREG 3.5
85.532 + BREGF95 X200REG .233
85.533 + BREGF95 X230REG -0.358
85.534 + BREGF95 EVOLREG -1.0
85.535 + BREGF90 MVOLF90 1.0
85.536 + BREGF90 XLPRREG -9.07
85.537 + BREGF90 XHPRREG -9.21
85.538 + BREGF90 XTELREG -3.0
85.539 + BREGF90 XRVPREG 3.5
85.540 + BREGF90 X200REG .205
85.541 + BREGF90 X230REG -0.333
85.542 + BREGF90 EVOLREG -1.0
85.543 + BREGFCG MVOLFCG 1.0
85.544 + BREGFCG XLPRREG -9.27
85.545 + BREGFCG XHPRREG -9.14
85.546 + BREGFCG XTELREG -3.0
85.547 + BREGFCG XRVPREG 6.0
85.548 + BREGFCG X200REG 0.318
85.549 + BREGFCG X230REG -0.509
85.550 + BREGFCG EVOLREG -1.0
85.551 + BREGNC4 MVOLNC4 1.0
85.552 + BREGNC4 XLPRREG -9.78
85.553 + BREGNC4 XHPRREG -9.79
85.554 + BREGNC4 XTELREG -3.0
85.555 + BREGNC4 XRVPREG 66.0
85.556 + BREGNC4 X200REG 1.0
85.557 + BREGNC4 X230REG -1.0
85.558 + BREGNC4 EVOLREG -1.0
85.559 + BREGTEL XLPRREG -0.426
85.560 + BREGTEL XHPRREG -.204
85.561 + BREGTEL XTELREG 1.0
85.562 + BREGTEL PROFIT -0.3696
85.563 + SELLREG XLPRREG 9.05
85.564 + SELLREG XHPRREG 9.05
85.565 + SELLREG XRVPREG -9.5
85.566 + SELLREG X200REG -0.5
85.567 + SELLREG X230REG 0.5
85.568 + SELLREG XPSCPRE -0.36
85.569 + SELLREG XRSCREG -0.65
85.570 + SELLREG EVOLREG 1.0
85.571 + SELLREG PROFIT 18.04
85.572 + BRSDVBB MVOLVBB 1.0
85.573 + BRSDVBB EVOLRSD -1.0
85.574 + BRSDVBB XVISRSD 10.1
85.575 + BRSDVBC MVOLVBC 1.0
85.576 + BRSDVBC EVOLRSD -1.0
85.577 + BRSDVBC XVISRSD 12.63
85.578 + BRSDRCR MVOLRCR 1.0
85.579 + BRSDRCR EVOLRSD -1.0
85.580 + BRSDRCR XVISRSD 6.9
85.581 + BRSDHVO MVOLHVO 1.0
85.582 + BRSDHVO EVOLRSD -1.0
85.583 + BRSDHVO XVISRSD 8.05
85.584 + BRSDHVO VCAPHVO 1.0
85.585 + BRSDSLR MVOLSLR 1.0
85.586 + BRSDSLR EVOLRSD -1.0
85.587 + BRSDSLR XVISRSD 8.05
85.588 + BRSDLCO MVOLLCO 1.0
85.589 + BRSDLCO EVOLRSD -1.0
85.590 + BRSDLCO XVISRSD 4.4
85.591 + SELLRSD EVOLRSD 1.0
85.592 + SELLRSD XVISRSD -10.1
85.593 + SELLRSD PROFIT 8.00
85.594 +RHS
85.595 + LIMITMAX MVOLBOL 26.316
85.596 + LIMITMAX MVOLCOL 21.052
85.597 + LIMITMAX VCAPSGP 23.25
85.598 + LIMITMAX VCAPHVO 5.25
85.599 + LIMITMAX VCAPRFG 13.455
85.600 + LIMITMAX VCAPHOL 3.87
85.601 + LIMITMAX VCAPCCU 7.26
85.602 + LIMITMAX VCAPALK 10.
85.603 +ENDATA
86.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
86.2 +++ b/examples/mvcp.mod Mon Dec 06 13:09:21 2010 +0100
86.3 @@ -0,0 +1,43 @@
86.4 +/* MVCP, Minimum Vertex Cover Problem */
86.5 +
86.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
86.7 +
86.8 +/* The Minimum Vertex Cover Problem in a network G = (V, E), where V
86.9 + is a set of nodes, E is a set of arcs, is to find a subset V' within
86.10 + V such that each edge (i,j) in E has at least one its endpoint in V'
86.11 + and which minimizes the sum of node weights w(i) over V'.
86.12 +
86.13 + Reference:
86.14 + Garey, M.R., and Johnson, D.S. (1979), Computers and Intractability:
86.15 + A guide to the theory of NP-completeness [Graph Theory, Covering and
86.16 + Partitioning, Minimum Vertex Cover, GT1]. */
86.17 +
86.18 +set E, dimen 2;
86.19 +/* set of edges */
86.20 +
86.21 +set V := (setof{(i,j) in E} i) union (setof{(i,j) in E} j);
86.22 +/* set of nodes */
86.23 +
86.24 +param w{i in V}, >= 0, default 1;
86.25 +/* w[i] is weight of vertex i */
86.26 +
86.27 +var x{i in V}, binary;
86.28 +/* x[i] = 1 means that node i is included into V' */
86.29 +
86.30 +s.t. cov{(i,j) in E}: x[i] + x[j] >= 1;
86.31 +/* each edge (i,j) must have node i or j (or both) in V' */
86.32 +
86.33 +minimize z: sum{i in V} w[i] * x[i];
86.34 +/* we need to minimize the sum of node weights over V' */
86.35 +
86.36 +data;
86.37 +
86.38 +/* These data correspond to an example from [Papadimitriou]. */
86.39 +
86.40 +/* Optimal solution is 6 (greedy heuristic gives 13) */
86.41 +
86.42 +set E := a1 b1, b1 c1, a1 b2, b2 c2, a2 b3, b3 c3, a2 b4, b4 c4, a3 b5,
86.43 + b5 c5, a3 b6, b6 c6, a4 b1, a4 b2, a4 b3, a5 b4, a5 b5, a5 b6,
86.44 + a6 b1, a6 b2, a6 b3, a6 b4, a7 b2, a7 b3, a7 b4, a7 b5, a7 b6;
86.45 +
86.46 +end;
87.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
87.2 +++ b/examples/netgen.c Mon Dec 06 13:09:21 2010 +0100
87.3 @@ -0,0 +1,141 @@
87.4 +/* netgen.c */
87.5 +
87.6 +/* This main program generates 50 original NETGEN instances of the
87.7 + minimum cost flow problem and writes them in DIMACS format to the
87.8 + current directory. */
87.9 +
87.10 +#include <stddef.h>
87.11 +#include <stdio.h>
87.12 +#include <stdlib.h>
87.13 +#include <glpk.h>
87.14 +
87.15 +static int parm[50][15] =
87.16 +{ {13502460, 101,
87.17 + 5000, 2500, 2500, 25000, 1, 100, 250000, 0, 0, 0, 100, 1, 1000,
87.18 + },{4281922, 102,
87.19 + 5000, 2500, 2500, 25000, 1, 100, 2500000, 0, 0, 0, 100, 1, 1000,
87.20 + },{44820113, 103,
87.21 + 5000, 2500, 2500, 25000, 1, 100, 6250000, 0, 0, 0, 100, 1, 1000,
87.22 + },{13450451, 104,
87.23 + 5000, 2500, 2500, 25000, -100, -1, 250000, 0, 0, 0, 100, 1, 1000,
87.24 + },{14719436, 105,
87.25 + 5000, 2500, 2500, 25000, 101, 200, 250000, 0, 0, 0, 100, 1, 1000,
87.26 + },{17365786, 106,
87.27 + 5000, 2500, 2500, 12500, 1, 100, 125000, 0, 0, 0, 100, 1, 1000,
87.28 + },{19540113, 107,
87.29 + 5000, 2500, 2500, 37500, 1, 100, 375000, 0, 0, 0, 100, 1, 1000,
87.30 + },{19560313, 108,
87.31 + 5000, 2500, 2500, 50000, 1, 100, 500000, 0, 0, 0, 100, 1, 1000,
87.32 + },{2403509, 109,
87.33 + 5000, 2500, 2500, 75000, 1, 100, 750000, 0, 0, 0, 100, 1, 1000,
87.34 + },{92480414, 110,
87.35 + 5000, 2500, 2500, 12500, 1, 100, 250000, 0, 0, 0, 100, 1, 1000,
87.36 + },{4230140, 111,
87.37 + 5000, 2500, 2500, 37500, 1, 100, 250000, 0, 0, 0, 100, 1, 1000,
87.38 + },{10032490, 112,
87.39 + 5000, 2500, 2500, 50000, 1, 100, 250000, 0, 0, 0, 100, 1, 1000,
87.40 + },{17307474, 113,
87.41 + 5000, 2500, 2500, 75000, 1, 100, 250000, 0, 0, 0, 100, 1, 1000,
87.42 + },{4925114, 114,
87.43 + 5000, 500, 4500, 25000, 1, 100, 250000, 0, 0, 0, 100, 1, 1000,
87.44 + },{19842704, 115,
87.45 + 5000, 1500, 3500, 25000, 1, 100, 250000, 0, 0, 0, 100, 1, 1000,
87.46 + },{88392060, 116,
87.47 + 5000, 2500, 2500, 25000, 1, 100, 250000, 0, 0, 0, 0, 1, 1000,
87.48 + },{12904407, 117,
87.49 + 5000, 2500, 2500, 12500, 1, 100, 125000, 0, 0, 0, 0, 1, 1000,
87.50 + },{11811811, 118,
87.51 + 5000, 2500, 2500, 37500, 1, 100, 375000, 0, 0, 0, 0, 1, 1000,
87.52 + },{90023593, 119,
87.53 + 5000, 2500, 2500, 50000, 1, 100, 500000, 0, 0, 0, 0, 1, 1000,
87.54 + },{93028922, 120,
87.55 + 5000, 2500, 2500, 75000, 1, 100, 750000, 0, 0, 0, 0, 1, 1000,
87.56 + },{72707401, 121,
87.57 + 5000, 50, 50, 25000, 1, 100, 250000, 50, 50, 0, 100, 1, 1000,
87.58 + },{93040771, 122,
87.59 + 5000, 250, 250, 25000, 1, 100, 250000, 250, 250, 0, 100, 1, 1000,
87.60 + },{70220611, 123,
87.61 + 5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
87.62 + },{52774811, 124,
87.63 + 5000, 1000, 1000, 25000, 1, 100, 250000, 1000, 1000, 0, 100, 1,
87.64 + 1000,
87.65 + },{22492311, 125,
87.66 + 5000, 1500, 1500, 25000, 1, 100, 250000, 1500, 1500, 0, 100, 1,
87.67 + 1000,
87.68 + },{35269337, 126,
87.69 + 5000, 500, 500, 12500, 1, 100, 125000, 500, 500, 0, 100, 1, 1000,
87.70 + },{30140502, 127,
87.71 + 5000, 500, 500, 37500, 1, 100, 375000, 500, 500, 0, 100, 1, 1000,
87.72 + },{49205455, 128,
87.73 + 5000, 500, 500, 50000, 1, 100, 500000, 500, 500, 0, 100, 1, 1000,
87.74 + },{42958341, 129,
87.75 + 5000, 500, 500, 75000, 1, 100, 750000, 500, 500, 0, 100, 1, 1000,
87.76 + },{25440925, 130,
87.77 + 5000, 500, 500, 12500, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
87.78 + },{75294924, 131,
87.79 + 5000, 500, 500, 37500, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
87.80 + },{4463965, 132,
87.81 + 5000, 500, 500, 50000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
87.82 + },{13390427, 133,
87.83 + 5000, 500, 500, 75000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
87.84 + },{95250971, 134,
87.85 + 1000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
87.86 + },{54830522, 135,
87.87 + 2500, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
87.88 + },{520593, 136,
87.89 + 7500, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
87.90 + },{52900925, 137,
87.91 + 10000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
87.92 + },{22603395, 138,
87.93 + 5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 50,
87.94 + },{55253099, 139,
87.95 + 5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 250,
87.96 + },{75357001, 140,
87.97 + 5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 500,
87.98 + },{10072459, 141,
87.99 + 5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 2500,
87.100 + },{55728492, 142,
87.101 + 5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 5000,
87.102 + },{593043, 143,
87.103 + 5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 0, 1, 1000,
87.104 + },{94236572, 144,
87.105 + 5000, 500, 500, 25000, 1, 10, 250000, 500, 500, 0, 100, 1, 1000,
87.106 + },{94882955, 145,
87.107 + 5000, 500, 500, 25000, 1, 1000, 250000, 500, 500, 0, 100, 1, 1000,
87.108 + },{48489922, 146,
87.109 + 5000, 500, 500, 25000, 1, 10000, 250000, 500, 500, 0, 100, 1,
87.110 + 1000,
87.111 + },{75578374, 147,
87.112 + 5000, 500, 500, 25000, -100, -1, 250000, 500, 500, 0, 100, 1,
87.113 + 1000,
87.114 + },{44821152, 148,
87.115 + 5000, 500, 500, 25000, -50, 49, 250000, 500, 500, 0, 100, 1, 1000,
87.116 + },{45224103, 149,
87.117 + 5000, 500, 500, 25000, 101, 200, 250000, 500, 500, 0, 100, 1,
87.118 + 1000,
87.119 + },{63491741, 150,
87.120 + 5000, 500, 500, 25000, 1001, 1100, 250000, 500, 500, 0, 100, 1,
87.121 + 1000,
87.122 + }
87.123 +};
87.124 +
87.125 +typedef struct { double rhs; } v_data;
87.126 +typedef struct { double cap, cost; } a_data;
87.127 +
87.128 +int main(void)
87.129 +{ glp_graph *G;
87.130 + int k;
87.131 + char fname[100+1];
87.132 + G = glp_create_graph(sizeof(v_data), sizeof(a_data));
87.133 + for (k = 1; k <= 50; k++)
87.134 + { sprintf(fname, "netgn%03d.min", parm[k-1][1]);
87.135 + glp_netgen(G, offsetof(v_data, rhs), offsetof(a_data, cap),
87.136 + offsetof(a_data, cost), &parm[k-1][-1]);
87.137 + glp_write_mincost(G, offsetof(v_data, rhs), -1,
87.138 + offsetof(a_data, cap), offsetof(a_data, cost), fname);
87.139 + }
87.140 + glp_delete_graph(G);
87.141 + return 0;
87.142 +}
87.143 +
87.144 +/* eof */
88.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
88.2 +++ b/examples/numbrix.mod Mon Dec 06 13:09:21 2010 +0100
88.3 @@ -0,0 +1,84 @@
88.4 +/* Numbrix, Number Placement Puzzle */
88.5 +
88.6 +/* Written in GNU MathProg by Robert Wood <rwood@targus.com> */
88.7 +
88.8 +/* Numbrix is a logic-based number-placement puzzle.[1]
88.9 + * The objective is to fill the grid so that each cell contains
88.10 + * digits in sequential order taking a horizontal or vertical
88.11 + * path; diagonal paths are not allowed. The puzzle setter
88.12 + * provides a grid often with the outer most cells completed.
88.13 + *
88.14 + * Completed Numbrix puzzles are usually a square of numbers
88.15 + * in order from 1 to 64 (8x8 grid) or from 1 to 81 (9x9 grid),
88.16 + * following a continuous path in sequence.
88.17 + *
88.18 + * The modern puzzle was invented by Marilyn vos Savant in 2008
88.19 + * and published by Parade Magazine under the name "Numbrix",
88.20 + * near her weekly Ask Marilyn article.
88.21 + *
88.22 + * http://en.wikipedia.org/wiki/Numbrix */
88.23 +
88.24 +set I := {1..9};
88.25 +set J := {1..9};
88.26 +set VALS := {1..81};
88.27 +
88.28 +param givens{I, J}, integer, >= 0, <= 81, default 0;
88.29 +/* the "givens" */
88.30 +
88.31 +param neighbors{i in I,j in J, i2 in I, j2 in J} , binary :=
88.32 +(if abs(i - i2) + abs(j -j2) == 1 then
88.33 + 1
88.34 + else
88.35 + 0
88.36 +);
88.37 +/* defines which spots are the boards are neighbors */
88.38 +
88.39 +var x{i in I, j in J, k in VALS}, binary;
88.40 +/* x[i,j,k] = 1 means cell [i,j] is assigned number k */
88.41 +
88.42 +s.t. fa{i in I, j in J, k in VALS: givens[i,j] != 0}:
88.43 + x[i,j,k] = (if givens[i,j] = k then 1 else 0);
88.44 +/* assign pre-defined numbers using the "givens" */
88.45 +
88.46 +s.t. fb{i in I, j in J}: sum{k in VALS} x[i,j,k] = 1;
88.47 +/* each cell must be assigned exactly one number */
88.48 +
88.49 +s.t. singleNum {k in VALS}: sum{i in I, j in J} x[i,j,k] = 1;
88.50 +/* a value can only occur once */
88.51 +
88.52 +s.t. neighborContraint {i in I, j in J, k in 1..80}:
88.53 + x[i,j,k] <= sum{i2 in I, j2 in J} x[i2,j2,k+1] * neighbors[i,j,i2,j2];
88.54 +/* each cell must have a neighbor with the next higher value */
88.55 +
88.56 +
88.57 +/* there is no need for an objective function here */
88.58 +
88.59 +
88.60 +solve;
88.61 +
88.62 +for {i in I}
88.63 +{ for {0..0: i = 1 or i = 4 or i = 7}
88.64 + printf " +----------+----------+----------+\n";
88.65 + for {j in J}
88.66 + { for {0..0: j = 1 or j = 4 or j = 7} printf(" |");
88.67 + printf " %2d", sum{k in VALS} x[i,j,k] * k;
88.68 + for {0..0: j = 9} printf(" |\n");
88.69 + }
88.70 + for {0..0: i = 9}
88.71 + printf " +----------+----------+----------+\n";
88.72 +}
88.73 +
88.74 +data;
88.75 +
88.76 +param givens : 1 2 3 4 5 6 7 8 9 :=
88.77 + 1 . . . . . . . . .
88.78 + 2 . 11 12 15 18 21 62 61 .
88.79 + 3 . 6 . . . . . 60 .
88.80 + 4 . 33 . . . . . 57 .
88.81 + 5 . 32 . . . . . 56 .
88.82 + 6 . 37 . . . . . 73 .
88.83 + 7 . 38 . . . . . 72 .
88.84 + 8 . 43 44 47 48 51 76 77 .
88.85 + 9 . . . . . . . . . ;
88.86 +
88.87 +end;
89.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
89.2 +++ b/examples/pbn.mod Mon Dec 06 13:09:21 2010 +0100
89.3 @@ -0,0 +1,194 @@
89.4 +/* PBN, Paint-By-Numbers Puzzle */
89.5 +
89.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
89.7 +
89.8 +/* A paint-by-number puzzle consists of an m*n grid of pixels (the
89.9 + canvas) together with m+n cluster-size sequences, one for each row
89.10 + and column. The goal is to paint the canvas with a picture that
89.11 + satisfies the following constraints:
89.12 +
89.13 + 1. Each pixel must be blank or white.
89.14 +
89.15 + 2. If a row or column has cluster-size sequence s1, s2, ..., sk,
89.16 + then it must contain k clusters of black pixels - the first with
89.17 + s1 black pixels, the second with s2 black pixels, and so on.
89.18 +
89.19 + It should be noted that "first" means "leftmost" for rows and
89.20 + "topmost" for columns, and that rows and columns need not begin or
89.21 + end with black pixels.
89.22 +
89.23 + Example:
89.24 + 1 1
89.25 + 1 1
89.26 + 2 1 1 1 1 1 2 3
89.27 + 3 2 1 2 1 2 3 4 8 9
89.28 +
89.29 + 3 6 # # # . # # # # # #
89.30 + 1 4 # . . . . . # # # #
89.31 + 1 1 3 . . # . # . . # # #
89.32 + 2 . . . . . . . . # #
89.33 + 3 3 . . # # # . . # # #
89.34 + 1 4 # . . . . . # # # #
89.35 + 2 5 # # . . . # # # # #
89.36 + 2 5 # # . . . # # # # #
89.37 + 1 1 . . . # . . . . . #
89.38 + 3 . . # # # . . . . .
89.39 +
89.40 + (In Russia this sort of puzzles is known as "Japanese crossword".)
89.41 +
89.42 + References:
89.43 + Robert A. Bosch, "Painting by Numbers", 2000.
89.44 + <http://www.oberlin.edu/~math/faculty/bosch/pbn-page.html> */
89.45 +
89.46 +param m, integer, >= 1;
89.47 +/* the number of rows */
89.48 +
89.49 +param n, integer, >= 1;
89.50 +/* the number of columns */
89.51 +
89.52 +param row{i in 1..m, 1..n div 2}, integer, >= 0, default 0;
89.53 +/* the cluster-size sequence for row i (raw data) */
89.54 +
89.55 +param col{j in 1..n, 1..m div 2}, integer, >= 0, default 0;
89.56 +/* the cluster-size sequence for column j (raw data) */
89.57 +
89.58 +param kr{i in 1..m} := sum{t in 1..n div 2: row[i,t] > 0} 1;
89.59 +/* the number of clusters in row i */
89.60 +
89.61 +param kc{j in 1..n} := sum{t in 1..m div 2: col[j,t] > 0} 1;
89.62 +/* the number of clusters in column j */
89.63 +
89.64 +param sr{i in 1..m, t in 1..kr[i]} := row[i,t], integer, >= 1;
89.65 +/* the cluster-size sequence for row i */
89.66 +
89.67 +param sc{j in 1..n, t in 1..kc[j]} := col[j,t], integer, >= 1;
89.68 +/* the cluster-size sequence for column j */
89.69 +
89.70 +check{i in 1..m}: sum{t in 1..kr[i]} sr[i,t] <= n - (kr[i] - 1);
89.71 +/* check that the sum of the cluster sizes in each row is valid */
89.72 +
89.73 +check{j in 1..n}: sum{t in 1..kc[j]} sc[j,t] <= m - (kc[j] - 1);
89.74 +/* check that the sum of the cluster sizes in each column is valid */
89.75 +
89.76 +check: sum{i in 1..m, t in 1..kr[i]} sr[i,t] =
89.77 + sum{j in 1..n, t in 1..kc[j]} sc[j,t];
89.78 +/* check that the sum of the cluster sizes in all rows is equal to the
89.79 + sum of the cluster sizes in all columns */
89.80 +
89.81 +param er{i in 1..m, t in 1..kr[i]} :=
89.82 + if t = 1 then 1 else er[i,t-1] + sr[i,t-1] + 1;
89.83 +/* the smallest value of j such that row i's t-th cluster can be
89.84 + placed in row i with its leftmost pixel occupying pixel j */
89.85 +
89.86 +param lr{i in 1..m, t in 1..kr[i]} :=
89.87 + if t = kr[i] then n + 1 - sr[i,t] else lr[i,t+1] - sr[i,t] - 1;
89.88 +/* the largest value of j such that row i's t-th cluster can be
89.89 + placed in row i with its leftmost pixel occupying pixel j */
89.90 +
89.91 +param ec{j in 1..n, t in 1..kc[j]} :=
89.92 + if t = 1 then 1 else ec[j,t-1] + sc[j,t-1] + 1;
89.93 +/* the smallest value of i such that column j's t-th cluster can be
89.94 + placed in column j with its topmost pixel occupying pixel i */
89.95 +
89.96 +param lc{j in 1..n, t in 1..kc[j]} :=
89.97 + if t = kc[j] then m + 1 - sc[j,t] else lc[j,t+1] - sc[j,t] - 1;
89.98 +/* the largest value of i such that column j's t-th cluster can be
89.99 + placed in column j with its topmost pixel occupying pixel i */
89.100 +
89.101 +var z{i in 1..m, j in 1..n}, binary;
89.102 +/* z[i,j] = 1, if row i's j-th pixel is painted black
89.103 + z[i,j] = 0, if row i's j-th pixel is painted white */
89.104 +
89.105 +var y{i in 1..m, t in 1..kr[i], j in er[i,t]..lr[i,t]}, binary;
89.106 +/* y[i,t,j] = 1, if row i's t-th cluster is placed in row i with its
89.107 + leftmost pixel occupying pixel j
89.108 + y[i,t,j] = 0, if not */
89.109 +
89.110 +var x{j in 1..n, t in 1..kc[j], i in ec[j,t]..lc[j,t]}, binary;
89.111 +/* x[j,t,i] = 1, if column j's t-th cluster is placed in column j with
89.112 + its topmost pixel occupying pixel i
89.113 + x[j,t,i] = 0, if not */
89.114 +
89.115 +s.t. fa{i in 1..m, t in 1..kr[i]}:
89.116 + sum{j in er[i,t]..lr[i,t]} y[i,t,j] = 1;
89.117 +/* row i's t-th cluster must appear in row i exactly once */
89.118 +
89.119 +s.t. fb{i in 1..m, t in 1..kr[i]-1, j in er[i,t]..lr[i,t]}:
89.120 + y[i,t,j] <= sum{jp in j+sr[i,t]+1..lr[i,t+1]} y[i,t+1,jp];
89.121 +/* row i's (t+1)-th cluster must be placed to the right of its t-th
89.122 + cluster */
89.123 +
89.124 +s.t. fc{j in 1..n, t in 1..kc[j]}:
89.125 + sum{i in ec[j,t]..lc[j,t]} x[j,t,i] = 1;
89.126 +/* column j's t-th cluster must appear in column j exactly once */
89.127 +
89.128 +s.t. fd{j in 1..n, t in 1..kc[j]-1, i in ec[j,t]..lc[j,t]}:
89.129 + x[j,t,i] <= sum{ip in i+sc[j,t]+1..lc[j,t+1]} x[j,t+1,ip];
89.130 +/* column j's (t+1)-th cluster must be placed below its t-th cluster */
89.131 +
89.132 +s.t. fe{i in 1..m, j in 1..n}:
89.133 + z[i,j] <= sum{t in 1..kr[i], jp in er[i,t]..lr[i,t]:
89.134 + j-sr[i,t]+1 <= jp and jp <= j} y[i,t,jp];
89.135 +/* the double coverage constraint stating that if row i's j-th pixel
89.136 + is painted black, then at least one of row i's clusters must be
89.137 + placed in such a way that it covers row i's j-th pixel */
89.138 +
89.139 +s.t. ff{i in 1..m, j in 1..n}:
89.140 + z[i,j] <= sum{t in 1..kc[j], ip in ec[j,t]..lc[j,t]:
89.141 + i-sc[j,t]+1 <= ip and ip <= i} x[j,t,ip];
89.142 +/* the double coverage constraint making sure that if row i's j-th
89.143 + pixel is painted black, then at least one of column j's clusters
89.144 + covers it */
89.145 +
89.146 +s.t. fg{i in 1..m, j in 1..n, t in 1..kr[i], jp in er[i,t]..lr[i,t]:
89.147 + j-sr[i,t]+1 <= jp and jp <= j}: z[i,j] >= y[i,t,jp];
89.148 +/* the constraint to prevent white pixels from being covered by the
89.149 + row clusters */
89.150 +
89.151 +s.t. fh{i in 1..m, j in 1..n, t in 1..kc[j], ip in ec[j,t]..lc[j,t]:
89.152 + i-sc[j,t]+1 <= ip and ip <= i}: z[i,j] >= x[j,t,ip];
89.153 +/* the constraint to prevent white pixels from being covered by the
89.154 + column clusters */
89.155 +
89.156 +/* there is no need for an objective function here */
89.157 +
89.158 +solve;
89.159 +
89.160 +for {i in 1..m}
89.161 +{ printf{j in 1..n} " %s", if z[i,j] then "#" else ".";
89.162 + printf "\n";
89.163 +}
89.164 +
89.165 +data;
89.166 +
89.167 +/* These data correspond to the example above. */
89.168 +
89.169 +param m := 10;
89.170 +
89.171 +param n := 10;
89.172 +
89.173 +param row : 1 2 3 4 :=
89.174 + 1 3 6 . .
89.175 + 2 1 4 . .
89.176 + 3 1 1 3 .
89.177 + 4 2 . . .
89.178 + 5 3 3 . .
89.179 + 6 1 4 . .
89.180 + 7 2 5 . .
89.181 + 8 2 5 . .
89.182 + 9 1 1 . .
89.183 + 10 3 . . . ;
89.184 +
89.185 +param col : 1 2 3 4 :=
89.186 + 1 2 3 . .
89.187 + 2 1 2 . .
89.188 + 3 1 1 1 1
89.189 + 4 1 2 . .
89.190 + 5 1 1 1 1
89.191 + 6 1 2 . .
89.192 + 7 2 3 . .
89.193 + 8 3 4 . .
89.194 + 9 8 . . .
89.195 + 10 9 . . . ;
89.196 +
89.197 +end;
90.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
90.2 +++ b/examples/plan.lp Mon Dec 06 13:09:21 2010 +0100
90.3 @@ -0,0 +1,39 @@
90.4 +\* plan.lp *\
90.5 +
90.6 +Minimize
90.7 + value: .03 bin1 + .08 bin2 + .17 bin3 + .12 bin4 + .15 bin5 +
90.8 + .21 alum + .38 silicon
90.9 +
90.10 +Subject To
90.11 + yield: bin1 + bin2 + bin3 + bin4 + bin5 +
90.12 + alum + silicon = 2000
90.13 +
90.14 + fe: .15 bin1 + .04 bin2 + .02 bin3 + .04 bin4 + .02 bin5 +
90.15 + .01 alum + .03 silicon <= 60
90.16 +
90.17 + cu: .03 bin1 + .05 bin2 + .08 bin3 + .02 bin4 + .06 bin5 +
90.18 + .01 alum <= 100
90.19 +
90.20 + mn: .02 bin1 + .04 bin2 + .01 bin3 + .02 bin4 + .02 bin5 <= 40
90.21 +
90.22 + mg: .02 bin1 + .03 bin2 + .01 bin5 <= 30
90.23 +
90.24 + al: .70 bin1 + .75 bin2 + .80 bin3 + .75 bin4 + .80 bin5 +
90.25 + .97 alum >= 1500
90.26 +
90.27 + si1: .02 bin1 + .06 bin2 + .08 bin3 + .12 bin4 + .02 bin5 +
90.28 + .01 alum + .97 silicon >= 250
90.29 +
90.30 + si2: .02 bin1 + .06 bin2 + .08 bin3 + .12 bin4 + .02 bin5 +
90.31 + .01 alum + .97 silicon <= 300
90.32 +
90.33 +Bounds
90.34 + bin1 <= 200
90.35 + bin2 <= 2500
90.36 + 400 <= bin3 <= 800
90.37 + 100 <= bin4 <= 700
90.38 + bin5 <= 1500
90.39 +
90.40 +End
90.41 +
90.42 +\* eof *\
91.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
91.2 +++ b/examples/plan.mod Mon Dec 06 13:09:21 2010 +0100
91.3 @@ -0,0 +1,39 @@
91.4 +/* plan.mod */
91.5 +
91.6 +var bin1, >= 0, <= 200;
91.7 +var bin2, >= 0, <= 2500;
91.8 +var bin3, >= 400, <= 800;
91.9 +var bin4, >= 100, <= 700;
91.10 +var bin5, >= 0, <= 1500;
91.11 +var alum, >= 0;
91.12 +var silicon, >= 0;
91.13 +
91.14 +minimize
91.15 +
91.16 +value: .03 * bin1 + .08 * bin2 + .17 * bin3 + .12 * bin4 + .15 * bin5 +
91.17 + .21 * alum + .38 * silicon;
91.18 +
91.19 +subject to
91.20 +
91.21 +yield: bin1 + bin2 + bin3 + bin4 + bin5 + alum + silicon = 2000;
91.22 +
91.23 +fe: .15 * bin1 + .04 * bin2 + .02 * bin3 + .04 * bin4 + .02 * bin5 +
91.24 + .01 * alum + .03 * silicon <= 60;
91.25 +
91.26 +cu: .03 * bin1 + .05 * bin2 + .08 * bin3 + .02 * bin4 + .06 * bin5 +
91.27 + .01 * alum <= 100;
91.28 +
91.29 +mn: .02 * bin1 + .04 * bin2 + .01 * bin3 + .02 * bin4 + .02 * bin5
91.30 + <= 40;
91.31 +
91.32 +mg: .02 * bin1 + .03 * bin2 + .01 * bin5 <= 30;
91.33 +
91.34 +al: .70 * bin1 + .75 * bin2 + .80 * bin3 + .75 * bin4 + .80 * bin5 +
91.35 + .97 * alum >= 1500;
91.36 +
91.37 +si: 250 <= .02 * bin1 + .06 * bin2 + .08 * bin3 + .12 * bin4 +
91.38 + .02 * bin5 + .01 * alum + .97 * silicon <= 300;
91.39 +
91.40 +end;
91.41 +
91.42 +/* eof */
92.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
92.2 +++ b/examples/plan.mps Mon Dec 06 13:09:21 2010 +0100
92.3 @@ -0,0 +1,54 @@
92.4 +*000000001111111111222222222233333333334444444444555555555566
92.5 +*234567890123456789012345678901234567890123456789012345678901
92.6 +NAME PLAN
92.7 +ROWS
92.8 + N VALUE
92.9 + E YIELD
92.10 + L FE
92.11 + L CU
92.12 + L MN
92.13 + L MG
92.14 + G AL
92.15 + L SI
92.16 +COLUMNS
92.17 + BIN1 VALUE .03000 YIELD 1.00000
92.18 + FE .15000 CU .03000
92.19 + MN .02000 MG .02000
92.20 + AL .70000 SI .02000
92.21 + BIN2 VALUE .08000 YIELD 1.00000
92.22 + FE .04000 CU .05000
92.23 + MN .04000 MG .03000
92.24 + AL .75000 SI .06000
92.25 + BIN3 VALUE .17000 YIELD 1.00000
92.26 + FE .02000 CU .08000
92.27 + MN .01000 AL .80000
92.28 + SI .08000
92.29 + BIN4 VALUE .12000 YIELD 1.00000
92.30 + FE .04000 CU .02000
92.31 + MN .02000 AL .75000
92.32 + SI .12000
92.33 + BIN5 VALUE .15000 YIELD 1.00000
92.34 + FE .02000 CU .06000
92.35 + MN .02000 MG .01000
92.36 + AL .80000 SI .02000
92.37 + ALUM VALUE .21000 YIELD 1.00000
92.38 + FE .01000 CU .01000
92.39 + AL .97000 SI .01000
92.40 + SILICON VALUE .38000 YIELD 1.00000
92.41 + FE .03000 SI .97000
92.42 +RHS
92.43 + RHS1 YIELD 2000.00000 FE 60.00000
92.44 + CU 100.00000 MN 40.00000
92.45 + SI 300.00000
92.46 + MG 30.00000 AL 1500.00000
92.47 +RANGES
92.48 + RNG1 SI 50.00000
92.49 +BOUNDS
92.50 + UP BND1 BIN1 200.00000
92.51 + UP BIN2 2500.00000
92.52 + LO BIN3 400.00000
92.53 + UP BIN3 800.00000
92.54 + LO BIN4 100.00000
92.55 + UP BIN4 700.00000
92.56 + UP BIN5 1500.00000
92.57 +ENDATA
93.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
93.2 +++ b/examples/prod.mod Mon Dec 06 13:09:21 2010 +0100
93.3 @@ -0,0 +1,331 @@
93.4 +# PROD, a multiperiod production model
93.5 +#
93.6 +# References:
93.7 +# Robert Fourer, David M. Gay and Brian W. Kernighan, "A Modeling Language
93.8 +# for Mathematical Programming." Management Science 36 (1990) 519-554.
93.9 +
93.10 +### PRODUCTION SETS AND PARAMETERS ###
93.11 +
93.12 +set prd 'products'; # Members of the product group
93.13 +
93.14 +param pt 'production time' {prd} > 0;
93.15 +
93.16 + # Crew-hours to produce 1000 units
93.17 +
93.18 +param pc 'production cost' {prd} > 0;
93.19 +
93.20 + # Nominal production cost per 1000, used
93.21 + # to compute inventory and shortage costs
93.22 +
93.23 +### TIME PERIOD SETS AND PARAMETERS ###
93.24 +
93.25 +param first > 0 integer;
93.26 + # Index of first production period to be modeled
93.27 +
93.28 +param last > first integer;
93.29 +
93.30 + # Index of last production period to be modeled
93.31 +
93.32 +set time 'planning horizon' := first..last;
93.33 +
93.34 +### EMPLOYMENT PARAMETERS ###
93.35 +
93.36 +param cs 'crew size' > 0 integer;
93.37 +
93.38 + # Workers per crew
93.39 +
93.40 +param sl 'shift length' > 0;
93.41 +
93.42 + # Regular-time hours per shift
93.43 +
93.44 +param rtr 'regular time rate' > 0;
93.45 +
93.46 + # Wage per hour for regular-time labor
93.47 +
93.48 +param otr 'overtime rate' > rtr;
93.49 +
93.50 + # Wage per hour for overtime labor
93.51 +
93.52 +param iw 'initial workforce' >= 0 integer;
93.53 +
93.54 + # Crews employed at start of first period
93.55 +
93.56 +param dpp 'days per period' {time} > 0;
93.57 +
93.58 + # Regular working days in a production period
93.59 +
93.60 +param ol 'overtime limit' {time} >= 0;
93.61 +
93.62 + # Maximum crew-hours of overtime in a period
93.63 +
93.64 +param cmin 'crew minimum' {time} >= 0;
93.65 +
93.66 + # Lower limit on average employment in a period
93.67 +
93.68 +param cmax 'crew maximum' {t in time} >= cmin[t];
93.69 +
93.70 + # Upper limit on average employment in a period
93.71 +
93.72 +param hc 'hiring cost' {time} >= 0;
93.73 +
93.74 + # Penalty cost of hiring a crew
93.75 +
93.76 +param lc 'layoff cost' {time} >= 0;
93.77 +
93.78 + # Penalty cost of laying off a crew
93.79 +
93.80 +### DEMAND PARAMETERS ###
93.81 +
93.82 +param dem 'demand' {prd,first..last+1} >= 0;
93.83 +
93.84 + # Requirements (in 1000s)
93.85 + # to be met from current production and inventory
93.86 +
93.87 +param pro 'promoted' {prd,first..last+1} logical;
93.88 +
93.89 + # true if product will be the subject
93.90 + # of a special promotion in the period
93.91 +
93.92 +### INVENTORY AND SHORTAGE PARAMETERS ###
93.93 +
93.94 +param rir 'regular inventory ratio' >= 0;
93.95 +
93.96 + # Proportion of non-promoted demand
93.97 + # that must be in inventory the previous period
93.98 +
93.99 +param pir 'promotional inventory ratio' >= 0;
93.100 +
93.101 + # Proportion of promoted demand
93.102 + # that must be in inventory the previous period
93.103 +
93.104 +param life 'inventory lifetime' > 0 integer;
93.105 +
93.106 + # Upper limit on number of periods that
93.107 + # any product may sit in inventory
93.108 +
93.109 +param cri 'inventory cost ratio' {prd} > 0;
93.110 +
93.111 + # Inventory cost per 1000 units is
93.112 + # cri times nominal production cost
93.113 +
93.114 +param crs 'shortage cost ratio' {prd} > 0;
93.115 +
93.116 + # Shortage cost per 1000 units is
93.117 + # crs times nominal production cost
93.118 +
93.119 +param iinv 'initial inventory' {prd} >= 0;
93.120 +
93.121 + # Inventory at start of first period; age unknown
93.122 +
93.123 +param iil 'initial inventory left' {p in prd, t in time}
93.124 + := iinv[p] less sum {v in first..t} dem[p,v];
93.125 +
93.126 + # Initial inventory still available for allocation
93.127 + # at end of period t
93.128 +
93.129 +param minv 'minimum inventory' {p in prd, t in time}
93.130 + := dem[p,t+1] * (if pro[p,t+1] then pir else rir);
93.131 +
93.132 + # Lower limit on inventory at end of period t
93.133 +
93.134 +### VARIABLES ###
93.135 +
93.136 +var Crews{first-1..last} >= 0;
93.137 +
93.138 + # Average number of crews employed in each period
93.139 +
93.140 +var Hire{time} >= 0; # Crews hired from previous to current period
93.141 +
93.142 +var Layoff{time} >= 0; # Crews laid off from previous to current period
93.143 +
93.144 +var Rprd 'regular production' {prd,time} >= 0;
93.145 +
93.146 + # Production using regular-time labor, in 1000s
93.147 +
93.148 +var Oprd 'overtime production' {prd,time} >= 0;
93.149 +
93.150 + # Production using overtime labor, in 1000s
93.151 +
93.152 +var Inv 'inventory' {prd,time,1..life} >= 0;
93.153 +
93.154 + # Inv[p,t,a] is the amount of product p that is
93.155 + # a periods old -- produced in period (t+1)-a --
93.156 + # and still in storage at the end of period t
93.157 +
93.158 +var Short 'shortage' {prd,time} >= 0;
93.159 +
93.160 + # Accumulated unsatisfied demand at the end of period t
93.161 +
93.162 +### OBJECTIVE ###
93.163 +
93.164 +minimize cost:
93.165 +
93.166 + sum {t in time} rtr * sl * dpp[t] * cs * Crews[t] +
93.167 + sum {t in time} hc[t] * Hire[t] +
93.168 + sum {t in time} lc[t] * Layoff[t] +
93.169 + sum {t in time, p in prd} otr * cs * pt[p] * Oprd[p,t] +
93.170 + sum {t in time, p in prd, a in 1..life} cri[p] * pc[p] * Inv[p,t,a] +
93.171 + sum {t in time, p in prd} crs[p] * pc[p] * Short[p,t];
93.172 +
93.173 + # Full regular wages for all crews employed, plus
93.174 + # penalties for hiring and layoffs, plus
93.175 + # wages for any overtime worked, plus
93.176 + # inventory and shortage costs
93.177 +
93.178 + # (All other production costs are assumed
93.179 + # to depend on initial inventory and on demands,
93.180 + # and so are not included explicitly.)
93.181 +
93.182 +### CONSTRAINTS ###
93.183 +
93.184 +rlim 'regular-time limit' {t in time}:
93.185 +
93.186 + sum {p in prd} pt[p] * Rprd[p,t] <= sl * dpp[t] * Crews[t];
93.187 +
93.188 + # Hours needed to accomplish all regular-time
93.189 + # production in a period must not exceed
93.190 + # hours available on all shifts
93.191 +
93.192 +olim 'overtime limit' {t in time}:
93.193 +
93.194 + sum {p in prd} pt[p] * Oprd[p,t] <= ol[t];
93.195 +
93.196 + # Hours needed to accomplish all overtime
93.197 + # production in a period must not exceed
93.198 + # the specified overtime limit
93.199 +
93.200 +empl0 'initial crew level': Crews[first-1] = iw;
93.201 +
93.202 + # Use given initial workforce
93.203 +
93.204 +empl 'crew levels' {t in time}: Crews[t] = Crews[t-1] + Hire[t] - Layoff[t];
93.205 +
93.206 + # Workforce changes by hiring or layoffs
93.207 +
93.208 +emplbnd 'crew limits' {t in time}: cmin[t] <= Crews[t] <= cmax[t];
93.209 +
93.210 + # Workforce must remain within specified bounds
93.211 +
93.212 +dreq1 'first demand requirement' {p in prd}:
93.213 +
93.214 + Rprd[p,first] + Oprd[p,first] + Short[p,first]
93.215 + - Inv[p,first,1] = dem[p,first] less iinv[p];
93.216 +
93.217 +dreq 'demand requirements' {p in prd, t in first+1..last}:
93.218 +
93.219 + Rprd[p,t] + Oprd[p,t] + Short[p,t] - Short[p,t-1]
93.220 + + sum {a in 1..life} (Inv[p,t-1,a] - Inv[p,t,a])
93.221 + = dem[p,t] less iil[p,t-1];
93.222 +
93.223 + # Production plus increase in shortage plus
93.224 + # decrease in inventory must equal demand
93.225 +
93.226 +ireq 'inventory requirements' {p in prd, t in time}:
93.227 +
93.228 + sum {a in 1..life} Inv[p,t,a] + iil[p,t] >= minv[p,t];
93.229 +
93.230 + # Inventory in storage at end of period t
93.231 + # must meet specified minimum
93.232 +
93.233 +izero 'impossible inventories' {p in prd, v in 1..life-1, a in v+1..life}:
93.234 +
93.235 + Inv[p,first+v-1,a] = 0;
93.236 +
93.237 + # In the vth period (starting from first)
93.238 + # no inventory may be more than v periods old
93.239 + # (initial inventories are handled separately)
93.240 +
93.241 +ilim1 'new-inventory limits' {p in prd, t in time}:
93.242 +
93.243 + Inv[p,t,1] <= Rprd[p,t] + Oprd[p,t];
93.244 +
93.245 + # New inventory cannot exceed
93.246 + # production in the most recent period
93.247 +
93.248 +ilim 'inventory limits' {p in prd, t in first+1..last, a in 2..life}:
93.249 +
93.250 + Inv[p,t,a] <= Inv[p,t-1,a-1];
93.251 +
93.252 + # Inventory left from period (t+1)-p
93.253 + # can only decrease as time goes on
93.254 +
93.255 +### DATA ###
93.256 +
93.257 +data;
93.258 +
93.259 +set prd := 18REG 24REG 24PRO ;
93.260 +
93.261 +param first := 1 ;
93.262 +param last := 13 ;
93.263 +param life := 2 ;
93.264 +
93.265 +param cs := 18 ;
93.266 +param sl := 8 ;
93.267 +param iw := 8 ;
93.268 +
93.269 +param rtr := 16.00 ;
93.270 +param otr := 43.85 ;
93.271 +param rir := 0.75 ;
93.272 +param pir := 0.80 ;
93.273 +
93.274 +param : pt pc cri crs iinv :=
93.275 +
93.276 + 18REG 1.194 2304. 0.015 1.100 82.0
93.277 + 24REG 1.509 2920. 0.015 1.100 792.2
93.278 + 24PRO 1.509 2910. 0.015 1.100 0.0 ;
93.279 +
93.280 +param : dpp ol cmin cmax hc lc :=
93.281 +
93.282 + 1 19.5 96.0 0.0 8.0 7500 7500
93.283 + 2 19.0 96.0 0.0 8.0 7500 7500
93.284 + 3 20.0 96.0 0.0 8.0 7500 7500
93.285 + 4 19.0 96.0 0.0 8.0 7500 7500
93.286 + 5 19.5 96.0 0.0 8.0 15000 15000
93.287 + 6 19.0 96.0 0.0 8.0 15000 15000
93.288 + 7 19.0 96.0 0.0 8.0 15000 15000
93.289 + 8 20.0 96.0 0.0 8.0 15000 15000
93.290 + 9 19.0 96.0 0.0 8.0 15000 15000
93.291 + 10 20.0 96.0 0.0 8.0 15000 15000
93.292 + 11 20.0 96.0 0.0 8.0 7500 7500
93.293 + 12 18.0 96.0 0.0 8.0 7500 7500
93.294 + 13 18.0 96.0 0.0 8.0 7500 7500 ;
93.295 +
93.296 +param dem (tr) :
93.297 +
93.298 + 18REG 24REG 24PRO :=
93.299 +
93.300 + 1 63.8 1212.0 0.0
93.301 + 2 76.0 306.2 0.0
93.302 + 3 88.4 319.0 0.0
93.303 + 4 913.8 208.4 0.0
93.304 + 5 115.0 298.0 0.0
93.305 + 6 133.8 328.2 0.0
93.306 + 7 79.6 959.6 0.0
93.307 + 8 111.0 257.6 0.0
93.308 + 9 121.6 335.6 0.0
93.309 + 10 470.0 118.0 1102.0
93.310 + 11 78.4 284.8 0.0
93.311 + 12 99.4 970.0 0.0
93.312 + 13 140.4 343.8 0.0
93.313 + 14 63.8 1212.0 0.0 ;
93.314 +
93.315 +param pro (tr) :
93.316 +
93.317 + 18REG 24REG 24PRO :=
93.318 +
93.319 + 1 0 1 0
93.320 + 2 0 0 0
93.321 + 3 0 0 0
93.322 + 4 1 0 0
93.323 + 5 0 0 0
93.324 + 6 0 0 0
93.325 + 7 0 1 0
93.326 + 8 0 0 0
93.327 + 9 0 0 0
93.328 + 10 1 0 1
93.329 + 11 0 0 0
93.330 + 12 0 0 0
93.331 + 13 0 1 0
93.332 + 14 0 1 0 ;
93.333 +
93.334 +end;
94.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
94.2 +++ b/examples/qfit.mod Mon Dec 06 13:09:21 2010 +0100
94.3 @@ -0,0 +1,49 @@
94.4 +/*Quadratic Curve Fitting Solution
94.5 +
94.6 + Find a plausable quadratic fit to a sample of points
94.7 +
94.8 + Nigel_Galloway@operamail.com
94.9 + February 1st., 2009
94.10 +*/
94.11 +set Sample;
94.12 +param Sx {z in Sample};
94.13 +param Sy {z in Sample};
94.14 +
94.15 +var a;
94.16 +var b;
94.17 +var c;
94.18 +
94.19 +equalz1 :sum{z in Sample} a*Sx[z]*Sx[z]*Sx[z]*Sx[z] + sum{z in Sample} b*Sx[z]*Sx[z]*Sx[z] + sum{z in Sample} c*Sx[z]*Sx[z] = sum{z in Sample} Sy[z]*Sx[z]*Sx[z];
94.20 +equalz2 :sum{z in Sample} a*Sx[z]*Sx[z]*Sx[z] + sum{z in Sample} b*Sx[z]*Sx[z] + sum{z in Sample} c*Sx[z] = sum{z in Sample} Sy[z]*Sx[z];
94.21 +equalz3 :sum{z in Sample} a*Sx[z]*Sx[z] + sum{z in Sample} b*Sx[z] + sum{z in Sample} c = sum{z in Sample} Sy[z];
94.22 +
94.23 +solve;
94.24 +
94.25 +printf "\nbest quadratic fit is:\n\ty = %f %s %fx %s %fx^2\n\n", c, if b < 0 then "-" else "+", abs(b), if a < 0 then "-" else "+", abs(a);
94.26 +
94.27 +data;
94.28 +
94.29 +param:
94.30 +Sample: Sx Sy :=
94.31 + 1 0 1
94.32 + 2 0.5 0.9
94.33 + 3 1 0.7
94.34 + 4 1.5 1.5
94.35 + 5 1.9 2
94.36 + 6 2.5 2.4
94.37 + 7 3 3.2
94.38 + 8 3.5 2
94.39 + 9 4 2.7
94.40 + 10 4.5 3.5
94.41 + 11 5 1
94.42 + 12 5.5 4
94.43 + 13 6 3.6
94.44 + 14 6.6 2.7
94.45 + 15 7 5.7
94.46 + 16 7.6 4.6
94.47 + 17 8.5 6
94.48 + 18 9 6.8
94.49 + 19 10 7.3
94.50 +;
94.51 +
94.52 +end;
95.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
95.2 +++ b/examples/queens.mod Mon Dec 06 13:09:21 2010 +0100
95.3 @@ -0,0 +1,41 @@
95.4 +/* QUEENS, a classic combinatorial optimization problem */
95.5 +
95.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
95.7 +
95.8 +/* The Queens Problem is to place as many queens as possible on the 8x8
95.9 + (or more generally, nxn) chess board in a way that they do not fight
95.10 + each other. This problem is probably as old as the chess game itself,
95.11 + and thus its origin is not known, but it is known that Gauss studied
95.12 + this problem. */
95.13 +
95.14 +param n, integer, > 0, default 8;
95.15 +/* size of the chess board */
95.16 +
95.17 +var x{1..n, 1..n}, binary;
95.18 +/* x[i,j] = 1 means that a queen is placed in square [i,j] */
95.19 +
95.20 +s.t. a{i in 1..n}: sum{j in 1..n} x[i,j] <= 1;
95.21 +/* at most one queen can be placed in each row */
95.22 +
95.23 +s.t. b{j in 1..n}: sum{i in 1..n} x[i,j] <= 1;
95.24 +/* at most one queen can be placed in each column */
95.25 +
95.26 +s.t. c{k in 2-n..n-2}: sum{i in 1..n, j in 1..n: i-j == k} x[i,j] <= 1;
95.27 +/* at most one queen can be placed in each "\"-diagonal */
95.28 +
95.29 +s.t. d{k in 3..n+n-1}: sum{i in 1..n, j in 1..n: i+j == k} x[i,j] <= 1;
95.30 +/* at most one queen can be placed in each "/"-diagonal */
95.31 +
95.32 +maximize obj: sum{i in 1..n, j in 1..n} x[i,j];
95.33 +/* objective is to place as many queens as possible */
95.34 +
95.35 +/* solve the problem */
95.36 +solve;
95.37 +
95.38 +/* and print its optimal solution */
95.39 +for {i in 1..n}
95.40 +{ for {j in 1..n} printf " %s", if x[i,j] then "Q" else ".";
95.41 + printf("\n");
95.42 +}
95.43 +
95.44 +end;
96.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
96.2 +++ b/examples/samp1.mps Mon Dec 06 13:09:21 2010 +0100
96.3 @@ -0,0 +1,29 @@
96.4 +NAME SAMP1
96.5 +ROWS
96.6 + N Z
96.7 + G R1
96.8 + G R2
96.9 + G R3
96.10 +COLUMNS
96.11 + X1 R1 2.0 R2 1.0
96.12 + X1 R3 5.0 Z 3.0
96.13 + MARK0001 'MARKER' 'INTORG'
96.14 + X2 R1 -1.0 R2 -1.0
96.15 + X2 R3 3.0 Z 7.0
96.16 + X3 R1 1.0 R2 -6.0
96.17 + X3 Z -1.0
96.18 + MARK0002 'MARKER' 'INTEND'
96.19 + X4 R1 -1.0 R2 4.0
96.20 + X4 R3 1.0 Z 1.0
96.21 +RHS
96.22 + RHS1 R1 1.0
96.23 + RHS1 R2 8.0
96.24 + RHS1 R3 5.0
96.25 +BOUNDS
96.26 + UP BND1 X1 4.0
96.27 + LO BND1 X2 2.0
96.28 + UP BND1 X2 5.0
96.29 + UP BND1 X3 1.0
96.30 + LO BND1 X4 3.0
96.31 + UP BND1 X4 8.0
96.32 +ENDATA
97.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
97.2 +++ b/examples/samp2.mps Mon Dec 06 13:09:21 2010 +0100
97.3 @@ -0,0 +1,27 @@
97.4 +NAME SAMP2
97.5 +ROWS
97.6 + N Z
97.7 + G R1
97.8 + G R2
97.9 + G R3
97.10 +COLUMNS
97.11 + X1 R1 2.0 R2 1.0
97.12 + X1 R3 5.0 Z 3.0
97.13 + X2 R1 -1.0 R2 -1.0
97.14 + X2 R3 3.0 Z 7.0
97.15 + X3 R1 1.0 R2 -6.0
97.16 + X3 Z -1.0
97.17 + X4 R1 -1.0 R2 4.0
97.18 + X4 R3 1.0 Z 1.0
97.19 +RHS
97.20 + RHS1 R1 1.0
97.21 + RHS1 R2 8.0
97.22 + RHS1 R3 5.0
97.23 +BOUNDS
97.24 + UP BND1 X1 4.0
97.25 + LO BND1 X2 2.0
97.26 + UI BND1 X2 5.0
97.27 + BV BND1 X3
97.28 + LO BND1 X4 3.0
97.29 + UP BND1 X4 8.0
97.30 +ENDATA
98.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
98.2 +++ b/examples/sample.asn Mon Dec 06 13:09:21 2010 +0100
98.3 @@ -0,0 +1,40 @@
98.4 +c sample.asn
98.5 +c
98.6 +c This is an example of the assignment problem data
98.7 +c in DIMACS format.
98.8 +c
98.9 +p asn 17 22
98.10 +c
98.11 +n 1
98.12 +n 2
98.13 +n 3
98.14 +n 4
98.15 +n 5
98.16 +n 6
98.17 +n 7
98.18 +n 8
98.19 +c
98.20 +a 1 9 13
98.21 +a 1 10 21
98.22 +a 1 12 20
98.23 +a 2 10 12
98.24 +a 2 12 8
98.25 +a 2 13 26
98.26 +a 3 11 22
98.27 +a 3 13 11
98.28 +a 4 9 12
98.29 +a 4 12 36
98.30 +a 4 14 25
98.31 +a 5 11 41
98.32 +a 5 12 40
98.33 +a 5 13 11
98.34 +a 5 14 4
98.35 +a 5 15 8
98.36 +a 5 16 35
98.37 +a 5 17 32
98.38 +a 6 9 13
98.39 +a 7 10 19
98.40 +a 8 10 39
98.41 +a 8 11 15
98.42 +c
98.43 +c eof
99.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
99.2 +++ b/examples/sample.c Mon Dec 06 13:09:21 2010 +0100
99.3 @@ -0,0 +1,52 @@
99.4 +/* sample.c */
99.5 +
99.6 +#include <stdio.h>
99.7 +#include <stdlib.h>
99.8 +#include <glpk.h>
99.9 +
99.10 +int main(void)
99.11 +{ glp_prob *lp;
99.12 + int ia[1+1000], ja[1+1000];
99.13 + double ar[1+1000], z, x1, x2, x3;
99.14 +s1: lp = glp_create_prob();
99.15 +s2: glp_set_prob_name(lp, "sample");
99.16 +s3: glp_set_obj_dir(lp, GLP_MAX);
99.17 +s4: glp_add_rows(lp, 3);
99.18 +s5: glp_set_row_name(lp, 1, "p");
99.19 +s6: glp_set_row_bnds(lp, 1, GLP_UP, 0.0, 100.0);
99.20 +s7: glp_set_row_name(lp, 2, "q");
99.21 +s8: glp_set_row_bnds(lp, 2, GLP_UP, 0.0, 600.0);
99.22 +s9: glp_set_row_name(lp, 3, "r");
99.23 +s10: glp_set_row_bnds(lp, 3, GLP_UP, 0.0, 300.0);
99.24 +s11: glp_add_cols(lp, 3);
99.25 +s12: glp_set_col_name(lp, 1, "x1");
99.26 +s13: glp_set_col_bnds(lp, 1, GLP_LO, 0.0, 0.0);
99.27 +s14: glp_set_obj_coef(lp, 1, 10.0);
99.28 +s15: glp_set_col_name(lp, 2, "x2");
99.29 +s16: glp_set_col_bnds(lp, 2, GLP_LO, 0.0, 0.0);
99.30 +s17: glp_set_obj_coef(lp, 2, 6.0);
99.31 +s18: glp_set_col_name(lp, 3, "x3");
99.32 +s19: glp_set_col_bnds(lp, 3, GLP_LO, 0.0, 0.0);
99.33 +s20: glp_set_obj_coef(lp, 3, 4.0);
99.34 +s21: ia[1] = 1, ja[1] = 1, ar[1] = 1.0; /* a[1,1] = 1 */
99.35 +s22: ia[2] = 1, ja[2] = 2, ar[2] = 1.0; /* a[1,2] = 1 */
99.36 +s23: ia[3] = 1, ja[3] = 3, ar[3] = 1.0; /* a[1,3] = 1 */
99.37 +s24: ia[4] = 2, ja[4] = 1, ar[4] = 10.0; /* a[2,1] = 10 */
99.38 +s25: ia[5] = 3, ja[5] = 1, ar[5] = 2.0; /* a[3,1] = 2 */
99.39 +s26: ia[6] = 2, ja[6] = 2, ar[6] = 4.0; /* a[2,2] = 4 */
99.40 +s27: ia[7] = 3, ja[7] = 2, ar[7] = 2.0; /* a[3,2] = 2 */
99.41 +s28: ia[8] = 2, ja[8] = 3, ar[8] = 5.0; /* a[2,3] = 5 */
99.42 +s29: ia[9] = 3, ja[9] = 3, ar[9] = 6.0; /* a[3,3] = 6 */
99.43 +s30: glp_load_matrix(lp, 9, ia, ja, ar);
99.44 +s31: glp_simplex(lp, NULL);
99.45 +s32: z = glp_get_obj_val(lp);
99.46 +s33: x1 = glp_get_col_prim(lp, 1);
99.47 +s34: x2 = glp_get_col_prim(lp, 2);
99.48 +s35: x3 = glp_get_col_prim(lp, 3);
99.49 +s36: printf("\nz = %g; x1 = %g; x2 = %g; x3 = %g\n",
99.50 + z, x1, x2, x3);
99.51 +s37: glp_delete_prob(lp);
99.52 + return 0;
99.53 +}
99.54 +
99.55 +/* eof */
100.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
100.2 +++ b/examples/sample.clq Mon Dec 06 13:09:21 2010 +0100
100.3 @@ -0,0 +1,30 @@
100.4 +c sample.clq
100.5 +c
100.6 +c This is an example of the Maximum Weight Clique
100.7 +c Problem in DIMACS clique/coloring format.
100.8 +c
100.9 +p edge 8 16
100.10 +n 1 3
100.11 +n 2 4
100.12 +n 3 8
100.13 +n 5 5
100.14 +n 6 2
100.15 +n 8 3
100.16 +e 1 4
100.17 +e 1 5
100.18 +e 1 6
100.19 +e 1 8
100.20 +e 2 3
100.21 +e 2 6
100.22 +e 2 7
100.23 +e 2 8
100.24 +e 3 4
100.25 +e 3 6
100.26 +e 3 7
100.27 +e 4 5
100.28 +e 4 8
100.29 +e 5 7
100.30 +e 5 8
100.31 +e 6 7
100.32 +c
100.33 +c eof
101.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
101.2 +++ b/examples/sample.col Mon Dec 06 13:09:21 2010 +0100
101.3 @@ -0,0 +1,30 @@
101.4 +c sample.col
101.5 +c
101.6 +c This is an example of the vertex coloring problem data
101.7 +c in DIMACS format.
101.8 +c
101.9 +p edge 10 21
101.10 +c
101.11 +e 1 2
101.12 +e 1 6
101.13 +e 1 7
101.14 +e 1 10
101.15 +e 2 3
101.16 +e 2 7
101.17 +e 2 8
101.18 +e 3 4
101.19 +e 3 8
101.20 +e 4 5
101.21 +e 4 8
101.22 +e 4 9
101.23 +e 5 6
101.24 +e 5 9
101.25 +e 5 10
101.26 +e 6 10
101.27 +e 7 8
101.28 +e 7 10
101.29 +e 8 9
101.30 +e 8 10
101.31 +e 9 10
101.32 +c
101.33 +c eof
102.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
102.2 +++ b/examples/sample.max Mon Dec 06 13:09:21 2010 +0100
102.3 @@ -0,0 +1,26 @@
102.4 +c sample.max
102.5 +c
102.6 +c This is an example of the maximum flow problem data
102.7 +c in DIMACS format.
102.8 +c
102.9 +p max 9 14
102.10 +c
102.11 +n 1 s
102.12 +n 9 t
102.13 +c
102.14 +a 1 2 14
102.15 +a 1 4 23
102.16 +a 2 3 10
102.17 +a 2 4 9
102.18 +a 3 5 12
102.19 +a 3 8 18
102.20 +a 4 5 26
102.21 +a 5 2 11
102.22 +a 5 6 25
102.23 +a 5 7 4
102.24 +a 6 7 7
102.25 +a 6 8 8
102.26 +a 7 9 15
102.27 +a 8 9 20
102.28 +c
102.29 +c eof
103.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
103.2 +++ b/examples/sample.min Mon Dec 06 13:09:21 2010 +0100
103.3 @@ -0,0 +1,26 @@
103.4 +c sample.min
103.5 +c
103.6 +c This is an example of the minimum cost flow problem data
103.7 +c in DIMACS format.
103.8 +c
103.9 +p min 9 14
103.10 +c
103.11 +n 1 20
103.12 +n 9 -20
103.13 +c
103.14 +a 1 2 0 14 0
103.15 +a 1 4 0 23 0
103.16 +a 2 3 0 10 2
103.17 +a 2 4 0 9 3
103.18 +a 3 5 2 12 1
103.19 +a 3 8 0 18 0
103.20 +a 4 5 0 26 0
103.21 +a 5 2 0 11 1
103.22 +a 5 6 0 25 5
103.23 +a 5 7 0 4 7
103.24 +a 6 7 0 7 0
103.25 +a 6 8 4 8 0
103.26 +a 7 9 0 15 3
103.27 +a 8 9 0 20 9
103.28 +c
103.29 +c eof
104.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
104.2 +++ b/examples/sat.mod Mon Dec 06 13:09:21 2010 +0100
104.3 @@ -0,0 +1,201 @@
104.4 +/* SAT, Satisfiability Problem */
104.5 +
104.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
104.7 +
104.8 +param m, integer, > 0;
104.9 +/* number of clauses */
104.10 +
104.11 +param n, integer, > 0;
104.12 +/* number of variables */
104.13 +
104.14 +set C{1..m};
104.15 +/* clauses; each clause C[i], i = 1, ..., m, is disjunction of some
104.16 + variables or their negations; in the data section each clause is
104.17 + coded as a set of indices of corresponding variables, where negative
104.18 + indices mean negation; for example, the clause (x3 or not x7 or x11)
104.19 + is coded as the set { 3, -7, 11 } */
104.20 +
104.21 +var x{1..n}, binary;
104.22 +/* main variables */
104.23 +
104.24 +/* To solve the satisfiability problem means to determine all variables
104.25 + x[j] such that conjunction of all clauses C[1] and ... and C[m] takes
104.26 + on the value true, i.e. all clauses are satisfied.
104.27 +
104.28 + Let the clause C[i] be (t or t' or ... or t''), where t, t', ..., t''
104.29 + are either variables or their negations. The condition of satisfying
104.30 + C[i] can be most naturally written as:
104.31 +
104.32 + t + t' + ... + t'' >= 1, (1)
104.33 +
104.34 + where t, t', t'' have to be replaced by either x[j] or (1 - x[j]).
104.35 + The formulation (1) leads to the mip problem with no objective, i.e.
104.36 + to a feasibility problem.
104.37 +
104.38 + Another, more practical way is to write the condition for C[i] as:
104.39 +
104.40 + t + t' + ... + t'' + y[i] >= 1, (2)
104.41 +
104.42 + where y[i] is an auxiliary binary variable, and minimize the sum of
104.43 + y[i]. If the sum is zero, all y[i] are also zero, and therefore all
104.44 + clauses are satisfied. If the sum is minimal but non-zero, its value
104.45 + shows the number of clauses which cannot be satisfied. */
104.46 +
104.47 +var y{1..m}, binary, >= 0;
104.48 +/* auxiliary variables */
104.49 +
104.50 +s.t. c{i in 1..m}:
104.51 + sum{j in C[i]} (if j > 0 then x[j] else (1 - x[-j])) + y[i] >= 1;
104.52 +/* the condition (2) */
104.53 +
104.54 +minimize unsat: sum{i in 1..m} y[i];
104.55 +/* number of unsatisfied clauses */
104.56 +
104.57 +data;
104.58 +
104.59 +/* These data correspond to the instance hole6 (pigeon hole problem for
104.60 + 6 holes) from SATLIB, the Satisfiability Library, which is part of
104.61 + the collection at the Forschungsinstitut fuer anwendungsorientierte
104.62 + Wissensverarbeitung in Ulm Germany */
104.63 +
104.64 +/* The optimal solution is 1 (one clause cannot be satisfied) */
104.65 +
104.66 +param m := 133;
104.67 +
104.68 +param n := 42;
104.69 +
104.70 +set C[1] := -1 -7;
104.71 +set C[2] := -1 -13;
104.72 +set C[3] := -1 -19;
104.73 +set C[4] := -1 -25;
104.74 +set C[5] := -1 -31;
104.75 +set C[6] := -1 -37;
104.76 +set C[7] := -7 -13;
104.77 +set C[8] := -7 -19;
104.78 +set C[9] := -7 -25;
104.79 +set C[10] := -7 -31;
104.80 +set C[11] := -7 -37;
104.81 +set C[12] := -13 -19;
104.82 +set C[13] := -13 -25;
104.83 +set C[14] := -13 -31;
104.84 +set C[15] := -13 -37;
104.85 +set C[16] := -19 -25;
104.86 +set C[17] := -19 -31;
104.87 +set C[18] := -19 -37;
104.88 +set C[19] := -25 -31;
104.89 +set C[20] := -25 -37;
104.90 +set C[21] := -31 -37;
104.91 +set C[22] := -2 -8;
104.92 +set C[23] := -2 -14;
104.93 +set C[24] := -2 -20;
104.94 +set C[25] := -2 -26;
104.95 +set C[26] := -2 -32;
104.96 +set C[27] := -2 -38;
104.97 +set C[28] := -8 -14;
104.98 +set C[29] := -8 -20;
104.99 +set C[30] := -8 -26;
104.100 +set C[31] := -8 -32;
104.101 +set C[32] := -8 -38;
104.102 +set C[33] := -14 -20;
104.103 +set C[34] := -14 -26;
104.104 +set C[35] := -14 -32;
104.105 +set C[36] := -14 -38;
104.106 +set C[37] := -20 -26;
104.107 +set C[38] := -20 -32;
104.108 +set C[39] := -20 -38;
104.109 +set C[40] := -26 -32;
104.110 +set C[41] := -26 -38;
104.111 +set C[42] := -32 -38;
104.112 +set C[43] := -3 -9;
104.113 +set C[44] := -3 -15;
104.114 +set C[45] := -3 -21;
104.115 +set C[46] := -3 -27;
104.116 +set C[47] := -3 -33;
104.117 +set C[48] := -3 -39;
104.118 +set C[49] := -9 -15;
104.119 +set C[50] := -9 -21;
104.120 +set C[51] := -9 -27;
104.121 +set C[52] := -9 -33;
104.122 +set C[53] := -9 -39;
104.123 +set C[54] := -15 -21;
104.124 +set C[55] := -15 -27;
104.125 +set C[56] := -15 -33;
104.126 +set C[57] := -15 -39;
104.127 +set C[58] := -21 -27;
104.128 +set C[59] := -21 -33;
104.129 +set C[60] := -21 -39;
104.130 +set C[61] := -27 -33;
104.131 +set C[62] := -27 -39;
104.132 +set C[63] := -33 -39;
104.133 +set C[64] := -4 -10;
104.134 +set C[65] := -4 -16;
104.135 +set C[66] := -4 -22;
104.136 +set C[67] := -4 -28;
104.137 +set C[68] := -4 -34;
104.138 +set C[69] := -4 -40;
104.139 +set C[70] := -10 -16;
104.140 +set C[71] := -10 -22;
104.141 +set C[72] := -10 -28;
104.142 +set C[73] := -10 -34;
104.143 +set C[74] := -10 -40;
104.144 +set C[75] := -16 -22;
104.145 +set C[76] := -16 -28;
104.146 +set C[77] := -16 -34;
104.147 +set C[78] := -16 -40;
104.148 +set C[79] := -22 -28;
104.149 +set C[80] := -22 -34;
104.150 +set C[81] := -22 -40;
104.151 +set C[82] := -28 -34;
104.152 +set C[83] := -28 -40;
104.153 +set C[84] := -34 -40;
104.154 +set C[85] := -5 -11;
104.155 +set C[86] := -5 -17;
104.156 +set C[87] := -5 -23;
104.157 +set C[88] := -5 -29;
104.158 +set C[89] := -5 -35;
104.159 +set C[90] := -5 -41;
104.160 +set C[91] := -11 -17;
104.161 +set C[92] := -11 -23;
104.162 +set C[93] := -11 -29;
104.163 +set C[94] := -11 -35;
104.164 +set C[95] := -11 -41;
104.165 +set C[96] := -17 -23;
104.166 +set C[97] := -17 -29;
104.167 +set C[98] := -17 -35;
104.168 +set C[99] := -17 -41;
104.169 +set C[100] := -23 -29;
104.170 +set C[101] := -23 -35;
104.171 +set C[102] := -23 -41;
104.172 +set C[103] := -29 -35;
104.173 +set C[104] := -29 -41;
104.174 +set C[105] := -35 -41;
104.175 +set C[106] := -6 -12;
104.176 +set C[107] := -6 -18;
104.177 +set C[108] := -6 -24;
104.178 +set C[109] := -6 -30;
104.179 +set C[110] := -6 -36;
104.180 +set C[111] := -6 -42;
104.181 +set C[112] := -12 -18;
104.182 +set C[113] := -12 -24;
104.183 +set C[114] := -12 -30;
104.184 +set C[115] := -12 -36;
104.185 +set C[116] := -12 -42;
104.186 +set C[117] := -18 -24;
104.187 +set C[118] := -18 -30;
104.188 +set C[119] := -18 -36;
104.189 +set C[120] := -18 -42;
104.190 +set C[121] := -24 -30;
104.191 +set C[122] := -24 -36;
104.192 +set C[123] := -24 -42;
104.193 +set C[124] := -30 -36;
104.194 +set C[125] := -30 -42;
104.195 +set C[126] := -36 -42;
104.196 +set C[127] := 6 5 4 3 2 1;
104.197 +set C[128] := 12 11 10 9 8 7;
104.198 +set C[129] := 18 17 16 15 14 13;
104.199 +set C[130] := 24 23 22 21 20 19;
104.200 +set C[131] := 30 29 28 27 26 25;
104.201 +set C[132] := 36 35 34 33 32 31;
104.202 +set C[133] := 42 41 40 39 38 37;
104.203 +
104.204 +end;
105.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
105.2 +++ b/examples/shiftcover.mod Mon Dec 06 13:09:21 2010 +0100
105.3 @@ -0,0 +1,244 @@
105.4 +/* File: shiftcover.mod */
105.5 +
105.6 +/* WORKFORCE SHIFT COVERAGE assignment problem */
105.7 +
105.8 +/* Written by Larry D'Agostino <larrydag -at- sbcglobal -dot- com>
105.9 +
105.10 + Maximize Productivity with Industrial Engineer and Operations Research Tools
105.11 + http://industrialengineertools.blogspot.com
105.12 +
105.13 +
105.14 +/* The WORKFORCE SHIFT COVERAGE is an assigment problem that determines
105.15 + the schedule of crew given available time and shifts.
105.16 +
105.17 + The objective is to cover the available time given hourly demand with the minimum
105.18 + number of crew members.
105.19 +
105.20 + This is a set covering problem that is very common among finding crew
105.21 + and shift allocations. Notice in the data section the workforce shift allocation
105.22 + per day of the week.*/
105.23 +
105.24 +
105.25 +/* ----- Model PARAMTERS and SETS -----*/
105.26 +
105.27 +param numhrs;
105.28 +/* number of hours of operations in a given day */
105.29 +
105.30 +param dys;
105.31 +/* number of days in a week */
105.32 +
105.33 +set S;
105.34 +/* set of crew shifts */
105.35 +
105.36 +set H := 1..numhrs;
105.37 +/* set of hours of a day*/
105.38 +
105.39 +set D;
105.40 +/* set of days of a week*/
105.41 +
105.42 +param dmnd{h in H, d in D};
105.43 +/* demand for crew members given h hour and d day */
105.44 +
105.45 +param shifts{d in D, h in H, s in S};
105.46 +/* shifts to assign to crew members given d day, h hour, and s shift schedule
105.47 +
105.48 +/*----- Model VARIABLES -----*/
105.49 +
105.50 +var crew{s in S}, integer, >=0;
105.51 +/* number of crew assigned to shift S */
105.52 +
105.53 +
105.54 +/*----- Model CONSTRAINTS -----*/
105.55 +
105.56 +s.t. Coverage{h in H, d in D}: sum{s in S} crew[s]*shifts[d,h,s] >= dmnd[h,d];
105.57 +/* number of crew to cover with a shift given hourly demand and day */
105.58 +
105.59 +
105.60 +/*----- Model OBJECTIVE -----*/
105.61 +
105.62 +minimize obj: sum{s in S} crew[s];
105.63 +/* minimize number of crew to cover demand*/
105.64 +
105.65 +solve;
105.66 +display crew;
105.67 +
105.68 +printf "\n";
105.69 +printf "Total Crew: %3d\n\n", sum{s in S} crew[s];
105.70 +
105.71 +
105.72 +
105.73 +printf "\n\n";
105.74 +printf "Weekly Crew Schedule\n\n";
105.75 +printf "Hour ";
105.76 +printf{d in D} " %s ", d;
105.77 +printf "\n";
105.78 +for {h in H} {
105.79 + printf " %2s ",h;
105.80 + printf{d in D} " %3d ", sum{s in S} crew[s]*shifts[d,h,s];
105.81 + printf "\n";
105.82 +}
105.83 +printf"\n";
105.84 +
105.85 +
105.86 +
105.87 +data;
105.88 +
105.89 +param numhrs := 16;
105.90 +
105.91 +set D := SUN, MON, TUE, WED, THU, FRI, SAT;
105.92 +
105.93 +set S := Sh1, Sh2, Sh3, Sh4, Sh5, Sh6, Sh7, Sh8, Sh9;
105.94 +
105.95 +param dmnd : SUN MON TUE WED THU FRI SAT :=
105.96 +1 0 3 3 4 3 2 0
105.97 +2 0 14 14 16 14 12 12
105.98 +3 0 24 24 27 24 20 15
105.99 +4 0 28 28 32 28 23 15
105.100 +5 0 33 33 37 33 24 16
105.101 +6 0 34 34 38 34 24 15
105.102 +7 0 35 35 39 35 25 11
105.103 +8 0 35 35 40 35 27 0
105.104 +9 0 34 34 39 34 25 0
105.105 +10 0 31 31 35 31 24 0
105.106 +11 2 24 24 27 24 25 0
105.107 +12 3 19 19 21 19 21 0
105.108 +13 2 24 24 27 24 13 0
105.109 +14 2 16 16 18 16 0 0
105.110 +15 0 7 7 7 7 0 0
105.111 +16 0 5 5 5 5 0 0;
105.112 +
105.113 +
105.114 +param shifts :=
105.115 +['SUN',*,*]:
105.116 + Sh1 Sh2 Sh3 Sh4 Sh5 Sh6 Sh7 Sh8 Sh9 :=
105.117 +1 0 0 0 0 0 0 0 0 0
105.118 +2 0 0 0 0 0 0 0 0 0
105.119 +3 0 0 0 0 0 0 0 0 0
105.120 +4 0 0 0 0 0 0 0 0 0
105.121 +5 0 0 0 0 0 0 0 0 0
105.122 +6 0 0 0 0 0 0 0 0 0
105.123 +7 0 0 0 0 0 0 0 0 0
105.124 +8 0 0 0 0 0 0 0 0 0
105.125 +9 0 0 0 0 0 0 0 0 0
105.126 +10 0 0 0 0 0 0 0 0 0
105.127 +11 0 0 0 0 0 0 0 0 1
105.128 +12 0 0 0 0 0 0 0 0 1
105.129 +13 0 0 0 0 0 0 0 0 1
105.130 +14 0 0 0 0 0 0 0 0 1
105.131 +15 0 0 0 0 0 0 0 0 0
105.132 +16 0 0 0 0 0 0 0 0 0
105.133 +
105.134 +
105.135 +['MON',*,*]:
105.136 + Sh1 Sh2 Sh3 Sh4 Sh5 Sh6 Sh7 Sh8 Sh9 :=
105.137 +1 1 0 0 0 0 0 0 0 0
105.138 +2 1 1 0 0 0 0 0 0 0
105.139 +3 1 1 1 0 0 0 0 0 0
105.140 +4 1 1 1 1 0 0 0 0 0
105.141 +5 0 1 1 1 1 0 0 0 0
105.142 +6 1 0 1 1 1 1 0 0 1
105.143 +7 1 1 0 1 1 1 1 0 1
105.144 +8 1 1 1 0 1 1 1 1 1
105.145 +9 1 1 1 1 0 1 1 1 1
105.146 +10 0 1 1 1 1 0 1 1 1
105.147 +11 0 0 1 1 1 1 0 1 0
105.148 +12 0 0 0 1 1 1 1 0 1
105.149 +13 0 0 0 0 1 1 1 1 1
105.150 +14 0 0 0 0 0 1 1 1 1
105.151 +15 0 0 0 0 0 0 1 1 1
105.152 +16 0 0 0 0 0 0 0 1 1
105.153 +
105.154 +['TUE',*,*]:
105.155 + Sh1 Sh2 Sh3 Sh4 Sh5 Sh6 Sh7 Sh8 Sh9 :=
105.156 +1 1 0 0 0 0 0 0 0 0
105.157 +2 1 1 0 0 0 0 0 0 0
105.158 +3 1 1 1 0 0 0 0 0 0
105.159 +4 1 1 1 1 0 0 0 0 0
105.160 +5 0 1 1 1 1 0 0 0 0
105.161 +6 1 0 1 1 1 1 0 0 1
105.162 +7 1 1 0 1 1 1 1 0 1
105.163 +8 1 1 1 0 1 1 1 1 1
105.164 +9 1 1 1 1 0 1 1 1 1
105.165 +10 0 1 1 1 1 0 1 1 1
105.166 +11 0 0 1 1 1 1 0 1 0
105.167 +12 0 0 0 1 1 1 1 0 1
105.168 +13 0 0 0 0 1 1 1 1 1
105.169 +14 0 0 0 0 0 1 1 1 1
105.170 +15 0 0 0 0 0 0 1 1 1
105.171 +16 0 0 0 0 0 0 0 1 1
105.172 +
105.173 +['WED',*,*]:
105.174 + Sh1 Sh2 Sh3 Sh4 Sh5 Sh6 Sh7 Sh8 Sh9 :=
105.175 +1 1 0 0 0 0 0 0 0 0
105.176 +2 1 1 0 0 0 0 0 0 0
105.177 +3 1 1 1 0 0 0 0 0 0
105.178 +4 1 1 1 1 0 0 0 0 0
105.179 +5 0 1 1 1 1 0 0 0 0
105.180 +6 1 0 1 1 1 1 0 0 1
105.181 +7 1 1 0 1 1 1 1 0 1
105.182 +8 1 1 1 0 1 1 1 1 1
105.183 +9 1 1 1 1 0 1 1 1 1
105.184 +10 0 1 1 1 1 0 1 1 1
105.185 +11 0 0 1 1 1 1 0 1 0
105.186 +12 0 0 0 1 1 1 1 0 1
105.187 +13 0 0 0 0 1 1 1 1 1
105.188 +14 0 0 0 0 0 1 1 1 1
105.189 +15 0 0 0 0 0 0 1 1 1
105.190 +16 0 0 0 0 0 0 0 1 1
105.191 +
105.192 +['THU',*,*]:
105.193 + Sh1 Sh2 Sh3 Sh4 Sh5 Sh6 Sh7 Sh8 Sh9 :=
105.194 +1 1 0 0 0 0 0 0 0 0
105.195 +2 1 1 0 0 0 0 0 0 0
105.196 +3 1 1 1 0 0 0 0 0 0
105.197 +4 1 1 1 1 0 0 0 0 0
105.198 +5 0 1 1 1 1 0 0 0 0
105.199 +6 1 0 1 1 1 1 0 0 0
105.200 +7 1 1 0 1 1 1 1 0 0
105.201 +8 1 1 1 0 1 1 1 1 0
105.202 +9 1 1 1 1 0 1 1 1 0
105.203 +10 0 1 1 1 1 0 1 1 0
105.204 +11 0 0 1 1 1 1 0 1 0
105.205 +12 0 0 0 1 1 1 1 0 0
105.206 +13 0 0 0 0 1 1 1 1 0
105.207 +14 0 0 0 0 0 1 1 1 0
105.208 +15 0 0 0 0 0 0 1 1 0
105.209 +16 0 0 0 0 0 0 0 1 0
105.210 +
105.211 +['FRI',*,*]:
105.212 + Sh1 Sh2 Sh3 Sh4 Sh5 Sh6 Sh7 Sh8 Sh9 :=
105.213 +1 1 0 0 0 0 0 0 0 0
105.214 +2 1 1 0 0 0 0 0 0 0
105.215 +3 1 1 1 0 0 0 0 0 0
105.216 +4 1 1 1 1 0 0 0 0 0
105.217 +5 0 1 1 1 1 0 0 0 0
105.218 +6 1 0 1 1 1 1 0 0 0
105.219 +7 1 1 0 1 1 1 1 0 0
105.220 +8 1 1 1 0 1 1 1 1 0
105.221 +9 1 1 1 1 0 1 1 1 0
105.222 +10 0 1 1 1 1 0 1 1 0
105.223 +11 0 0 1 1 1 1 0 1 0
105.224 +12 0 0 0 1 1 1 1 0 0
105.225 +13 0 0 0 0 1 1 1 1 0
105.226 +14 0 0 0 0 0 1 1 1 0
105.227 +15 0 0 0 0 0 0 1 1 0
105.228 +16 0 0 0 0 0 0 0 1 0
105.229 +
105.230 +['SAT',*,*]:
105.231 + Sh1 Sh2 Sh3 Sh4 Sh5 Sh6 Sh7 Sh8 Sh9 :=
105.232 +1 0 0 0 0 0 0 0 0 0
105.233 +2 0 0 0 0 0 0 0 0 1
105.234 +3 0 0 0 0 0 0 0 0 1
105.235 +4 0 0 0 0 0 0 0 0 1
105.236 +5 0 0 0 0 0 0 0 0 1
105.237 +6 0 0 0 0 0 0 0 0 1
105.238 +7 0 0 0 0 0 0 0 0 1
105.239 +8 0 0 0 0 0 0 0 0 0
105.240 +9 0 0 0 0 0 0 0 0 0
105.241 +10 0 0 0 0 0 0 0 0 0
105.242 +11 0 0 0 0 0 0 0 0 0
105.243 +12 0 0 0 0 0 0 0 0 0
105.244 +13 0 0 0 0 0 0 0 0 0
105.245 +14 0 0 0 0 0 0 0 0 0
105.246 +15 0 0 0 0 0 0 0 0 0
105.247 +16 0 0 0 0 0 0 0 0 0;
106.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
106.2 +++ b/examples/shikaku.mod Mon Dec 06 13:09:21 2010 +0100
106.3 @@ -0,0 +1,107 @@
106.4 +/* A solver for the Japanese number-puzzle Shikaku
106.5 + * http://en.wikipedia.org/wiki/Shikaku
106.6 + *
106.7 + * Sebastian Nowozin <nowozin@gmail.com>, 27th January 2009
106.8 + */
106.9 +
106.10 +param ndim := 10;
106.11 +set rows := 1..ndim;
106.12 +set rows1 := 1..(ndim+1);
106.13 +set cols := 1..ndim;
106.14 +set cols1 := 1..(ndim+1);
106.15 +param givens{rows, cols}, integer, >= 0, default 0;
106.16 +
106.17 +/* Set of vertices as (row,col) coordinates */
106.18 +set V := { (i,j) in { rows, cols }: givens[i,j] != 0 };
106.19 +
106.20 +/* Set of all feasible boxes of the right size: only this boxes are possible.
106.21 + * The box contains (i,j) and ranges from (k,l) to (m,n)
106.22 + */
106.23 +set B := { (i,j,k,l,m,n) in { V, rows, cols, rows1, cols1 }:
106.24 + i >= k and i < m and j >= l and j < n and /* Contains (i,j) */
106.25 + ((m-k)*(n-l)) = givens[i,j] and /* Right size */
106.26 + card({ (s,t) in V: s >= k and s < m and t >= l and t < n }) = 1
106.27 + /* Contains only (i,j), no other number */
106.28 +};
106.29 +
106.30 +var x{B}, binary;
106.31 +
106.32 +/* Cover each square exactly once */
106.33 +s.t. cover_once{ (s,t) in { rows, cols } }:
106.34 + sum{(i,j,k,l,m,n) in B: s >= k and s < m and t >= l and t < n}
106.35 + x[i,j,k,l,m,n] = 1;
106.36 +
106.37 +minimize cost: 0;
106.38 +
106.39 +solve;
106.40 +
106.41 +/* Output solution graphically */
106.42 +printf "\nSolution:\n";
106.43 +for { row in rows1 } {
106.44 + for { col in cols1 } {
106.45 + printf{0..0: card({(i,j,k,l,m,n) in B:
106.46 + col >= l and col <= n and (row = k or row = m) and
106.47 + x[i,j,k,l,m,n] = 1}) > 0 and
106.48 + card({(i,j,k,l,m,n) in B:
106.49 + row >= k and row <= m and (col = l or col = n) and
106.50 + x[i,j,k,l,m,n] = 1}) > 0} "+";
106.51 + printf{0..0: card({(i,j,k,l,m,n) in B:
106.52 + col >= l and col <= n and (row = k or row = m) and
106.53 + x[i,j,k,l,m,n] = 1}) = 0 and
106.54 + card({(i,j,k,l,m,n) in B:
106.55 + row >= k and row <= m and (col = l or col = n) and
106.56 + x[i,j,k,l,m,n] = 1}) > 0} "|";
106.57 + printf{0..0: card({(i,j,k,l,m,n) in B:
106.58 + row >= k and row <= m and (col = l or col = n) and
106.59 + x[i,j,k,l,m,n] = 1}) = 0 and
106.60 + card({(i,j,k,l,m,n) in B:
106.61 + col >= l and col <= n and (row = k or row = m) and
106.62 + x[i,j,k,l,m,n] = 1}) > 0} "-";
106.63 + printf{0..0: card({(i,j,k,l,m,n) in B:
106.64 + row >= k and row <= m and (col = l or col = n) and
106.65 + x[i,j,k,l,m,n] = 1}) = 0 and
106.66 + card({(i,j,k,l,m,n) in B:
106.67 + col >= l and col <= n and (row = k or row = m) and
106.68 + x[i,j,k,l,m,n] = 1}) = 0} " ";
106.69 +
106.70 + printf{0..0: card({(i,j,k,l,m,n) in B:
106.71 + col >= l and col < n and (row = k or row = m) and
106.72 + x[i,j,k,l,m,n] = 1}) > 0} "---";
106.73 + printf{0..0: card({(i,j,k,l,m,n) in B:
106.74 + col >= l and col < n and (row = k or row = m) and
106.75 + x[i,j,k,l,m,n] = 1}) = 0} " ";
106.76 + }
106.77 + printf "\n";
106.78 +
106.79 + for { (col,p) in { cols, 1 }: card({ s in rows: s = row }) = 1 } {
106.80 + printf{0..0: card({(i,j,k,l,m,n) in B:
106.81 + row >= k and row < m and (col = l or col = n) and
106.82 + x[i,j,k,l,m,n] = 1}) > 0} "|";
106.83 + printf{0..0: card({(i,j,k,l,m,n) in B:
106.84 + row >= k and row < m and (col = l or col = n) and
106.85 + x[i,j,k,l,m,n] = 1}) = 0} " ";
106.86 + printf{0..0: card({ (i,j) in V: i = row and j = col}) > 0} " %2d", givens[row,col];
106.87 + printf{0..0: card({ (i,j) in V: i = row and j = col}) = 0} " .";
106.88 + }
106.89 + printf{0..0: card({ r in rows: r = row }) = 1} "|\n";
106.90 +}
106.91 +
106.92 +data;
106.93 +
106.94 +/* This Shikaku is from
106.95 + * http://www.emn.fr/x-info/sdemasse/gccat/KShikaku.html#uid5449
106.96 + */
106.97 +param givens : 1 2 3 4 5 6 7 8 9 10 :=
106.98 + 1 9 . . . 12 . . 5 . .
106.99 + 2 . . . . . . . . . .
106.100 + 3 . . . . . . . . . 6
106.101 + 4 8 . 6 . 8 . . . . .
106.102 + 5 . . . . . . . . . .
106.103 + 6 . . . . . . . . . .
106.104 + 7 . . . . . 6 . 8 . 12
106.105 + 8 4 . . . . . . . . .
106.106 + 9 . . . . . . . . . .
106.107 + 10 . . 3 . . 9 . . . 4
106.108 + ;
106.109 +
106.110 +end;
107.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
107.2 +++ b/examples/sorting.mod Mon Dec 06 13:09:21 2010 +0100
107.3 @@ -0,0 +1,67 @@
107.4 +/* sorting.mod - how to sort arrays in MathProg */
107.5 +
107.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
107.7 +
107.8 +# Sometimes it is necessary to print parameters or variables in the
107.9 +# order of ascending or descending their values. Suppose, for example,
107.10 +# that we have the following subscripted parameter:
107.11 +
107.12 +set I := 1..12;
107.13 +
107.14 +param a{i in I} := Uniform(2, 7);
107.15 +
107.16 +# If we print all its members:
107.17 +
107.18 +printf{i in I} "a[%d] = %g\n", i, a[i];
107.19 +
107.20 +# the output may look like follows:
107.21 +#
107.22 +# a[1] = 2.64156
107.23 +# a[2] = 2.04798
107.24 +# a[3] = 2.14843
107.25 +# a[4] = 4.76896
107.26 +# a[5] = 6.09132
107.27 +# a[6] = 3.27780
107.28 +# a[7] = 4.06113
107.29 +# a[8] = 4.05898
107.30 +# a[9] = 6.63120
107.31 +# a[10] = 6.50318
107.32 +# a[11] = 3.46065
107.33 +# a[12] = 4.69845
107.34 +#
107.35 +# However, we would like the parameter members to appear in the order
107.36 +# of ascending their values.
107.37 +#
107.38 +# Introduce the following auxiliary parameter:
107.39 +
107.40 +param pos{i in I} :=
107.41 + 1 + card({j in I: a[j] < a[i] or a[j] = a[i] and j < i});
107.42 +
107.43 +# where pos[i] = k means that in the sorted list member a[i] would
107.44 +# have k-th position, 1 <= k <= |I|. Then introduce another auxiliary
107.45 +# parameter:
107.46 +
107.47 +param ind{k in 1..card(I)} := sum{i in I: pos[i] = k} i;
107.48 +
107.49 +# where ind[k] = i iff pos[k] = i.
107.50 +#
107.51 +# Now, the following statement:
107.52 +
107.53 +printf{k in 1..card(I)} "a[%d] = %g\n", ind[k], a[ind[k]];
107.54 +
107.55 +# prints the parameter members in the desired order:
107.56 +#
107.57 +# a[2] = 2.04798
107.58 +# a[3] = 2.14843
107.59 +# a[1] = 2.64156
107.60 +# a[6] = 3.27780
107.61 +# a[11] = 3.46065
107.62 +# a[8] = 4.05898
107.63 +# a[7] = 4.06113
107.64 +# a[12] = 4.69845
107.65 +# a[4] = 4.76896
107.66 +# a[5] = 6.09132
107.67 +# a[10] = 6.50318
107.68 +# a[9] = 6.63120
107.69 +
107.70 +end;
108.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
108.2 +++ b/examples/spp.mod Mon Dec 06 13:09:21 2010 +0100
108.3 @@ -0,0 +1,67 @@
108.4 +/* SPP, Shortest Path Problem */
108.5 +
108.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
108.7 +
108.8 +/* Given a directed graph G = (V,E), its edge lengths c(i,j) for all
108.9 + (i,j) in E, and two nodes s, t in V, the Shortest Path Problem (SPP)
108.10 + is to find a directed path from s to t whose length is minimal. */
108.11 +
108.12 +param n, integer, > 0;
108.13 +/* number of nodes */
108.14 +
108.15 +set E, within {i in 1..n, j in 1..n};
108.16 +/* set of edges */
108.17 +
108.18 +param c{(i,j) in E};
108.19 +/* c[i,j] is length of edge (i,j); note that edge lengths are allowed
108.20 + to be of any sign (positive, negative, or zero) */
108.21 +
108.22 +param s, in {1..n};
108.23 +/* source node */
108.24 +
108.25 +param t, in {1..n};
108.26 +/* target node */
108.27 +
108.28 +var x{(i,j) in E}, >= 0;
108.29 +/* x[i,j] = 1 means that edge (i,j) belong to shortest path;
108.30 + x[i,j] = 0 means that edge (i,j) does not belong to shortest path;
108.31 + note that variables x[i,j] are binary, however, there is no need to
108.32 + declare them so due to the totally unimodular constraint matrix */
108.33 +
108.34 +s.t. r{i in 1..n}: sum{(j,i) in E} x[j,i] + (if i = s then 1) =
108.35 + sum{(i,j) in E} x[i,j] + (if i = t then 1);
108.36 +/* conservation conditions for unity flow from s to t; every feasible
108.37 + solution is a path from s to t */
108.38 +
108.39 +minimize Z: sum{(i,j) in E} c[i,j] * x[i,j];
108.40 +/* objective function is the path length to be minimized */
108.41 +
108.42 +data;
108.43 +
108.44 +/* Optimal solution is 20 that corresponds to the following shortest
108.45 + path: s = 1 -> 2 -> 4 -> 8 -> 6 = t */
108.46 +
108.47 +param n := 8;
108.48 +
108.49 +param s := 1;
108.50 +
108.51 +param t := 6;
108.52 +
108.53 +param : E : c :=
108.54 + 1 2 1
108.55 + 1 4 8
108.56 + 1 7 6
108.57 + 2 4 2
108.58 + 3 2 14
108.59 + 3 4 10
108.60 + 3 5 6
108.61 + 3 6 19
108.62 + 4 5 8
108.63 + 4 8 13
108.64 + 5 8 12
108.65 + 6 5 7
108.66 + 7 4 5
108.67 + 8 6 4
108.68 + 8 7 10;
108.69 +
108.70 +end;
109.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
109.2 +++ b/examples/spxsamp1.c Mon Dec 06 13:09:21 2010 +0100
109.3 @@ -0,0 +1,18 @@
109.4 +/* spxsamp1.c */
109.5 +
109.6 +#include <stdio.h>
109.7 +#include <stdlib.h>
109.8 +#include <glpk.h>
109.9 +
109.10 +int main(void)
109.11 +{ glp_prob *P;
109.12 + P = glp_create_prob();
109.13 + glp_read_mps(P, GLP_MPS_DECK, NULL, "25fv47.mps");
109.14 + glp_adv_basis(P, 0);
109.15 + glp_simplex(P, NULL);
109.16 + glp_print_sol(P, "25fv47.txt");
109.17 + glp_delete_prob(P);
109.18 + return 0;
109.19 +}
109.20 +
109.21 +/* eof */
110.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
110.2 +++ b/examples/spxsamp2.c Mon Dec 06 13:09:21 2010 +0100
110.3 @@ -0,0 +1,20 @@
110.4 +/* spxsamp2.c */
110.5 +
110.6 +#include <stdio.h>
110.7 +#include <stdlib.h>
110.8 +#include <glpk.h>
110.9 +
110.10 +int main(void)
110.11 +{ glp_prob *P;
110.12 + glp_smcp parm;
110.13 + P = glp_create_prob();
110.14 + glp_read_mps(P, GLP_MPS_DECK, NULL, "25fv47.mps");
110.15 + glp_init_smcp(&parm);
110.16 + parm.meth = GLP_DUAL;
110.17 + glp_simplex(P, &parm);
110.18 + glp_print_sol(P, "25fv47.txt");
110.19 + glp_delete_prob(P);
110.20 + return 0;
110.21 +}
110.22 +
110.23 +/* eof */
111.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
111.2 +++ b/examples/sql/README Mon Dec 06 13:09:21 2010 +0100
111.3 @@ -0,0 +1,5 @@
111.4 +This subdirectory contains files which demonstrate using data tables
111.5 +in MathProg models for MySQL and iODBC.
111.6 +
111.7 +Script mysql_setup.sh is used to load the data from the *.sql files to
111.8 +a MySQL database. Change the username, if necessary.
112.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
112.2 +++ b/examples/sql/mysql_setup.sh Mon Dec 06 13:09:21 2010 +0100
112.3 @@ -0,0 +1,6 @@
112.4 +#!/bin/sh
112.5 +# This file can be used to create database glpk in MySQL.
112.6 +echo MySQL is called for user root.
112.7 +mysql -f -u root -p < sudoku.sql
112.8 +echo MySQL is called for user root.
112.9 +mysql -f -u root -p < transp.sql
113.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
113.2 +++ b/examples/sql/sudoku.sql Mon Dec 06 13:09:21 2010 +0100
113.3 @@ -0,0 +1,101 @@
113.4 +CREATE DATABASE glpk;
113.5 +CREATE USER glpk@localhost IDENTIFIED BY 'gnu';
113.6 +GRANT ALL PRIVILEGES ON glpk.* TO glpk@localhost;
113.7 +USE glpk;
113.8 +DROP TABLE sudoku;
113.9 +CREATE TABLE sudoku (
113.10 + ID INT ,
113.11 + COL INT ,
113.12 + LIN INT ,
113.13 + VAL INT ,
113.14 + PRIMARY KEY ( ID, COL, LIN )
113.15 + );
113.16 +DROP TABLE sudoku_solution;
113.17 +CREATE TABLE sudoku_solution (
113.18 + ID INT ,
113.19 + COL INT ,
113.20 + LIN INT ,
113.21 + VAL INT ,
113.22 + PRIMARY KEY ( ID, COL, LIN )
113.23 + );
113.24 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 1, 5);
113.25 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 2, 0);
113.26 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 3, 0);
113.27 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 4, 0);
113.28 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 5, 4);
113.29 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 6, 0);
113.30 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 7, 0);
113.31 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 8, 0);
113.32 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 9, 0);
113.33 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 1, 0);
113.34 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 2, 0);
113.35 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 3, 3);
113.36 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 4, 0);
113.37 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 5, 0);
113.38 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 6, 0);
113.39 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 7, 6);
113.40 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 8, 2);
113.41 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 9, 0);
113.42 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 1, 0);
113.43 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 2, 0);
113.44 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 3, 0);
113.45 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 4, 0);
113.46 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 5, 0);
113.47 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 6, 9);
113.48 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 7, 0);
113.49 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 8, 0);
113.50 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 9, 4);
113.51 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 1, 0);
113.52 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 2, 0);
113.53 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 3, 6);
113.54 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 4, 0);
113.55 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 5, 0);
113.56 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 6, 7);
113.57 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 7, 2);
113.58 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 8, 0);
113.59 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 9, 0);
113.60 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 1, 8);
113.61 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 2, 1);
113.62 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 3, 0);
113.63 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 4, 0);
113.64 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 5, 0);
113.65 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 6, 0);
113.66 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 7, 0);
113.67 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 8, 4);
113.68 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 9, 3);
113.69 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 1, 0);
113.70 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 2, 0);
113.71 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 3, 9);
113.72 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 4, 1);
113.73 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 5, 0);
113.74 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 6, 0);
113.75 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 7, 0);
113.76 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 8, 0);
113.77 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 9, 0);
113.78 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 1, 7);
113.79 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 2, 0);
113.80 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 3, 0);
113.81 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 4, 5);
113.82 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 5, 0);
113.83 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 6, 0);
113.84 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 7, 0);
113.85 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 8, 0);
113.86 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 9, 0);
113.87 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 1, 0);
113.88 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 2, 9);
113.89 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 3, 2);
113.90 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 4, 0);
113.91 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 5, 0);
113.92 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 6, 0);
113.93 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 7, 8);
113.94 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 8, 0);
113.95 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 9, 0);
113.96 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 1, 0);
113.97 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 2, 0);
113.98 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 3, 0);
113.99 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 4, 0);
113.100 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 5, 3);
113.101 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 6, 0);
113.102 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 7, 0);
113.103 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 8, 0);
113.104 +INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 9, 6);
114.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
114.2 +++ b/examples/sql/sudoku_mysql.mod Mon Dec 06 13:09:21 2010 +0100
114.3 @@ -0,0 +1,113 @@
114.4 +/* SUDOKU, Number Placement Puzzle */
114.5 +
114.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@mai2.rcnet.ru> */
114.7 +
114.8 +/* This example shows how to use the table statement.
114.9 + The sudoku to be solves is read from file sudoku_in.csv.
114.10 + The solution is written to sudoku_out.csv.
114.11 + The file format is CSV as defined in
114.12 + RFC 4180 - Common Format and MIME Type for
114.13 + Comma-Separated Values (CSV) Files */
114.14 +
114.15 +/* Sudoku, also known as Number Place, is a logic-based placement
114.16 + puzzle. The aim of the canonical puzzle is to enter a numerical
114.17 + digit from 1 through 9 in each cell of a 9x9 grid made up of 3x3
114.18 + subgrids (called "regions"), starting with various digits given in
114.19 + some cells (the "givens"). Each row, column, and region must contain
114.20 + only one instance of each numeral.
114.21 +
114.22 + Example:
114.23 +
114.24 + +-------+-------+-------+
114.25 + | 5 3 . | . 7 . | . . . |
114.26 + | 6 . . | 1 9 5 | . . . |
114.27 + | . 9 8 | . . . | . 6 . |
114.28 + +-------+-------+-------+
114.29 + | 8 . . | . 6 . | . . 3 |
114.30 + | 4 . . | 8 . 3 | . . 1 |
114.31 + | 7 . . | . 2 . | . . 6 |
114.32 + +-------+-------+-------+
114.33 + | . 6 . | . . . | 2 8 . |
114.34 + | . . . | 4 1 9 | . . 5 |
114.35 + | . . . | . 8 . | . 7 9 |
114.36 + +-------+-------+-------+
114.37 +
114.38 + (From Wikipedia, the free encyclopedia.) */
114.39 +set fields dimen 2;
114.40 +
114.41 +param id;
114.42 +
114.43 +param givens{1..9, 1..9}, integer, >= 0, <= 9, default 0;
114.44 +/* the "givens" */
114.45 +
114.46 +/*
114.47 +table ti IN 'MySQL' 'Database=glpk;UID=glpk;PWD=gnu'
114.48 + 'sudoku' :
114.49 + fields <- [COL, LIN], givens ~ VAL;
114.50 +*/
114.51 +table ti IN 'MySQL' 'Database=glpk;UID=glpk;PWD=gnu'
114.52 + 'SELECT * FROM sudoku WHERE ID = ' & id :
114.53 + fields <- [COL, LIN], givens ~ VAL;
114.54 +
114.55 +var x{i in 1..9, j in 1..9, k in 1..9}, binary;
114.56 +/* x[i,j,k] = 1 means cell [i,j] is assigned number k */
114.57 +
114.58 +s.t. fa{i in 1..9, j in 1..9, k in 1..9: givens[i,j] != 0}:
114.59 + x[i,j,k] = (if givens[i,j] = k then 1 else 0);
114.60 +/* assign pre-defined numbers using the "givens" */
114.61 +
114.62 +s.t. fb{i in 1..9, j in 1..9}: sum{k in 1..9} x[i,j,k] = 1;
114.63 +/* each cell must be assigned exactly one number */
114.64 +
114.65 +s.t. fc{i in 1..9, k in 1..9}: sum{j in 1..9} x[i,j,k] = 1;
114.66 +/* cells in the same row must be assigned distinct numbers */
114.67 +
114.68 +s.t. fd{j in 1..9, k in 1..9}: sum{i in 1..9} x[i,j,k] = 1;
114.69 +/* cells in the same column must be assigned distinct numbers */
114.70 +
114.71 +s.t. fe{I in 1..9 by 3, J in 1..9 by 3, k in 1..9}:
114.72 + sum{i in I..I+2, j in J..J+2} x[i,j,k] = 1;
114.73 +/* cells in the same region must be assigned distinct numbers */
114.74 +
114.75 +/* there is no need for an objective function here */
114.76 +
114.77 +solve;
114.78 +
114.79 +table ta{(i,j) in fields} OUT
114.80 + 'MySQL' 'Database=glpk;UID=glpk;PWD=gnu'
114.81 + 'DELETE FROM sudoku_solution'
114.82 + 'WHERE ID = ' & id & ';'
114.83 + 'INSERT INTO sudoku_solution'
114.84 + '(ID, COL, LIN, VAL)'
114.85 + 'VALUES(?, ?, ?, ?);' :
114.86 + id ~ ID, i ~ COL, j ~ LIN, (sum{k in 1..9} x[i,j,k] * k) ~ VAL;
114.87 +
114.88 +printf "\nSudoku to be solved\n";
114.89 +for {i in 1..9}
114.90 +{ for {0..0: i = 1 or i = 4 or i = 7}
114.91 + printf " +-------+-------+-------+\n";
114.92 + for {j in 1..9}
114.93 + { for {0..0: j = 1 or j = 4 or j = 7} printf(" |");
114.94 + printf " %d", givens[i,j];
114.95 + for {0..0: j = 9} printf(" |\n");
114.96 + }
114.97 + for {0..0: i = 9}
114.98 + printf " +-------+-------+-------+\n";
114.99 + }
114.100 +printf "\nSolution\n";
114.101 +for {i in 1..9}
114.102 +{ for {0..0: i = 1 or i = 4 or i = 7}
114.103 + printf " +-------+-------+-------+\n";
114.104 + for {j in 1..9}
114.105 + { for {0..0: j = 1 or j = 4 or j = 7} printf(" |");
114.106 + printf " %d", sum{k in 1..9} x[i,j,k] * k;
114.107 + for {0..0: j = 9} printf(" |\n");
114.108 + }
114.109 + for {0..0: i = 9}
114.110 + printf " +-------+-------+-------+\n";
114.111 +}
114.112 +
114.113 +data;
114.114 +
114.115 +param id := 1;
114.116 +end;
115.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
115.2 +++ b/examples/sql/sudoku_odbc.mod Mon Dec 06 13:09:21 2010 +0100
115.3 @@ -0,0 +1,111 @@
115.4 +/* SUDOKU, Number Placement Puzzle */
115.5 +
115.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@mai2.rcnet.ru> */
115.7 +
115.8 +/* This example shows how to use the table statement.
115.9 + The sudoku to be solves is read from file sudoku_in.csv.
115.10 + The solution is written to sudoku_out.csv.
115.11 + The file format is CSV as defined in
115.12 + RFC 4180 - Common Format and MIME Type for
115.13 + Comma-Separated Values (CSV) Files */
115.14 +
115.15 +/* Sudoku, also known as Number Place, is a logic-based placement
115.16 + puzzle. The aim of the canonical puzzle is to enter a numerical
115.17 + digit from 1 through 9 in each cell of a 9x9 grid made up of 3x3
115.18 + subgrids (called "regions"), starting with various digits given in
115.19 + some cells (the "givens"). Each row, column, and region must contain
115.20 + only one instance of each numeral.
115.21 +
115.22 + Example:
115.23 +
115.24 + +-------+-------+-------+
115.25 + | 5 3 . | . 7 . | . . . |
115.26 + | 6 . . | 1 9 5 | . . . |
115.27 + | . 9 8 | . . . | . 6 . |
115.28 + +-------+-------+-------+
115.29 + | 8 . . | . 6 . | . . 3 |
115.30 + | 4 . . | 8 . 3 | . . 1 |
115.31 + | 7 . . | . 2 . | . . 6 |
115.32 + +-------+-------+-------+
115.33 + | . 6 . | . . . | 2 8 . |
115.34 + | . . . | 4 1 9 | . . 5 |
115.35 + | . . . | . 8 . | . 7 9 |
115.36 + +-------+-------+-------+
115.37 +
115.38 + (From Wikipedia, the free encyclopedia.) */
115.39 +set fields dimen 2;
115.40 +
115.41 +param id;
115.42 +
115.43 +param givens{1..9, 1..9}, integer, >= 0, <= 9, default 0;
115.44 +/* the "givens" */
115.45 +
115.46 +table ti IN 'iODBC'
115.47 + 'DSN=glpk;UID=glpk;PWD=gnu'
115.48 + 'SELECT * FROM sudoku'
115.49 + 'WHERE ID = ' & id :
115.50 + fields <- [COL, LIN], givens ~ VAL;
115.51 +
115.52 +var x{i in 1..9, j in 1..9, k in 1..9}, binary;
115.53 +/* x[i,j,k] = 1 means cell [i,j] is assigned number k */
115.54 +
115.55 +s.t. fa{i in 1..9, j in 1..9, k in 1..9: givens[i,j] != 0}:
115.56 + x[i,j,k] = (if givens[i,j] = k then 1 else 0);
115.57 +/* assign pre-defined numbers using the "givens" */
115.58 +
115.59 +s.t. fb{i in 1..9, j in 1..9}: sum{k in 1..9} x[i,j,k] = 1;
115.60 +/* each cell must be assigned exactly one number */
115.61 +
115.62 +s.t. fc{i in 1..9, k in 1..9}: sum{j in 1..9} x[i,j,k] = 1;
115.63 +/* cells in the same row must be assigned distinct numbers */
115.64 +
115.65 +s.t. fd{j in 1..9, k in 1..9}: sum{i in 1..9} x[i,j,k] = 1;
115.66 +/* cells in the same column must be assigned distinct numbers */
115.67 +
115.68 +s.t. fe{I in 1..9 by 3, J in 1..9 by 3, k in 1..9}:
115.69 + sum{i in I..I+2, j in J..J+2} x[i,j,k] = 1;
115.70 +/* cells in the same region must be assigned distinct numbers */
115.71 +
115.72 +/* there is no need for an objective function here */
115.73 +
115.74 +
115.75 +solve;
115.76 +
115.77 +table ta {(i, j) in {i1 in 1..9} cross {i2 in 1..9}} OUT
115.78 + 'iODBC' 'DSN=glpk;UID=glpk;PWD=gnu'
115.79 + 'DELETE FROM sudoku_solution'
115.80 + 'WHERE ID = ' & id & ';'
115.81 + 'INSERT INTO sudoku_solution'
115.82 + '(ID, COL, LIN, VAL)'
115.83 + 'VALUES(?, ?, ?, ?);' :
115.84 + id ~ ID, i ~ COL, j ~ LIN, (sum{k in 1..9} x[i,j,k] * k) ~ VAL;
115.85 +
115.86 +printf "\nSudoku to be solved\n";
115.87 +for {i in 1..9}
115.88 +{ for {0..0: i = 1 or i = 4 or i = 7}
115.89 + printf " +-------+-------+-------+\n";
115.90 + for {j in 1..9}
115.91 + { for {0..0: j = 1 or j = 4 or j = 7} printf(" |");
115.92 + printf " %d", givens[i,j];
115.93 + for {0..0: j = 9} printf(" |\n");
115.94 + }
115.95 + for {0..0: i = 9}
115.96 + printf " +-------+-------+-------+\n";
115.97 + }
115.98 +printf "\nSolution\n";
115.99 +for {i in 1..9}
115.100 +{ for {0..0: i = 1 or i = 4 or i = 7}
115.101 + printf " +-------+-------+-------+\n";
115.102 + for {j in 1..9}
115.103 + { for {0..0: j = 1 or j = 4 or j = 7} printf(" |");
115.104 + printf " %d", sum{k in 1..9} x[i,j,k] * k;
115.105 + for {0..0: j = 9} printf(" |\n");
115.106 + }
115.107 + for {0..0: i = 9}
115.108 + printf " +-------+-------+-------+\n";
115.109 +}
115.110 +
115.111 +data;
115.112 +
115.113 +param id := 1;
115.114 +end;
116.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
116.2 +++ b/examples/sql/transp.sql Mon Dec 06 13:09:21 2010 +0100
116.3 @@ -0,0 +1,45 @@
116.4 +CREATE DATABASE glpk;
116.5 +CREATE USER glpk@localhost IDENTIFIED BY 'gnu';
116.6 +GRANT ALL PRIVILEGES ON glpk.* TO glpk@localhost;
116.7 +USE glpk;
116.8 +# production capacity
116.9 +DROP TABLE transp_capa;
116.10 +CREATE TABLE transp_capa (
116.11 + PLANT TEXT(127),
116.12 + CAPA REAL,
116.13 + PRIMARY KEY ( PLANT(127) )
116.14 + );
116.15 +INSERT INTO transp_capa ( PLANT, CAPA ) VALUES ( 'Seattle', 350 );
116.16 +INSERT INTO transp_capa ( PLANT, CAPA ) VALUES ( 'San Diego', 600 );
116.17 +# demand
116.18 +DROP TABLE transp_demand;
116.19 +CREATE TABLE transp_demand (
116.20 + MARKET TEXT(127),
116.21 + DEMAND REAL,
116.22 + PRIMARY KEY ( MARKET(127) )
116.23 + );
116.24 +INSERT INTO transp_demand ( MARKET, DEMAND ) VALUES ( 'New York', 325 );
116.25 +INSERT INTO transp_demand ( MARKET, DEMAND ) VALUES ( 'Chicago', 300 );
116.26 +INSERT INTO transp_demand ( MARKET, DEMAND ) VALUES ( 'Topeka', 275 );
116.27 +# distance
116.28 +DROP TABLE transp_dist;
116.29 +CREATE TABLE transp_dist (
116.30 + LOC1 TEXT(127),
116.31 + LOC2 TEXT(127),
116.32 + DIST REAL,
116.33 + PRIMARY KEY ( LOC1(127), LOC2(127) )
116.34 + );
116.35 +INSERT INTO transp_dist ( LOC1, LOC2, DIST ) VALUES ( 'Seattle', 'New York', 2.5 );
116.36 +INSERT INTO transp_dist ( LOC1, LOC2, DIST ) VALUES ( 'Seattle', 'Chicago', 1.7 );
116.37 +INSERT INTO transp_dist ( LOC1, LOC2, DIST ) VALUES ( 'Seattle', 'Topeka', 1.8 );
116.38 +INSERT INTO transp_dist ( LOC1, LOC2, DIST ) VALUES ( 'San Diego', 'New York', 2.5 );
116.39 +INSERT INTO transp_dist ( LOC1, LOC2, DIST ) VALUES ( 'San Diego', 'Chicago', 1.8 );
116.40 +INSERT INTO transp_dist ( LOC1, LOC2, DIST ) VALUES ( 'San Diego', 'Topeka', 1.4 );
116.41 +# result
116.42 +DROP TABLE transp_result;
116.43 +CREATE TABLE transp_result (
116.44 + LOC1 TEXT(127),
116.45 + LOC2 TEXT(127),
116.46 + QUANTITY REAL,
116.47 + PRIMARY KEY ( LOC1(127), LOC2(127) )
116.48 + );
117.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
117.2 +++ b/examples/sql/transp_mysql.mod Mon Dec 06 13:09:21 2010 +0100
117.3 @@ -0,0 +1,71 @@
117.4 +# A TRANSPORTATION PROBLEM
117.5 +#
117.6 +# This problem finds a least cost shipping schedule that meets
117.7 +# requirements at markets and supplies at factories.
117.8 +#
117.9 +# References:
117.10 +# Dantzig G B, "Linear Programming and Extensions."
117.11 +# Princeton University Press, Princeton, New Jersey, 1963,
117.12 +# Chapter 3-3.
117.13 +
117.14 +set I;
117.15 +/* canning plants */
117.16 +
117.17 +param a{i in I};
117.18 +/* capacity of plant i in cases */
117.19 +
117.20 +table plants IN "MySQL"
117.21 + 'Database=glpk;UID=glpk;PWD=gnu'
117.22 + 'SELECT PLANT, CAPA AS CAPACITY FROM transp_capa' :
117.23 + I <- [ PLANT ], a ~ CAPACITY;
117.24 +
117.25 +set J;
117.26 +/* markets */
117.27 +
117.28 +param b{j in J};
117.29 +/* demand at market j in cases */
117.30 +
117.31 +table markets IN "MySQL"
117.32 + 'Database=glpk;UID=glpk;PWD=gnu'
117.33 + 'transp_demand' :
117.34 + J <- [ MARKET ], b ~ DEMAND;
117.35 +
117.36 +param d{i in I, j in J};
117.37 +/* distance in thousands of miles */
117.38 +
117.39 +table dist IN "MySQL"
117.40 + 'Database=glpk;UID=glpk;PWD=gnu'
117.41 + 'transp_dist' :
117.42 + [ LOC1, LOC2 ], d ~ DIST;
117.43 +
117.44 +param f;
117.45 +/* freight in dollars per case per thousand miles */
117.46 +
117.47 +param c{i in I, j in J} := f * d[i,j] / 1000;
117.48 +/* transport cost in thousands of dollars per case */
117.49 +
117.50 +var x{i in I, j in J} >= 0;
117.51 +/* shipment quantities in cases */
117.52 +
117.53 +minimize cost: sum{i in I, j in J} c[i,j] * x[i,j];
117.54 +/* total transportation costs in thousands of dollars */
117.55 +
117.56 +s.t. supply{i in I}: sum{j in J} x[i,j] <= a[i];
117.57 +/* observe supply limit at plant i */
117.58 +
117.59 +s.t. demand{j in J}: sum{i in I} x[i,j] >= b[j];
117.60 +/* satisfy demand at market j */
117.61 +
117.62 +solve;
117.63 +
117.64 +table result{i in I, j in J: x[i,j]} OUT "MySQL"
117.65 + 'Database=glpk;UID=glpk;PWD=gnu'
117.66 + 'DELETE FROM transp_result;'
117.67 + 'INSERT INTO transp_result VALUES (?,?,?)' :
117.68 + i ~ LOC1, j ~ LOC2, x[i,j] ~ QUANTITY;
117.69 +
117.70 +data;
117.71 +
117.72 +param f := 90;
117.73 +
117.74 +end;
118.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
118.2 +++ b/examples/sql/transp_odbc.mod Mon Dec 06 13:09:21 2010 +0100
118.3 @@ -0,0 +1,72 @@
118.4 +# A TRANSPORTATION PROBLEM
118.5 +#
118.6 +# This problem finds a least cost shipping schedule that meets
118.7 +# requirements at markets and supplies at factories.
118.8 +#
118.9 +# References:
118.10 +# Dantzig G B, "Linear Programming and Extensions."
118.11 +# Princeton University Press, Princeton, New Jersey, 1963,
118.12 +# Chapter 3-3.
118.13 +
118.14 +set I;
118.15 +/* canning plants */
118.16 +
118.17 +param a{i in I};
118.18 +/* capacity of plant i in cases */
118.19 +
118.20 +table plants IN "iODBC"
118.21 + 'DSN=glpk;UID=glpk;PWD=gnu'
118.22 + 'SELECT PLANT, CAPA AS CAPACITY'
118.23 + 'FROM transp_capa' :
118.24 + I <- [ PLANT ], a ~ CAPACITY;
118.25 +
118.26 +set J;
118.27 +/* markets */
118.28 +
118.29 +param b{j in J};
118.30 +/* demand at market j in cases */
118.31 +
118.32 +table markets IN "iODBC"
118.33 + 'DSN=glpk;UID=glpk;PWD=gnu'
118.34 + 'transp_demand' :
118.35 + J <- [ MARKET ], b ~ DEMAND;
118.36 +
118.37 +param d{i in I, j in J};
118.38 +/* distance in thousands of miles */
118.39 +
118.40 +table dist IN "iODBC"
118.41 + 'DSN=glpk;UID=glpk;PWD=gnu'
118.42 + 'transp_dist' :
118.43 + [ LOC1, LOC2 ], d ~ DIST;
118.44 +
118.45 +param f;
118.46 +/* freight in dollars per case per thousand miles */
118.47 +
118.48 +param c{i in I, j in J} := f * d[i,j] / 1000;
118.49 +/* transport cost in thousands of dollars per case */
118.50 +
118.51 +var x{i in I, j in J} >= 0;
118.52 +/* shipment quantities in cases */
118.53 +
118.54 +minimize cost: sum{i in I, j in J} c[i,j] * x[i,j];
118.55 +/* total transportation costs in thousands of dollars */
118.56 +
118.57 +s.t. supply{i in I}: sum{j in J} x[i,j] <= a[i];
118.58 +/* observe supply limit at plant i */
118.59 +
118.60 +s.t. demand{j in J}: sum{i in I} x[i,j] >= b[j];
118.61 +/* satisfy demand at market j */
118.62 +
118.63 +solve;
118.64 +
118.65 +table result{i in I, j in J: x[i,j]} OUT "iODBC"
118.66 + 'DSN=glpk;UID=glpk;PWD=gnu'
118.67 + 'DELETE FROM transp_result;'
118.68 + 'INSERT INTO transp_result VALUES (?,?,?)' :
118.69 + i ~ LOC1, j ~ LOC2, x[i,j] ~ QUANTITY;
118.70 +
118.71 +data;
118.72 +
118.73 +param f := 90;
118.74 +
118.75 +end;
119.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
119.2 +++ b/examples/stigler.mod Mon Dec 06 13:09:21 2010 +0100
119.3 @@ -0,0 +1,411 @@
119.4 +/* STIGLER, original Stigler's 1939 diet problem */
119.5 +
119.6 +/* The Stigler Diet is an optimization problem named for George Stigler,
119.7 + a 1982 Nobel Laureate in economics, who posed the following problem:
119.8 + For a moderately active man weighing 154 pounds, how much of each of
119.9 + 77 foods should be eaten on a daily basis so that the man's intake of
119.10 + nine nutrients will be at least equal to the recommended dietary
119.11 + allowances (RDSs) suggested by the National Research Council in 1943,
119.12 + with the cost of the diet being minimal?
119.13 +
119.14 + The nutrient RDAs required to be met in Stigler's experiment were
119.15 + calories, protein, calcium, iron, vitamin A, thiamine, riboflavin,
119.16 + niacin, and ascorbic acid. The result was an annual budget allocated
119.17 + to foods such as evaporated milk, cabbage, dried navy beans, and beef
119.18 + liver at a cost of approximately $0.11 a day in 1939 U.S. dollars.
119.19 +
119.20 + While the name "Stigler Diet" was applied after the experiment by
119.21 + outsiders, according to Stigler, "No one recommends these diets for
119.22 + anyone, let alone everyone." The Stigler diet has been much ridiculed
119.23 + for its lack of variety and palatability, however his methodology has
119.24 + received praise and is considered to be some of the earliest work in
119.25 + linear programming.
119.26 +
119.27 + The Stigler diet question is a linear programming problem. Lacking
119.28 + any sophisticated method of solving such a problem, Stigler was
119.29 + forced to utilize heuristic methods in order to find a solution. The
119.30 + diet question originally asked in which quantities a 154 pound male
119.31 + would have to consume 77 different foods in order to fulfill the
119.32 + recommended intake of 9 different nutrients while keeping expense at
119.33 + a minimum. Through "trial and error, mathematical insight and
119.34 + agility," Stigler was able to eliminate 62 of the foods from the
119.35 + original 77 (these foods were removed based because they lacked
119.36 + nutrients in comparison to the remaining 15). From the reduced list,
119.37 + Stigler calculated the required amounts of each of the remaining 15
119.38 + foods to arrive at a cost-minimizing solution to his question.
119.39 + According to Stigler's calculations, the annual cost of his solution
119.40 + was $39.93 in 1939 dollars. When corrected for inflation using the
119.41 + consumer price index, the cost of the diet in 2005 dollars is
119.42 + $561.43. The specific combination of foods and quantities is as
119.43 + follows:
119.44 +
119.45 + Stigler's 1939 Diet
119.46 +
119.47 + Food Annual Quantities Annual Cost
119.48 + ---------------- ----------------- -----------
119.49 + Wheat Flour 370 lb. $13.33
119.50 + Evaporated Milk 57 cans 3.84
119.51 + Cabbage 111 lb. 4.11
119.52 + Spinach 23 lb. 1.85
119.53 + Dried Navy Beans 285 lb. 16.80
119.54 + ----------------------------------------------
119.55 + Total Annual Cost $39.93
119.56 +
119.57 + The 9 nutrients that Stigler's diet took into consideration and their
119.58 + respective recommended daily amounts were:
119.59 +
119.60 + Table of nutrients considered in Stigler's diet
119.61 +
119.62 + Nutrient Daily Recommended Intake
119.63 + ------------------------- ------------------------
119.64 + Calories 3,000 Calories
119.65 + Protein 70 grams
119.66 + Calcium .8 grams
119.67 + Iron 12 milligrams
119.68 + Vitamin A 5,000 IU
119.69 + Thiamine (Vitamin B1) 1.8 milligrams
119.70 + Riboflavin (Vitamin B2) 2.7 milligrams
119.71 + Niacin 18 milligrams
119.72 + Ascorbic Acid (Vitamin C) 75 milligrams
119.73 +
119.74 + Seven years after Stigler made his initial estimates, the development
119.75 + of George Dantzig's Simplex algorithm made it possible to solve the
119.76 + problem without relying on heuristic methods. The exact value was
119.77 + determined to be $39.69 (using the original 1939 data). Dantzig's
119.78 + algorithm describes a method of traversing the vertices of a polytope
119.79 + of N+1 dimensions in order to find the optimal solution to a specific
119.80 + situation.
119.81 +
119.82 + (From Wikipedia, the free encyclopedia.) */
119.83 +
119.84 +/* Translated from GAMS by Andrew Makhorin <mao@gnu.org>.
119.85 +
119.86 + For the original GAMS model stigler1939.gms see [3].
119.87 +
119.88 + References:
119.89 +
119.90 + 1. George J. Stigler, "The Cost of Subsistence," J. Farm Econ. 27,
119.91 + 1945, pp. 303-14.
119.92 +
119.93 + 2. National Research Council, "Recommended Daily Allowances," Reprint
119.94 + and Circular Series No. 115, January, 1943.
119.95 +
119.96 + 3. Erwin Kalvelagen, "Model building with GAMS," Chapter 2, "Building
119.97 + linear programming models," pp. 128-34. */
119.98 +
119.99 +set C;
119.100 +/* commodities */
119.101 +
119.102 +check card(C) = 77;
119.103 +/* there must be 77 commodities */
119.104 +
119.105 +set N;
119.106 +/* nutrients */
119.107 +
119.108 +param data{c in C, {"price", "weight"} union N};
119.109 +/* nutritive values per dollar of expenditure */
119.110 +
119.111 +param allowance{n in N};
119.112 +/* recommended daily allowance for a moderately active man */
119.113 +
119.114 +var x{c in C}, >= 0;
119.115 +/* dollars of food to be purchased daily */
119.116 +
119.117 +s.t. nb{n in N}: sum{c in C} data[c,n] * x[c] >= allowance[n];
119.118 +/* nutrient balance */
119.119 +
119.120 +minimize cost: sum{c in C} x[c];
119.121 +/* total food bill */
119.122 +
119.123 +solve;
119.124 +
119.125 +param days := 365.25;
119.126 +/* days in a year */
119.127 +
119.128 +param commodity{c in C}, symbolic;
119.129 +
119.130 +param unit{c in C}, symbolic;
119.131 +
119.132 +printf "\n";
119.133 +printf "MINIMUM COST ANNUAL DIET\n";
119.134 +printf "\n";
119.135 +printf " Commodity Unit Quantity Cost \n";
119.136 +printf "------------------------- ---------- ---------- ----------\n";
119.137 +printf{c in C: x[c] != 0} "%-25s %10s %10.2f $%7.2f\n", commodity[c],
119.138 + unit[c], 100 * days * x[c] / data[c,"price"], days * x[c];
119.139 +printf " -----------------\n";
119.140 +printf " Total: $%7.2f\n",
119.141 + days * sum{c in C} x[c];
119.142 +printf "\n";
119.143 +
119.144 +data;
119.145 +
119.146 +param : C : commodity unit :=
119.147 +flour "Wheat Flour (Enriched)" "10 lb."
119.148 +macaroni "Macaroni" "1 lb."
119.149 +cereal "Wheat Cereal (Enriched)" "28 oz."
119.150 +cornflakes "Corn Flakes" "8 oz."
119.151 +cornmeal "Corn Meal" "1 lb."
119.152 +grits "Hominy Grits" "24 oz."
119.153 +rice "Rice" "1 lb."
119.154 +oats "Rolled Oats" "1 lb."
119.155 +whitebread "White Bread (Enriched)" "1 lb."
119.156 +wheatbread "Whole Wheat Bread" "1 lb."
119.157 +ryebread "Rye Bread" "1 lb."
119.158 +poundcake "Pound Cake" "1 lb."
119.159 +crackers "Soda Crackers" "1 lb."
119.160 +milk "Milk" "1 qt."
119.161 +evapmild "Evaporated Milk (can)" "14.5 oz."
119.162 +butter "Butter" "1 lb."
119.163 +margarine "Oleomargarine" "1 lb."
119.164 +eggs "Eggs" "1 doz."
119.165 +cheese "Cheese (Cheddar)" "1 lb."
119.166 +cream "Cream" "1/2 pt."
119.167 +peanutbutter "Peanut Butter" "1 lb."
119.168 +mayonnaise "Mayonnaise" "1/2 pt."
119.169 +crisco "Crisco" "1 lb."
119.170 +lard "Lard" "1 lb."
119.171 +sirloinsteak "Sirloin Steak" "1 lb."
119.172 +roundsteak "Round Steak" "1 lb."
119.173 +ribroast "Rib Roast" "1 lb."
119.174 +chuckroast "Chuck Roast" "1 lb."
119.175 +plate "Plate" "1 lb."
119.176 +liver "Liver (Beef)" "1 lb."
119.177 +lambleg "Leg of Lamb" "1 lb."
119.178 +lambchops "Lamb Chops (Rib)" "1 lb."
119.179 +porkchops "Pork Chops" "1 lb."
119.180 +porkroast "Pork Loin Roast" "1 lb."
119.181 +bacon "Bacon" "1 lb."
119.182 +ham "Ham - smoked" "1 lb."
119.183 +saltpork "Salt Pork" "1 lb."
119.184 +chicken "Roasting Chicken" "1 lb."
119.185 +veal "Veal Cutlets" "1 lb."
119.186 +salmon "Salmon, Pink (can)" "16 oz."
119.187 +apples "Apples" "1 lb."
119.188 +bananas "Bananas" "1 lb."
119.189 +lemons "Lemons" "1 doz."
119.190 +oranges "Oranges" "1 doz."
119.191 +greenbeans "Green Beans" "1 lb."
119.192 +cabbage "Cabbage" "1 lb."
119.193 +carrots "Carrots" "1 bunch"
119.194 +celery "Celery" "1 stalk"
119.195 +lettuce "Lettuce" "1 head"
119.196 +onions "Onions" "1 lb."
119.197 +potatoes "Potatoes" "15 lb."
119.198 +spinach "Spinach" "1 lb."
119.199 +sweetpotato "Sweet Potatoes" "1 lb."
119.200 +peaches "Peaches (can)" "No. 2 1/2"
119.201 +pears "Pears (can)" "No. 2 1/2"
119.202 +pineapple "Pineapple (can)" "No. 2 1/2"
119.203 +asparagus "Asparagus (can)" "No. 2"
119.204 +cannedgrbn "Grean Beans (can)" "No. 2"
119.205 +porkbeans "Pork and Beans (can)" "16 oz."
119.206 +corn "Corn (can)" "No. 2"
119.207 +peas "Peas (can)" "No. 2"
119.208 +tomatoes "Tomatoes (can)" "No. 2"
119.209 +tomatosoup "Tomato Soup (can)" "10 1/2 oz."
119.210 +driedpeach "Peaches, Dried" "1 lb."
119.211 +prunes "Prunes, Dried" "1 lb."
119.212 +raisins "Raisins, Dried" "15 oz."
119.213 +driedpeas "Peas, Dried" "1 lb."
119.214 +limabeans "Lima Beans, Dried" "1 lb."
119.215 +navybeans "Navy Beans, Dried" "1 lb."
119.216 +coffee "Coffee" "1 lb."
119.217 +tea "Tea" "1/4 lb."
119.218 +cocoa "Cocoa" "8 oz."
119.219 +chocolate "Chocolate" "8 oz."
119.220 +sugar "Sugar" "10 lb."
119.221 +cornsirup "Corn Sirup" "24 oz."
119.222 +molasses "Molasses" "18 oz."
119.223 +stawberry "Strawberry Preserve" "1 lb."
119.224 +;
119.225 +
119.226 +set N :=
119.227 +calories /* Calories, unit = 1000 */
119.228 +protein /* Protein, unit = grams */
119.229 +calcium /* Calcium, unit = grams */
119.230 +iron /* Iron, unit = milligrams */
119.231 +vitaminA /* Vitamin A, unit = 1000 International Units */
119.232 +thiamine /* Thiamine, Vit. B1, unit = milligrams */
119.233 +riboflavin /* Riboflavin, Vit. B2, unit = milligrams */
119.234 +niacin /* Niacin (Nicotinic Acid), unit = milligrams */
119.235 +ascorbicAcid /* Ascorbic Acid, Vit. C, unit = milligrams */
119.236 +;
119.237 +
119.238 +param data
119.239 +: price weight calories protein calcium iron :=
119.240 +# aug. 15 edible
119.241 +# 1939 per $1
119.242 +# (cents) (grams) (1000) (grams) (grams) (mg.)
119.243 +flour 36.0 12600 44.7 1411 2.0 365
119.244 +macaroni 14.1 3217 11.6 418 .7 54
119.245 +cereal 24.2 3280 11.8 377 14.4 175
119.246 +cornflakes 7.1 3194 11.4 252 .1 56
119.247 +cornmeal 4.6 9861 36.0 897 1.7 99
119.248 +grits 8.5 8005 28.6 680 .8 80
119.249 +rice 7.5 6048 21.2 460 .6 41
119.250 +oats 7.1 6389 25.3 907 5.1 341
119.251 +whitebread 7.9 5742 15.6 488 2.5 115
119.252 +wheatbread 9.1 4985 12.2 484 2.7 125
119.253 +ryebread 9.2 4930 12.4 439 1.1 82
119.254 +poundcake 24.8 1829 8.0 130 .4 31
119.255 +crackers 15.1 3004 12.5 288 .5 50
119.256 +milk 11.0 8867 6.1 310 10.5 18
119.257 +evapmild 6.7 6035 8.4 422 15.1 9
119.258 +butter 20.8 1473 10.8 9 .2 3
119.259 +margarine 16.1 2817 20.6 17 .6 6
119.260 +eggs 32.6 1857 2.9 238 1.0 52
119.261 +cheese 24.2 1874 7.4 448 16.4 19
119.262 +cream 14.1 1689 3.5 49 1.7 3
119.263 +peanutbutter 17.9 2534 15.7 661 1.0 48
119.264 +mayonnaise 16.7 1198 8.6 18 .2 8
119.265 +crisco 20.3 2234 20.1 0 .0 0
119.266 +lard 9.8 4628 41.7 0 .0 0
119.267 +sirloinsteak 39.6 1145 2.9 166 .1 34
119.268 +roundsteak 36.4 1246 2.2 214 .1 32
119.269 +ribroast 29.2 1553 3.4 213 .1 33
119.270 +chuckroast 22.6 2007 3.6 309 .2 46
119.271 +plate 14.6 3107 8.5 404 .2 62
119.272 +liver 26.8 1692 2.2 333 .2 139
119.273 +lambleg 27.6 1643 3.1 245 .1 20
119.274 +lambchops 36.6 1239 3.3 140 .1 15
119.275 +porkchops 30.7 1477 3.5 196 .2 80
119.276 +porkroast 24.2 1874 4.4 249 .3 37
119.277 +bacon 25.6 1772 10.4 152 .2 23
119.278 +ham 27.4 1655 6.7 212 .2 31
119.279 +saltpork 16.0 2835 18.8 164 .1 26
119.280 +chicken 30.3 1497 1.8 184 .1 30
119.281 +veal 42.3 1072 1.7 156 .1 24
119.282 +salmon 13.0 3489 5.8 705 6.8 45
119.283 +apples 4.4 9072 5.8 27 .5 36
119.284 +bananas 6.1 4982 4.9 60 .4 30
119.285 +lemons 26.0 2380 1.0 21 .5 14
119.286 +oranges 30.9 4439 2.2 40 1.1 18
119.287 +greenbeans 7.1 5750 2.4 138 3.7 80
119.288 +cabbage 3.7 8949 2.6 125 4.0 36
119.289 +carrots 4.7 6080 2.7 73 2.8 43
119.290 +celery 7.3 3915 .9 51 3.0 23
119.291 +lettuce 8.2 2247 .4 27 1.1 22
119.292 +onions 3.6 11844 5.8 166 3.8 59
119.293 +potatoes 34.0 16810 14.3 336 1.8 118
119.294 +spinach 8.1 4592 1.1 106 .0 138
119.295 +sweetpotato 5.1 7649 9.6 138 2.7 54
119.296 +peaches 16.8 4894 3.7 20 .4 10
119.297 +pears 20.4 4030 3.0 8 .3 8
119.298 +pineapple 21.3 3993 2.4 16 .4 8
119.299 +asparagus 27.7 1945 .4 33 .3 12
119.300 +cannedgrbn 10.0 5386 1.0 54 2.0 65
119.301 +porkbeans 7.1 6389 7.5 364 4.0 134
119.302 +corn 10.4 5452 5.2 136 .2 16
119.303 +peas 13.8 4109 2.3 136 .6 45
119.304 +tomatoes 8.6 6263 1.3 63 .7 38
119.305 +tomatosoup 7.6 3917 1.6 71 .6 43
119.306 +driedpeach 15.7 2889 8.5 87 1.7 173
119.307 +prunes 9.0 4284 12.8 99 2.5 154
119.308 +raisins 9.4 4524 13.5 104 2.5 136
119.309 +driedpeas 7.9 5742 20.0 1367 4.2 345
119.310 +limabeans 8.9 5097 17.4 1055 3.7 459
119.311 +navybeans 5.9 7688 26.9 1691 11.4 792
119.312 +coffee 22.4 2025 .0 0 .0 0
119.313 +tea 17.4 652 .0 0 .0 0
119.314 +cocoa 8.6 2637 8.7 237 3.0 72
119.315 +chocolate 16.2 1400 8.0 77 1.3 39
119.316 +sugar 51.7 8773 34.9 0 .0 0
119.317 +cornsirup 13.7 4996 14.7 0 .5 74
119.318 +molasses 13.6 3752 9.0 0 10.3 244
119.319 +stawberry 20.5 2213 6.4 11 .4 7
119.320 +
119.321 +: vitaminA thiamine riboflavin niacin ascorbicAcid :=
119.322 +# (1000 IU) (mg.) (mg.) (mg.) (mg.)
119.323 +flour .0 55.4 33.3 441 0
119.324 +macaroni .0 3.2 1.9 68 0
119.325 +cereal .0 14.4 8.8 114 0
119.326 +cornflakes .0 13.5 2.3 68 0
119.327 +cornmeal 30.9 17.4 7.9 106 0
119.328 +grits .0 10.6 1.6 110 0
119.329 +rice .0 2.0 4.8 60 0
119.330 +oats .0 37.1 8.9 64 0
119.331 +whitebread .0 13.8 8.5 126 0
119.332 +wheatbread .0 13.9 6.4 160 0
119.333 +ryebread .0 9.9 3.0 66 0
119.334 +poundcake 18.9 2.8 3.0 17 0
119.335 +crackers .0 .0 .0 0 0
119.336 +milk 16.8 4.0 16.0 7 177
119.337 +evapmild 26.0 3.0 23.5 11 60
119.338 +butter 44.2 .0 .2 2 0
119.339 +margarine 55.8 .2 .0 0 0
119.340 +eggs 18.6 2.8 6.5 1 0
119.341 +cheese 28.1 .8 10.3 4 0
119.342 +cream 16.9 .6 2.5 0 17
119.343 +peanutbutter .0 9.6 8.1 471 0
119.344 +mayonnaise 2.7 .4 .5 0 0
119.345 +crisco .0 .0 .0 0 0
119.346 +lard .2 .0 .5 5 0
119.347 +sirloinsteak .2 2.1 2.9 69 0
119.348 +roundsteak .4 2.5 2.4 87 0
119.349 +ribroast .0 .0 2.0 0 0
119.350 +chuckroast .4 1.0 4.0 120 0
119.351 +plate .0 .9 .0 0 0
119.352 +liver 169.2 6.4 50.8 316 525
119.353 +lambleg .0 2.8 3.0 86 0
119.354 +lambchops .0 1.7 2.7 54 0
119.355 +porkchops .0 17.4 2.7 60 0
119.356 +porkroast .0 18.2 3.6 79 0
119.357 +bacon .0 1.8 1.8 71 0
119.358 +ham .0 9.9 3.3 50 0
119.359 +saltpork .0 1.4 1.8 0 0
119.360 +chicken .1 .9 1.8 68 46
119.361 +veal .0 1.4 2.4 57 0
119.362 +salmon 3.5 1.0 4.9 209 0
119.363 +apples 7.3 3.6 2.7 5 544
119.364 +bananas 17.4 2.5 3.5 28 498
119.365 +lemons .0 .5 .0 4 952
119.366 +oranges 11.1 3.6 1.3 10 1993
119.367 +greenbeans 69.0 4.3 5.8 37 862
119.368 +cabbage 7.2 9.0 4.5 26 5369
119.369 +carrots 188.5 6.1 4.3 89 608
119.370 +celery .9 1.4 1.4 9 313
119.371 +lettuce 112.4 1.8 3.4 11 449
119.372 +onions 16.6 4.7 5.9 21 1184
119.373 +potatoes 6.7 29.4 7.1 198 2522
119.374 +spinach 918.4 5.7 13.8 33 2755
119.375 +sweetpotato 290.7 8.4 5.4 83 1912
119.376 +peaches 21.5 .5 1.0 31 196
119.377 +pears .8 .8 .8 5 81
119.378 +pineapple 2.0 2.8 .8 7 399
119.379 +asparagus 16.3 1.4 2.1 17 272
119.380 +cannedgrbn 53.9 1.6 4.3 32 431
119.381 +porkbeans 3.5 8.3 7.7 56 0
119.382 +corn 12.0 1.6 2.7 42 218
119.383 +peas 34.9 4.9 2.5 37 370
119.384 +tomatoes 53.2 3.4 2.5 36 1253
119.385 +tomatosoup 57.9 3.5 2.4 67 862
119.386 +driedpeach 86.8 1.2 4.3 55 57
119.387 +prunes 85.7 3.9 4.3 65 257
119.388 +raisins 4.5 6.3 1.4 24 136
119.389 +driedpeas 2.9 28.7 18.4 162 0
119.390 +limabeans 5.1 26.9 38.2 93 0
119.391 +navybeans .0 38.4 24.6 217 0
119.392 +coffee .0 4.0 5.1 50 0
119.393 +tea .0 .0 2.3 42 0
119.394 +cocoa .0 2.0 11.9 40 0
119.395 +chocolate .0 .9 3.4 14 0
119.396 +sugar .0 .0 .0 0 0
119.397 +cornsirup .0 .0 .0 5 0
119.398 +molasses .0 1.9 7.5 146 0
119.399 +stawberry .2 .2 .4 3 0
119.400 +;
119.401 +
119.402 +param allowance :=
119.403 +calories 3
119.404 +protein 70
119.405 +calcium .8
119.406 +iron 12
119.407 +vitaminA 5
119.408 +thiamine 1.8
119.409 +riboflavin 2.7
119.410 +niacin 18
119.411 +ascorbicAcid 75
119.412 +;
119.413 +
119.414 +end;
120.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
120.2 +++ b/examples/sudoku.dat Mon Dec 06 13:09:21 2010 +0100
120.3 @@ -0,0 +1,16 @@
120.4 +/* sudoku.dat, a hard Sudoku puzzle which causes branching */
120.5 +
120.6 +data;
120.7 +
120.8 +param givens : 1 2 3 4 5 6 7 8 9 :=
120.9 + 1 1 . . . . . 7 . .
120.10 + 2 . 2 . . . . 5 . .
120.11 + 3 6 . . 3 8 . . . .
120.12 + 4 . 7 8 . . . . . .
120.13 + 5 . . . 6 . 9 . . .
120.14 + 6 . . . . . . 1 4 .
120.15 + 7 . . . . 2 5 . . 9
120.16 + 8 . . 3 . . . . 6 .
120.17 + 9 . . 4 . . . . . 2 ;
120.18 +
120.19 +end;
121.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
121.2 +++ b/examples/sudoku.mod Mon Dec 06 13:09:21 2010 +0100
121.3 @@ -0,0 +1,84 @@
121.4 +/* SUDOKU, Number Placement Puzzle */
121.5 +
121.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
121.7 +
121.8 +/* Sudoku, also known as Number Place, is a logic-based placement
121.9 + puzzle. The aim of the canonical puzzle is to enter a numerical
121.10 + digit from 1 through 9 in each cell of a 9x9 grid made up of 3x3
121.11 + subgrids (called "regions"), starting with various digits given in
121.12 + some cells (the "givens"). Each row, column, and region must contain
121.13 + only one instance of each numeral.
121.14 +
121.15 + Example:
121.16 +
121.17 + +-------+-------+-------+
121.18 + | 5 3 . | . 7 . | . . . |
121.19 + | 6 . . | 1 9 5 | . . . |
121.20 + | . 9 8 | . . . | . 6 . |
121.21 + +-------+-------+-------+
121.22 + | 8 . . | . 6 . | . . 3 |
121.23 + | 4 . . | 8 . 3 | . . 1 |
121.24 + | 7 . . | . 2 . | . . 6 |
121.25 + +-------+-------+-------+
121.26 + | . 6 . | . . . | 2 8 . |
121.27 + | . . . | 4 1 9 | . . 5 |
121.28 + | . . . | . 8 . | . 7 9 |
121.29 + +-------+-------+-------+
121.30 +
121.31 + (From Wikipedia, the free encyclopedia.) */
121.32 +
121.33 +param givens{1..9, 1..9}, integer, >= 0, <= 9, default 0;
121.34 +/* the "givens" */
121.35 +
121.36 +var x{i in 1..9, j in 1..9, k in 1..9}, binary;
121.37 +/* x[i,j,k] = 1 means cell [i,j] is assigned number k */
121.38 +
121.39 +s.t. fa{i in 1..9, j in 1..9, k in 1..9: givens[i,j] != 0}:
121.40 + x[i,j,k] = (if givens[i,j] = k then 1 else 0);
121.41 +/* assign pre-defined numbers using the "givens" */
121.42 +
121.43 +s.t. fb{i in 1..9, j in 1..9}: sum{k in 1..9} x[i,j,k] = 1;
121.44 +/* each cell must be assigned exactly one number */
121.45 +
121.46 +s.t. fc{i in 1..9, k in 1..9}: sum{j in 1..9} x[i,j,k] = 1;
121.47 +/* cells in the same row must be assigned distinct numbers */
121.48 +
121.49 +s.t. fd{j in 1..9, k in 1..9}: sum{i in 1..9} x[i,j,k] = 1;
121.50 +/* cells in the same column must be assigned distinct numbers */
121.51 +
121.52 +s.t. fe{I in 1..9 by 3, J in 1..9 by 3, k in 1..9}:
121.53 + sum{i in I..I+2, j in J..J+2} x[i,j,k] = 1;
121.54 +/* cells in the same region must be assigned distinct numbers */
121.55 +
121.56 +/* there is no need for an objective function here */
121.57 +
121.58 +solve;
121.59 +
121.60 +for {i in 1..9}
121.61 +{ for {0..0: i = 1 or i = 4 or i = 7}
121.62 + printf " +-------+-------+-------+\n";
121.63 + for {j in 1..9}
121.64 + { for {0..0: j = 1 or j = 4 or j = 7} printf(" |");
121.65 + printf " %d", sum{k in 1..9} x[i,j,k] * k;
121.66 + for {0..0: j = 9} printf(" |\n");
121.67 + }
121.68 + for {0..0: i = 9}
121.69 + printf " +-------+-------+-------+\n";
121.70 +}
121.71 +
121.72 +data;
121.73 +
121.74 +/* These data correspond to the example above. */
121.75 +
121.76 +param givens : 1 2 3 4 5 6 7 8 9 :=
121.77 + 1 5 3 . . 7 . . . .
121.78 + 2 6 . . 1 9 5 . . .
121.79 + 3 . 9 8 . . . . 6 .
121.80 + 4 8 . . . 6 . . . 3
121.81 + 5 4 . . 8 . 3 . . 1
121.82 + 6 7 . . . 2 . . . 6
121.83 + 7 . 6 . . . . 2 8 .
121.84 + 8 . . . 4 1 9 . . 5
121.85 + 9 . . . . 8 . . 7 9 ;
121.86 +
121.87 +end;
122.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
122.2 +++ b/examples/t1.cs Mon Dec 06 13:09:21 2010 +0100
122.3 @@ -0,0 +1,99 @@
122.4 +/*Find the minimum value which satisfies the linear inequality:
122.5 + a*x + b*y >= 1 {a,b,x,y Integers} {a,b > 0} {a,b entered on command line}
122.6 +
122.7 + Nigel_Galloway@operamail.com
122.8 + February 2008
122.9 +*/
122.10 +using System;
122.11 +using System.Runtime.InteropServices;
122.12 +
122.13 +unsafe class GLPK{
122.14 + double *lp;
122.15 + public int a;
122.16 + public int b;
122.17 +
122.18 + const string glpkLibrary = "libglpk.so";
122.19 + readonly int GLP_FR = 1;
122.20 + readonly int GLP_IV = 2;
122.21 + readonly int GLP_DB = 4;
122.22 + struct ConstraintMatrix{
122.23 + public fixed int ia[3];
122.24 + public fixed int ja[3];
122.25 + public fixed double ar[3];
122.26 + }
122.27 + [DllImport(glpkLibrary, SetLastError=true)]
122.28 + static extern double* glp_create_prob();
122.29 + [DllImport(glpkLibrary, SetLastError=true)]
122.30 + static extern void glp_add_rows(double* lp, int rows);
122.31 + [DllImport(glpkLibrary, SetLastError=true)]
122.32 + static extern void glp_add_cols(double* lp, int cols);
122.33 + [DllImport(glpkLibrary, SetLastError=true)]
122.34 + static extern void glp_set_col_bnds(double* lp, int col, int bound_type, double lower_bound, double upper_bound);
122.35 + [DllImport(glpkLibrary, SetLastError=true)]
122.36 + static extern void glp_set_col_kind(double* lp, int col, int kind);
122.37 + [DllImport(glpkLibrary, SetLastError=true)]
122.38 + static extern void glp_load_matrix(double* lp, int elements, int* ia, int* ja, double* ar);
122.39 + public GLPK(int a, int b){
122.40 + this.a = a;
122.41 + this.b = b;
122.42 + lp = glp_create_prob();
122.43 + //Col 1 is x, Col 2 is y
122.44 + glp_add_rows(lp, 1);
122.45 + glp_add_cols(lp, 2);
122.46 + glp_set_col_bnds(lp, 1, GLP_FR, 0.0, 0.0);
122.47 + glp_set_col_bnds(lp, 2, GLP_FR, 0.0, 0.0);
122.48 + glp_set_col_kind(lp, 1, GLP_IV);
122.49 + glp_set_col_kind(lp, 2, GLP_IV);
122.50 + //Row 1 is a*x + b*y
122.51 + ConstraintMatrix CM = new ConstraintMatrix();
122.52 + CM.ia[1]=1; CM.ja[1]=1; CM.ar[1]=a;
122.53 + CM.ia[2]=1; CM.ja[2]=2; CM.ar[2]=b;
122.54 + glp_load_matrix(lp, 2, CM.ia, CM.ja, CM.ar);
122.55 + Console.WriteLine("Hello Nigel");
122.56 + }
122.57 +
122.58 + [DllImport(glpkLibrary, SetLastError=true)]
122.59 + static extern void glp_set_row_bnds(double* lp, int row, int bound_type, double lower_bound, double upper_bound);
122.60 + [DllImport(glpkLibrary, SetLastError=true)]
122.61 + static extern void glp_simplex(double* lp, void* options);
122.62 + [DllImport(glpkLibrary, SetLastError=true)]
122.63 + static extern void glp_intopt(double* lp, void* options);
122.64 + [DllImport(glpkLibrary, SetLastError=true)]
122.65 + static extern double glp_mip_col_val(double* lp, int col);
122.66 + public int betterGuess(int upper_bound){
122.67 + //Find a new guess less than the old guess: 1 <= (a*x + b*y) <= (old guess - 1)
122.68 + glp_set_row_bnds(lp, 1, GLP_DB, 1.0, ((double)upper_bound)-0.5);
122.69 + glp_simplex(lp, null);
122.70 + glp_intopt(lp, null);
122.71 + int x = (int)glp_mip_col_val(lp, 1);
122.72 + int y = (int)glp_mip_col_val(lp, 2);
122.73 + int nextGuess = a*x + b*y;
122.74 + Console.WriteLine("x = {0}, y = {1}, a*x + b*y = {2}",x,y,nextGuess);
122.75 + return nextGuess;
122.76 + }
122.77 +
122.78 + [DllImport(glpkLibrary, SetLastError=true)]
122.79 + static extern void glp_delete_prob(double* lp);
122.80 + ~GLPK(){
122.81 + glp_delete_prob(lp);
122.82 + Console.WriteLine("Goodbye Nigel");
122.83 + }
122.84 +
122.85 +}
122.86 +
122.87 +class test{
122.88 + static bool isMinimum(int a, int b, int guess){
122.89 + Console.WriteLine("Trying {0}",guess);
122.90 + if (a%guess > 0) return false;
122.91 + if (b%guess > 0) return false;
122.92 + Console.WriteLine("Solution is {0}",guess);
122.93 + return true;
122.94 + }
122.95 +
122.96 + public static void Main(string[] args){
122.97 + Console.WriteLine("a = {0}, b = {1}",args[0], args[1]);
122.98 + GLPK lp = new GLPK(Int32.Parse(args[0]),Int32.Parse(args[1]));
122.99 + int guess = (lp.a > lp.b) ? lp.b : lp.a;
122.100 + while (!isMinimum(lp.a,lp.b,guess)) guess = lp.betterGuess(guess);
122.101 + }
122.102 +}
123.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
123.2 +++ b/examples/tas.mod Mon Dec 06 13:09:21 2010 +0100
123.3 @@ -0,0 +1,486 @@
123.4 +/* TAS, Tail Assignment Problem */
123.5 +
123.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
123.7 +
123.8 +/* The Tail Assignment Problem (TAS) is to construct rosters for a set
123.9 + of aircrafts (tails), which cover all flights for a given scheduling
123.10 + period.
123.11 +
123.12 + This model includes only flight connection constraints while other
123.13 + constraints (for example, maintenance constraints) are ignored. Such
123.14 + simplification allows using a single commodity network to model the
123.15 + problem, where commodity corresponds to the set of aircrafts.
123.16 +
123.17 + Nodes of the network are activities. They include all flights plus
123.18 + two dummy nodes (activities): source node, s, corresponding to
123.19 + initial activity of each aircraft, and sink node t, corresponding to
123.20 + final activity of each aircraft. Arc v->v' exists in the network if
123.21 + and only if the same aircraft is able to operate activity v and then
123.22 + immediately activity v'. In partucular, arcs s->f and f->t exist for
123.23 + all flights f. Arcs f->f', where f and f' are some flights, exist
123.24 + only if the connection time (which is the difference between the
123.25 + departure time of f' and the arrival time of f) is not less than a
123.26 + given minimal connection time.
123.27 +
123.28 + Reference:
123.29 + M. Groenkvist, "The Tail Assignment Problem," Dept. of Comp. Sci.
123.30 + and Eng., Chalmers University of Technology and Goeteborg University,
123.31 + Goeteborg, Sweden, August 2005. */
123.32 +
123.33 +########################################################################
123.34 +
123.35 +param nf, integer, > 0;
123.36 +/* number of flights */
123.37 +
123.38 +set F := 1..nf;
123.39 +/* set of flights (for a given period from timetable) */
123.40 +
123.41 +param hub{f in F}, in {1, 2};
123.42 +/* hub[f] = 1: Sheremetyevo-1
123.43 + hub[f] = 2: Sheremetyevo-2 */
123.44 +
123.45 +param dest{f in F}, symbolic;
123.46 +/* destination airport (IATA code) */
123.47 +
123.48 +param fno1{f in F}, integer;
123.49 +/* first leg flight number */
123.50 +
123.51 +param dep1{f in F}, integer, >= 0;
123.52 +/* departure time from Sheremetyevo airport, in minutes */
123.53 +
123.54 +check{f in F: f < nf}: dep1[f] <= dep1[f+1];
123.55 +/* all flights must be ordered by ascending of the departure time */
123.56 +
123.57 +param arr1{f in F}, integer, >= 0;
123.58 +/* arrival time to destination airport, in minutes */
123.59 +
123.60 +param fno2{f in F}, integer;
123.61 +/* second leg flight number */
123.62 +
123.63 +param dep2{f in F}, integer, >= 0;
123.64 +/* departure time from destination airport, in minutes */
123.65 +
123.66 +param arr2{f in F}, integer, >= 0;
123.67 +/* arrival time to Sheremetyevo airport, in minutes */
123.68 +
123.69 +param mct1, integer, >= 0, default 80;
123.70 +/* minimal connection time (within SVO1 or SVO2), in minutes */
123.71 +
123.72 +param mct2, integer, >= 0, default 150;
123.73 +/* minimal connection time (between SVO1 and SVO2), in minutes */
123.74 +
123.75 +set E := setof{f in F, ff in F: arr2[f] + (if hub[f] = hub[ff] then
123.76 + mct1 else mct2) <= dep1[ff]} (f, ff);
123.77 +/* connection network; arc f->ff is in E, iff the same aircraft can be
123.78 + assigned to flight f and then immediately to flight ff */
123.79 +
123.80 +var s{f in F}, >= 0;
123.81 +/* s[f] is a flow from source node to node f */
123.82 +
123.83 +var x{(f,ff) in E}, >= 0;
123.84 +/* x[f,ff] is a flow from node f to node ff */
123.85 +
123.86 +var t{f in F}, >= 0;
123.87 +/* t[f] is a flow from node f to sink node */
123.88 +
123.89 +s.t. into{f in F}: s[f] + sum{(ff,f) in E} x[ff,f] = 1;
123.90 +/* exactly one aircraft must come into each node f */
123.91 +
123.92 +s.t. from{f in F}: t[f] + sum{(f,ff) in E} x[f,ff] = 1;
123.93 +/* exactly one aircraft must come from each node f */
123.94 +
123.95 +minimize obj: sum{f in F} s[f];
123.96 +/* minimize the number aircrafts sufficient to cover all flights */
123.97 +
123.98 +solve;
123.99 +
123.100 +########################################################################
123.101 +
123.102 +param na := floor(sum{f in F} s[f] + .5);
123.103 +/* minimal number of aircrafts found */
123.104 +
123.105 +printf "At least %d aircrafts needed\n", na;
123.106 +
123.107 +set A := 1..na;
123.108 +/* set of aircrafts */
123.109 +
123.110 +printf "Building rosters...\n";
123.111 +
123.112 +param tail{f in F}, in A, :=
123.113 +/* tail[f] is the number of an aircraft assigned to flight f */
123.114 +
123.115 + if f = 1 then 1
123.116 + /* assign aircraft 1 to the earliest flight */
123.117 +
123.118 + else if s[f] >= 0.9 then (max{ff in 1..f-1} tail[ff]) + 1
123.119 + /* if f is the first flight in a roster, assign to it a next
123.120 + aircraft */
123.121 +
123.122 + else sum{(ff,f) in E} tail[ff] * (if x[ff,f] >= 0.9 then 1);
123.123 + /* otherwise, assign to flight f the same aircraft, which is
123.124 + assigned to a preceding flight in the roster */
123.125 +
123.126 +########################################################################
123.127 +
123.128 +param file, symbolic, default "tas.ps";
123.129 +/* file to output the assignment chart in postscript format */
123.130 +
123.131 +param title, symbolic, default "(no title)";
123.132 +/* chart title */
123.133 +
123.134 +param left, default 25;
123.135 +/* left margin, in mm */
123.136 +
123.137 +param top, default 25;
123.138 +/* top margin, in mm */
123.139 +
123.140 +param right, default 20;
123.141 +/* right margin, in mm */
123.142 +
123.143 +param bottom, default 15;
123.144 +/* bottom margin, in mm */
123.145 +
123.146 +param sx := 297 - left - right;
123.147 +/* chart area horizontal size, in mm */
123.148 +
123.149 +param sy := 210 - top - bottom;
123.150 +/* chart area vertical size, in mm */
123.151 +
123.152 +param gap, default sy / (na - 1);
123.153 +/* gap between rosters, in mm */
123.154 +
123.155 +printf "Writing assignment chart to %s...\n", file;
123.156 +
123.157 +printf "%%!PS-Adobe-3.0\n" > file;
123.158 +printf "%%%%Title: Tail Assignment Chart\n" >> file;
123.159 +printf "%%%%Creator: GLPK MathProg\n" >> file;
123.160 +printf "%%%%BoundingBox: 0 0 595 842\n" >> file;
123.161 +printf "%%%%EndComments\n" >> file;
123.162 +printf "<</PageSize [595 842]>> setpagedevice\n" >> file;
123.163 +printf "72 25.4 div dup scale\n" >> file;
123.164 +printf "210 %.3f sub %.3f translate\n", bottom, left >> file;
123.165 +printf "90 rotate\n" >> file;
123.166 +
123.167 +printf "/HelveticaBold findfont 5 scalefont setfont\n" >> file;
123.168 +printf "%.3f %.3f moveto (%s) dup show\n", 0, sy + 5, title >> file;
123.169 +
123.170 +param period := floor((max{f in F} arr2[f]) / 60. + .5);
123.171 +/* period duration, in hours */
123.172 +
123.173 +/* vertical bars */
123.174 +printf ".8 .8 .8 setrgbcolor\n" >> file;
123.175 +for {tt in 0..period}
123.176 +{ printf "%s setlinewidth\n",
123.177 + if tt mod 24 = 0 then ".5" else "0" >> file;
123.178 + printf "newpath %.3f %.3f moveto %.3f %.3f lineto stroke\n",
123.179 + tt * (sx / period), 0, tt * (sx / period),
123.180 + sy + (if tt mod 24 = 0 then 2) >> file;
123.181 +}
123.182 +
123.183 +/* rosters */
123.184 +for {a in A}
123.185 +{ printf "0 0 0 setrgbcolor\n" >> file;
123.186 + printf "0 setlinewidth\n" >> file;
123.187 + printf "newpath %.3f %.3f moveto %.3f %.3f lineto stroke\n",
123.188 + 0, sy - gap * (a - 1), sx, sy - gap * (a - 1) >> file;
123.189 + printf "/Dingbats findfont 4 scalefont setfont\n" >> file;
123.190 + printf "%.3f %.3f moveto <28> dup show\n",
123.191 + -4, sy - gap * (a - 1) - 1.4, a >> file;
123.192 + printf "/Helvetica findfont 3 scalefont setfont\n" >> file;
123.193 + printf "%.3f %.3f moveto (%2d) dup show\n",
123.194 + -9, sy - gap * (a - 1) - 1.2, a >> file;
123.195 + for {f in F: tail[f] == a}
123.196 + { printf "0 0 %s setrgbcolor\n",
123.197 + if hub[f] = 1 then "0" else ".8" >> file;
123.198 + printf "1 setlinewidth\n" >> file;
123.199 + printf "newpath %.3f %.3f moveto %.3f %.3f lineto stroke\n",
123.200 + dep1[f] / 60 * (sx / period), sy - gap * (a - 1),
123.201 + arr2[f] / 60 * (sx / period), sy - gap * (a - 1) >> file;
123.202 + printf "/Helvetica findfont 1.8 scalefont setfont\n" >> file;
123.203 + printf "%.3f %.3f moveto (%02d:%02d %s) dup show\n",
123.204 + dep1[f] / 60 * (sx / period), sy - gap * (a - 1) + .8,
123.205 + (dep1[f] mod 1440) div 60, (dep1[f] mod 1440) mod 60,
123.206 + dest[f] >> file;
123.207 + printf "%.3f %.3f moveto (%d %02d:%02d) dup show\n",
123.208 + dep1[f] / 60 * (sx / period), sy - gap * (a - 1) - 2.1,
123.209 + fno1[f],
123.210 + (arr2[f] mod 1440) div 60, (arr2[f] mod 1440) mod 60 >> file;
123.211 + }
123.212 +}
123.213 +
123.214 +printf "showpage\n" >> file;
123.215 +printf "%%%%EOF\n" >> file;
123.216 +
123.217 +########################################################################
123.218 +
123.219 +data;
123.220 +
123.221 +param title := "Tu-154 [from 2008-08-18 to 2008-08-24]";
123.222 +
123.223 +param nf := 261;
123.224 +
123.225 +param : hub dest fno1 dep1 arr1 fno2 dep2 arr2 :=
123.226 + 1 1 IKT 743 195 520 744 610 970
123.227 + 2 1 OMS 815 205 405 816 485 700
123.228 + 3 1 CEK 897 205 360 898 430 595
123.229 + 4 1 KRR 763 260 400 764 480 610
123.230 + 5 2 SIP 133 280 420 134 500 620
123.231 + 6 2 BUD 131 290 450 132 520 675
123.232 + 7 1 AAQ 701 305 440 702 510 640
123.233 + 8 1 MRV 785 310 440 786 520 650
123.234 + 9 2 WAW 101 355 475 102 540 660
123.235 + 10 2 GYD 147 370 550 148 675 860
123.236 + 11 1 AER 869 385 530 870 655 795
123.237 + 12 1 KRR 765 430 560 766 630 760
123.238 + 13 1 AAQ 703 520 660 704 740 850
123.239 + 14 1 LED 845 530 620 846 690 775
123.240 + 15 1 KRR 767 540 675 768 765 895
123.241 + 16 2 KBP 183 665 760 184 850 940
123.242 + 17 1 MRV 787 755 905 788 985 1135
123.243 + 18 1 KRR 771 810 940 772 1030 1165
123.244 + 19 1 LED 849 825 900 850 960 1095
123.245 + 20 2 IST 209 880 1050 210 1120 1280
123.246 + 21 1 AER 873 885 1030 874 1760 1900
123.247 + 22 1 ASF 711 995 1145 712 1640 1795
123.248 + 23 2 ULN 563 995 1335 564 1415 1815
123.249 + 24 2 OTP 151 1020 1175 152 1800 1940
123.250 + 25 2 BEY 509 1025 1265 510 1350 1580
123.251 + 26 2 OSL 211 1060 1220 212 1860 2015
123.252 + 27 1 IKT 739 1085 1420 740 1510 1870
123.253 + 28 1 KRR 773 1095 1240 774 1620 1765
123.254 + 29 1 SGC 877 1120 1315 878 1395 1625
123.255 + 30 1 LED 857 1150 1230 858 1610 1690
123.256 + 31 1 CEK 899 1230 1385 900 1455 1620
123.257 + 32 1 PEE 821 1235 1390 822 1450 1600
123.258 + 33 2 TBS 197 1240 1405 198 1560 1715
123.259 + 34 1 UFA 891 1275 1405 892 1475 1610
123.260 + 35 1 KJA 781 1300 1570 782 1680 1990
123.261 + 36 1 IKT 743 1635 1960 744 2050 2410
123.262 + 37 1 OMS 815 1645 1845 816 1925 2140
123.263 + 38 1 CEK 897 1645 1800 898 1870 2035
123.264 + 39 1 KRR 763 1700 1840 764 1920 2050
123.265 + 40 2 SIP 133 1720 1860 134 1940 2060
123.266 + 41 2 BUD 131 1730 1890 132 1960 2115
123.267 + 42 1 AAQ 701 1745 1880 702 1950 2080
123.268 + 43 1 MRV 785 1750 1880 786 1960 2090
123.269 + 44 2 WAW 101 1795 1915 102 1980 2100
123.270 + 45 2 GYD 147 1810 1990 148 2115 2300
123.271 + 46 1 AER 869 1825 1970 870 2095 2235
123.272 + 47 2 EVN 193 1850 2030 194 2105 2275
123.273 + 48 1 KRR 765 1870 2000 766 2070 2200
123.274 + 49 1 AAQ 703 1960 2100 704 2180 2290
123.275 + 50 1 LED 845 1970 2060 846 2130 2215
123.276 + 51 1 KRR 767 1980 2115 768 2205 2335
123.277 + 52 2 KBP 183 2105 2200 184 2290 2380
123.278 + 53 1 MRV 787 2195 2345 788 2425 2575
123.279 + 54 1 KRR 771 2250 2380 772 2470 2605
123.280 + 55 1 LED 849 2265 2340 850 2400 2535
123.281 + 56 2 IST 209 2320 2490 210 2560 2720
123.282 + 57 1 AER 873 2325 2470 874 3200 3340
123.283 + 58 2 ULN 563 2435 2775 564 2855 3255
123.284 + 59 1 ASF 711 2435 2585 712 3080 3235
123.285 + 60 2 DAM 517 2465 2705 518 2790 3020
123.286 + 61 2 OSL 211 2500 2660 212 3300 3455
123.287 + 62 2 KBP 185 2510 2610 186 3160 3250
123.288 + 63 1 IKT 739 2525 2860 740 2950 3310
123.289 + 64 1 KRR 773 2535 2680 774 3060 3205
123.290 + 65 1 SGC 877 2560 2755 878 2835 3065
123.291 + 66 1 LED 857 2590 2670 858 3050 3130
123.292 + 67 1 CEK 899 2670 2825 900 2895 3060
123.293 + 68 1 PEE 821 2675 2830 822 2890 3040
123.294 + 69 2 TBS 197 2680 2845 198 3000 3155
123.295 + 70 1 UFA 891 2715 2845 892 2915 3050
123.296 + 71 1 KJA 781 2740 3010 782 3120 3430
123.297 + 72 1 IKT 743 3075 3400 744 3490 3850
123.298 + 73 1 CEK 897 3085 3240 898 3310 3475
123.299 + 74 1 OMS 815 3085 3285 816 3365 3580
123.300 + 75 1 KRR 763 3140 3280 764 3360 3490
123.301 + 76 2 SIP 133 3160 3300 134 3380 3500
123.302 + 77 2 BUD 131 3170 3330 132 3400 3555
123.303 + 78 1 AAQ 701 3185 3320 702 3390 3520
123.304 + 79 1 MRV 785 3190 3320 786 3400 3530
123.305 + 80 2 WAW 101 3235 3355 102 3420 3540
123.306 + 81 2 FRU 181 3245 3495 182 3590 3860
123.307 + 82 2 GYD 147 3250 3430 148 3555 3740
123.308 + 83 1 AER 869 3265 3410 870 3535 3675
123.309 + 84 1 KRR 765 3310 3440 766 3510 3640
123.310 + 85 1 AAQ 703 3400 3540 704 3620 3730
123.311 + 86 1 LED 845 3410 3500 846 3570 3655
123.312 + 87 1 KRR 767 3420 3555 768 3645 3775
123.313 + 88 2 KBP 183 3545 3640 184 3730 3820
123.314 + 89 1 MRV 787 3635 3785 788 3865 4015
123.315 + 90 1 KRR 771 3690 3820 772 3910 4045
123.316 + 91 1 LED 849 3705 3780 850 3840 3975
123.317 + 92 2 IST 209 3760 3930 210 4000 4160
123.318 + 93 1 AER 873 3765 3910 874 4640 4780
123.319 + 94 2 ULN 563 3875 4215 564 4295 4695
123.320 + 95 1 ASF 711 3875 4025 712 4520 4675
123.321 + 96 2 OTP 151 3900 4055 152 4680 4820
123.322 + 97 2 BEY 509 3905 4145 510 4230 4460
123.323 + 98 2 OSL 211 3940 4100 212 4740 4895
123.324 + 99 2 KBP 185 3950 4050 186 4600 4690
123.325 + 100 1 IKT 739 3965 4300 740 4390 4750
123.326 + 101 1 KRR 773 3975 4120 774 4500 4645
123.327 + 102 1 SGC 877 4000 4195 878 4275 4505
123.328 + 103 1 LED 857 4030 4110 858 4490 4570
123.329 + 104 1 CEK 899 4110 4265 900 4335 4500
123.330 + 105 1 PEE 821 4115 4270 822 4330 4480
123.331 + 106 2 TBS 197 4120 4285 198 4440 4595
123.332 + 107 1 UFA 891 4155 4285 892 4355 4490
123.333 + 108 1 KJA 781 4180 4450 782 4560 4870
123.334 + 109 1 IKT 743 4515 4840 744 4930 5290
123.335 + 110 1 OMS 815 4525 4725 816 4805 5020
123.336 + 111 1 CEK 897 4525 4680 898 4750 4915
123.337 + 112 1 KRR 763 4580 4720 764 4800 4930
123.338 + 113 2 SIP 133 4600 4740 134 4820 4940
123.339 + 114 2 BUD 131 4610 4770 132 4840 4995
123.340 + 115 1 AAQ 701 4625 4760 702 4830 4960
123.341 + 116 1 MRV 785 4630 4760 786 4840 4970
123.342 + 117 2 WAW 101 4675 4795 102 4860 4980
123.343 + 118 2 GYD 147 4690 4870 148 4995 5180
123.344 + 119 1 AER 869 4705 4850 870 4975 5115
123.345 + 120 2 EVN 193 4730 4910 194 4985 5155
123.346 + 121 1 KRR 765 4750 4880 766 4950 5080
123.347 + 122 1 AAQ 703 4840 4980 704 5060 5170
123.348 + 123 1 LED 845 4850 4940 846 5010 5095
123.349 + 124 1 KRR 767 4860 4995 768 5085 5215
123.350 + 125 2 KBP 183 4985 5080 184 5170 5260
123.351 + 126 1 MRV 787 5075 5225 788 5305 5455
123.352 + 127 1 KRR 771 5130 5260 772 5350 5485
123.353 + 128 1 LED 849 5145 5220 850 5280 5415
123.354 + 129 2 IST 209 5200 5370 210 5440 5600
123.355 + 130 1 AER 873 5205 5350 874 6080 6220
123.356 + 131 1 ASF 711 5315 5465 712 5960 6115
123.357 + 132 2 ULN 563 5315 5655 564 5735 6135
123.358 + 133 2 DAM 517 5345 5585 518 5670 5900
123.359 + 134 2 OSL 211 5380 5540 212 6180 6335
123.360 + 135 2 KBP 185 5390 5490 186 6040 6130
123.361 + 136 1 IKT 739 5405 5740 740 5830 6190
123.362 + 137 1 KRR 773 5415 5560 774 5940 6085
123.363 + 138 1 SGC 877 5440 5635 878 5715 5945
123.364 + 139 1 LED 857 5470 5550 858 5930 6010
123.365 + 140 1 CEK 899 5550 5705 900 5775 5940
123.366 + 141 1 PEE 821 5555 5710 822 5770 5920
123.367 + 142 2 TBS 197 5560 5725 198 5880 6035
123.368 + 143 1 UFA 891 5595 5725 892 5795 5930
123.369 + 144 1 KJA 781 5620 5890 782 6000 6310
123.370 + 145 1 IKT 743 5955 6280 744 6370 6730
123.371 + 146 1 OMS 815 5965 6165 816 6245 6460
123.372 + 147 1 CEK 897 5965 6120 898 6190 6355
123.373 + 148 1 KRR 763 6020 6160 764 6240 6370
123.374 + 149 2 SIP 133 6040 6180 134 6260 6380
123.375 + 150 2 BUD 131 6050 6210 132 6280 6435
123.376 + 151 1 AAQ 701 6065 6200 702 6270 6400
123.377 + 152 1 MRV 785 6070 6200 786 6280 6410
123.378 + 153 2 WAW 101 6115 6235 102 6300 6420
123.379 + 154 2 FRU 181 6125 6375 182 6470 6740
123.380 + 155 2 GYD 147 6130 6310 148 6435 6620
123.381 + 156 1 AER 869 6145 6290 870 6415 6555
123.382 + 157 2 EVN 193 6170 6350 194 6425 6595
123.383 + 158 1 KRR 765 6190 6320 766 6390 6520
123.384 + 159 1 AAQ 703 6280 6420 704 6500 6610
123.385 + 160 1 LED 845 6290 6380 846 6450 6535
123.386 + 161 1 KRR 767 6300 6435 768 6525 6655
123.387 + 162 2 KBP 183 6425 6520 184 6610 6700
123.388 + 163 2 AYT 223 6500 6690 224 6750 6940
123.389 + 164 1 AER 867 6510 6660 868 6730 6880
123.390 + 165 1 MRV 787 6515 6665 788 6745 6895
123.391 + 166 1 KRR 771 6570 6700 772 6790 6925
123.392 + 167 1 LED 849 6585 6660 850 6720 6855
123.393 + 168 2 IST 209 6640 6810 210 6880 7040
123.394 + 169 1 AER 873 6645 6790 874 7520 7660
123.395 + 170 1 ASF 711 6755 6905 712 7400 7555
123.396 + 171 2 ULN 563 6755 7095 564 7175 7575
123.397 + 172 2 OTP 151 6780 6935 152 7560 7700
123.398 + 173 2 BEY 509 6785 7025 510 7110 7340
123.399 + 174 2 OSL 211 6820 6980 212 7620 7775
123.400 + 175 2 KBP 185 6830 6930 186 7480 7570
123.401 + 176 1 IKT 739 6845 7180 740 7270 7630
123.402 + 177 1 KRR 773 6855 7000 774 7380 7525
123.403 + 178 1 SGC 877 6880 7075 878 7155 7385
123.404 + 179 1 LED 857 6910 6990 858 7370 7450
123.405 + 180 1 CEK 899 6990 7145 900 7215 7380
123.406 + 181 1 PEE 821 6995 7150 822 7210 7360
123.407 + 182 2 TBS 197 7000 7165 198 7320 7475
123.408 + 183 1 UFA 891 7035 7165 892 7235 7370
123.409 + 184 1 KJA 781 7060 7330 782 7440 7750
123.410 + 185 1 IKT 743 7395 7720 744 7810 8170
123.411 + 186 1 CEK 897 7405 7560 898 7630 7795
123.412 + 187 1 KRR 763 7460 7600 764 7680 7810
123.413 + 188 2 SIP 133 7480 7620 134 7700 7820
123.414 + 189 2 BUD 131 7490 7650 132 7720 7875
123.415 + 190 1 AAQ 701 7505 7640 702 7710 7840
123.416 + 191 1 MRV 785 7510 7640 786 7720 7850
123.417 + 192 2 IST 207 7545 7720 208 7795 7985
123.418 + 193 2 WAW 101 7555 7675 102 7740 7860
123.419 + 194 2 GYD 147 7570 7750 148 7875 8060
123.420 + 195 1 AER 869 7585 7730 870 7855 7995
123.421 + 196 2 AYT 221 7610 7800 222 7895 8085
123.422 + 197 2 EVN 193 7610 7790 194 7865 8035
123.423 + 198 1 KRR 765 7630 7760 766 7830 7960
123.424 + 199 1 AAQ 703 7720 7860 704 7940 8050
123.425 + 200 1 LED 845 7730 7820 846 7890 7975
123.426 + 201 1 KRR 767 7740 7875 768 7965 8095
123.427 + 202 2 KBP 183 7865 7960 184 8050 8140
123.428 + 203 2 AYT 223 7940 8130 224 8190 8380
123.429 + 204 1 MRV 787 7955 8105 788 8185 8335
123.430 + 205 1 KRR 771 8010 8140 772 8230 8365
123.431 + 206 1 LED 849 8025 8100 850 8160 8295
123.432 + 207 2 IST 209 8080 8250 210 8320 8480
123.433 + 208 1 AER 873 8085 8230 874 8960 9100
123.434 + 209 1 ASF 711 8195 8345 712 8840 8995
123.435 + 210 2 ULN 563 8195 8535 564 8615 9015
123.436 + 211 1 KJA 779 8230 8500 780 8575 8870
123.437 + 212 2 OSL 211 8260 8420 212 9060 9215
123.438 + 213 2 KBP 185 8270 8370 186 8920 9010
123.439 + 214 1 IKT 739 8285 8620 740 8710 9070
123.440 + 215 1 KRR 773 8295 8440 774 8820 8965
123.441 + 216 1 SGC 877 8320 8515 878 8595 8825
123.442 + 217 1 LED 857 8350 8430 858 8810 8890
123.443 + 218 1 CEK 899 8430 8585 900 8655 8820
123.444 + 219 1 PEE 821 8435 8590 822 8650 8800
123.445 + 220 2 TBS 197 8440 8605 198 8760 8915
123.446 + 221 1 UFA 891 8475 8605 892 8675 8810
123.447 + 222 1 KJA 781 8500 8770 782 8880 9190
123.448 + 223 1 IKT 743 8835 9160 744 9250 9610
123.449 + 224 1 OMS 815 8845 9045 816 9125 9340
123.450 + 225 1 CEK 897 8845 9000 898 9070 9235
123.451 + 226 1 KRR 763 8900 9040 764 9120 9250
123.452 + 227 2 SIP 133 8920 9060 134 9140 9260
123.453 + 228 2 BUD 131 8930 9090 132 9160 9315
123.454 + 229 1 AAQ 701 8945 9080 702 9150 9280
123.455 + 230 1 MRV 785 8950 9080 786 9160 9290
123.456 + 231 2 IST 207 8985 9160 208 9235 9425
123.457 + 232 2 WAW 101 8995 9115 102 9180 9300
123.458 + 233 2 FRU 181 9005 9255 182 9350 9620
123.459 + 234 2 GYD 147 9010 9190 148 9315 9500
123.460 + 235 1 AER 869 9025 9170 870 9295 9435
123.461 + 236 2 EVN 193 9050 9230 194 9305 9475
123.462 + 237 1 KRR 765 9070 9200 766 9270 9400
123.463 + 238 1 AAQ 703 9160 9300 704 9380 9490
123.464 + 239 1 LED 845 9170 9260 846 9330 9415
123.465 + 240 1 KRR 767 9180 9315 768 9405 9535
123.466 + 241 2 KBP 183 9305 9400 184 9490 9580
123.467 + 242 2 AYT 223 9380 9570 224 9630 9820
123.468 + 243 1 MRV 787 9395 9545 788 9625 9775
123.469 + 244 1 KRR 771 9450 9580 772 9670 9805
123.470 + 245 1 LED 849 9465 9540 850 9600 9735
123.471 + 246 2 IST 209 9520 9690 210 9760 9920
123.472 + 247 1 AER 873 9525 9670 874 10400 10540
123.473 + 248 1 ASF 711 9635 9785 712 10280 10435
123.474 + 249 2 ULN 563 9635 9975 564 10055 10455
123.475 + 250 2 OTP 151 9660 9815 152 10440 10580
123.476 + 251 2 DAM 517 9665 9905 518 9990 10220
123.477 + 252 2 OSL 211 9700 9860 212 10500 10655
123.478 + 253 2 KBP 185 9710 9810 186 10360 10450
123.479 + 254 1 IKT 739 9725 10060 740 10150 10510
123.480 + 255 1 KRR 773 9735 9880 774 10260 10405
123.481 + 256 1 SGC 877 9760 9955 878 10035 10265
123.482 + 257 1 LED 857 9790 9870 858 10250 10330
123.483 + 258 1 CEK 899 9870 10025 900 10095 10260
123.484 + 259 1 PEE 821 9875 10030 822 10090 10240
123.485 + 260 1 UFA 891 9915 10045 892 10115 10250
123.486 + 261 1 KJA 781 9940 10210 782 10320 10630
123.487 +;
123.488 +
123.489 +end;
124.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
124.2 +++ b/examples/todd.mod Mon Dec 06 13:09:21 2010 +0100
124.3 @@ -0,0 +1,36 @@
124.4 +/* TODD, a class of hard instances of zero-one knapsack problems */
124.5 +
124.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
124.7 +
124.8 +/* Chvatal describes a class of instances of zero-one knapsack problems
124.9 + due to Todd. He shows that a wide class of algorithms - including all
124.10 + based on branch and bound or dynamic programming - find it difficult
124.11 + to solve problems in the Todd class. More exactly, the time required
124.12 + by these algorithms to solve instances of problems that belong to the
124.13 + Todd class grows as an exponential function of the problem size.
124.14 +
124.15 + Reference:
124.16 + Chvatal V. (1980), Hard knapsack problems, Op. Res. 28, 1402-1411. */
124.17 +
124.18 +param n > 0 integer;
124.19 +
124.20 +param log2_n := log(n) / log(2);
124.21 +
124.22 +param k := floor(log2_n);
124.23 +
124.24 +param a{j in 1..n} := 2 ** (k + n + 1) + 2 ** (k + n + 1 - j) + 1;
124.25 +
124.26 +param b := 0.5 * floor(sum{j in 1..n} a[j]);
124.27 +
124.28 +var x{1..n} binary;
124.29 +
124.30 +maximize obj: sum{j in 1..n} a[j] * x[j];
124.31 +
124.32 +s.t. cap: sum{j in 1..n} a[j] * x[j] <= b;
124.33 +
124.34 +data;
124.35 +
124.36 +param n := 15;
124.37 +/* change this parameter to choose a particular instance */
124.38 +
124.39 +end;
125.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
125.2 +++ b/examples/train.mod Mon Dec 06 13:09:21 2010 +0100
125.3 @@ -0,0 +1,281 @@
125.4 +# TRAIN, a model of railroad passenger car allocation
125.5 +#
125.6 +# References:
125.7 +# Robert Fourer, David M. Gay and Brian W. Kernighan, "A Modeling Language
125.8 +# for Mathematical Programming." Management Science 36 (1990) 519-554.
125.9 +
125.10 +### SCHEDULE SETS AND PARAMETERS ###
125.11 +
125.12 +set cities;
125.13 +
125.14 +set links within {c1 in cities, c2 in cities: c1 <> c2};
125.15 +
125.16 + # Set of cities, and set of intercity links
125.17 +
125.18 +param last > 0 integer; # Number of time intervals in a day
125.19 +
125.20 +set times := 1..last; # Set of time intervals in a day
125.21 +
125.22 +set schedule within
125.23 + {c1 in cities, t1 in times,
125.24 + c2 in cities, t2 in times: (c1,c2) in links};
125.25 +
125.26 + # Member (c1,t1,c2,t2) of this set represents
125.27 + # a train that leaves city c1 at time t1
125.28 + # and arrives in city c2 at time t2
125.29 +
125.30 +### DEMAND PARAMETERS ###
125.31 +
125.32 +param section > 0 integer;
125.33 +
125.34 + # Maximum number of cars in one section of a train
125.35 +
125.36 +param demand {schedule} > 0;
125.37 +
125.38 + # For each scheduled train:
125.39 + # the smallest number of cars that
125.40 + # can meet demand for the train
125.41 +
125.42 +param low {(c1,t1,c2,t2) in schedule} := ceil(demand[c1,t1,c2,t2]);
125.43 +
125.44 + # Minimum number of cars needed to meet demand
125.45 +
125.46 +param high {(c1,t1,c2,t2) in schedule}
125.47 +
125.48 + := max (2, min (ceil(2*demand[c1,t1,c2,t2]),
125.49 + section*ceil(demand[c1,t1,c2,t2]/section) ));
125.50 +
125.51 + # Maximum number of cars allowed on a train:
125.52 + # 2 if demand is for less than one car;
125.53 + # otherwise, lesser of
125.54 + # number of cars needed to hold twice the demand, and
125.55 + # number of cars in minimum number of sections needed
125.56 +
125.57 +### DISTANCE PARAMETERS ###
125.58 +
125.59 +param dist_table {links} >= 0 default 0.0;
125.60 +
125.61 +param distance {(c1,c2) in links} > 0
125.62 + := if dist_table[c1,c2] > 0 then dist_table[c1,c2] else dist_table[c2,c1];
125.63 +
125.64 + # Inter-city distances: distance[c1,c2] is miles
125.65 + # between city c1 and city c2
125.66 +
125.67 +### VARIABLES ###
125.68 +
125.69 +var U 'cars stored' {cities,times} >= 0;
125.70 +
125.71 + # u[c,t] is the number of unused cars stored
125.72 + # at city c in the interval beginning at time t
125.73 +
125.74 +var X 'cars in train' {schedule} >= 0;
125.75 +
125.76 + # x[c1,t1,c2,t2] is the number of cars assigned to
125.77 + # the scheduled train that leaves c1 at t1 and
125.78 + # arrives in c2 at t2
125.79 +
125.80 +### OBJECTIVES ###
125.81 +
125.82 +minimize cars:
125.83 + sum {c in cities} U[c,last] +
125.84 + sum {(c1,t1,c2,t2) in schedule: t2 < t1} X[c1,t1,c2,t2];
125.85 +
125.86 + # Number of cars in the system:
125.87 + # sum of unused cars and cars in trains during
125.88 + # the last time interval of the day
125.89 +
125.90 +minimize miles:
125.91 + sum {(c1,t1,c2,t2) in schedule} distance[c1,c2] * X[c1,t1,c2,t2];
125.92 +
125.93 + # Total car-miles run by all scheduled trains in a day
125.94 +
125.95 +### CONSTRAINTS ###
125.96 +
125.97 +account {c in cities, t in times}:
125.98 +
125.99 + U[c,t] = U[c, if t > 1 then t-1 else last] +
125.100 +
125.101 + sum {(c1,t1,c,t) in schedule} X[c1,t1,c,t] -
125.102 + sum {(c,t,c2,t2) in schedule} X[c,t,c2,t2];
125.103 +
125.104 + # For every city and time:
125.105 + # unused cars in the present interval must equal
125.106 + # unused cars in the previous interval,
125.107 + # plus cars just arriving in trains,
125.108 + # minus cars just leaving in trains
125.109 +
125.110 +satisfy {(c1,t1,c2,t2) in schedule}:
125.111 +
125.112 + low[c1,t1,c2,t2] <= X[c1,t1,c2,t2] <= high[c1,t1,c2,t2];
125.113 +
125.114 + # For each scheduled train:
125.115 + # number of cars must meet demand,
125.116 + # but must not be so great that unnecessary
125.117 + # sections are run
125.118 +
125.119 +### DATA ###
125.120 +
125.121 +data;
125.122 +
125.123 +set cities := BO NY PH WA ;
125.124 +
125.125 +set links := (BO,NY) (NY,PH) (PH,WA)
125.126 + (NY,BO) (PH,NY) (WA,PH) ;
125.127 +
125.128 +param dist_table := [*,*] BO NY 232
125.129 + NY PH 90
125.130 + PH WA 135 ;
125.131 +
125.132 +param last := 48 ;
125.133 +
125.134 +param section := 14 ;
125.135 +
125.136 +set schedule :=
125.137 +
125.138 + (WA,*,PH,*) 2 5 6 9 8 11 10 13
125.139 + 12 15 13 16 14 17 15 18
125.140 + 16 19 17 20 18 21 19 22
125.141 + 20 23 21 24 22 25 23 26
125.142 + 24 27 25 28 26 29 27 30
125.143 + 28 31 29 32 30 33 31 34
125.144 + 32 35 33 36 34 37 35 38
125.145 + 36 39 37 40 38 41 39 42
125.146 + 40 43 41 44 42 45 44 47
125.147 + 46 1
125.148 +
125.149 + (PH,*,NY,*) 1 3 5 7 9 11 11 13
125.150 + 13 15 14 16 15 17 16 18
125.151 + 17 19 18 20 19 21 20 22
125.152 + 21 23 22 24 23 25 24 26
125.153 + 25 27 26 28 27 29 28 30
125.154 + 29 31 30 32 31 33 32 34
125.155 + 33 35 34 36 35 37 36 38
125.156 + 37 39 38 40 39 41 40 42
125.157 + 41 43 42 44 43 45 44 46
125.158 + 45 47 47 1
125.159 +
125.160 + (NY,*,BO,*) 10 16 12 18 14 20 15 21
125.161 + 16 22 17 23 18 24 19 25
125.162 + 20 26 21 27 22 28 23 29
125.163 + 24 30 25 31 26 32 27 33
125.164 + 28 34 29 35 30 36 31 37
125.165 + 32 38 33 39 34 40 35 41
125.166 + 36 42 37 43 38 44 39 45
125.167 + 40 46 41 47 42 48 43 1
125.168 + 44 2 45 3 46 4 48 6
125.169 +
125.170 + (BO,*,NY,*) 7 13 9 15 11 17 12 18
125.171 + 13 19 14 20 15 21 16 22
125.172 + 17 23 18 24 19 25 20 26
125.173 + 21 27 22 28 23 29 24 30
125.174 + 25 31 26 32 27 33 28 34
125.175 + 29 35 30 36 31 37 32 38
125.176 + 33 39 34 40 35 41 36 42
125.177 + 37 43 38 44 39 45 40 46
125.178 + 41 47 43 1 45 3 47 5
125.179 +
125.180 + (NY,*,PH,*) 1 3 12 14 13 15 14 16
125.181 + 15 17 16 18 17 19 18 20
125.182 + 19 21 20 22 21 23 22 24
125.183 + 23 25 24 26 25 27 26 28
125.184 + 27 29 28 30 29 31 30 32
125.185 + 31 33 32 34 33 35 34 36
125.186 + 35 37 36 38 37 39 38 40
125.187 + 39 41 40 42 41 43 42 44
125.188 + 43 45 44 46 45 47 46 48
125.189 + 47 1
125.190 +
125.191 + (PH,*,WA,*) 1 4 14 17 15 18 16 19
125.192 + 17 20 18 21 19 22 20 23
125.193 + 21 24 22 25 23 26 24 27
125.194 + 25 28 26 29 27 30 28 31
125.195 + 29 32 30 33 31 34 32 35
125.196 + 33 36 34 37 35 38 36 39
125.197 + 37 40 38 41 39 42 40 43
125.198 + 41 44 42 45 43 46 44 47
125.199 + 45 48 46 1 47 2 ;
125.200 +
125.201 +param demand :=
125.202 +
125.203 + [WA,*,PH,*] 2 5 .55 6 9 .01 8 11 .01
125.204 + 10 13 .13 12 15 1.59 13 16 1.69
125.205 + 14 17 5.19 15 18 3.55 16 19 6.29
125.206 + 17 20 4.00 18 21 5.80 19 22 3.40
125.207 + 20 23 4.88 21 24 2.92 22 25 4.37
125.208 + 23 26 2.80 24 27 4.23 25 28 2.88
125.209 + 26 29 4.33 27 30 3.11 28 31 4.64
125.210 + 29 32 3.44 30 33 4.95 31 34 3.73
125.211 + 32 35 5.27 33 36 3.77 34 37 4.80
125.212 + 35 38 3.31 36 39 3.89 37 40 2.65
125.213 + 38 41 3.01 39 42 2.04 40 43 2.31
125.214 + 41 44 1.52 42 45 1.75 44 47 1.88
125.215 + 46 1 1.05
125.216 +
125.217 + [PH,*,NY,*] 1 3 1.05 5 7 .43 9 11 .20
125.218 + 11 13 .21 13 15 .40 14 16 6.49
125.219 + 15 17 16.40 16 18 9.48 17 19 17.15
125.220 + 18 20 9.31 19 21 15.20 20 22 8.21
125.221 + 21 23 13.32 22 24 7.35 23 25 11.83
125.222 + 24 26 6.61 25 27 10.61 26 28 6.05
125.223 + 27 29 9.65 28 30 5.61 29 31 9.25
125.224 + 30 32 5.40 31 33 8.24 32 34 4.84
125.225 + 33 35 7.44 34 36 4.44 35 37 6.80
125.226 + 36 38 4.11 37 39 6.25 38 40 3.69
125.227 + 39 41 5.55 40 42 3.29 41 43 4.77
125.228 + 42 44 2.91 43 45 4.19 44 46 2.53
125.229 + 45 47 4.00 47 1 1.65
125.230 +
125.231 + [NY,*,BO,*] 10 16 1.23 12 18 3.84 14 20 4.08
125.232 + 15 21 1.47 16 22 2.96 17 23 1.60
125.233 + 18 24 2.95 19 25 1.71 20 26 2.81
125.234 + 21 27 1.77 22 28 2.87 23 29 1.84
125.235 + 24 30 2.95 25 31 1.91 26 32 3.12
125.236 + 27 33 1.93 28 34 3.31 29 35 2.00
125.237 + 30 36 3.40 31 37 2.08 32 38 3.41
125.238 + 33 39 2.69 34 40 4.45 35 41 2.32
125.239 + 36 42 3.40 37 43 1.80 38 44 2.63
125.240 + 39 45 1.52 40 46 2.23 41 47 1.25
125.241 + 42 48 1.79 43 1 .97 44 2 1.28
125.242 + 45 3 .48 46 4 .68 48 6 .08
125.243 +
125.244 + [BO,*,NY,*] 7 13 .03 9 15 1.29 11 17 4.59
125.245 + 12 18 2.56 13 19 3.92 14 20 2.37
125.246 + 15 21 3.81 16 22 2.24 17 23 3.51
125.247 + 18 24 2.13 19 25 3.28 20 26 2.05
125.248 + 21 27 3.15 22 28 1.99 23 29 3.09
125.249 + 24 30 1.93 25 31 3.19 26 32 1.91
125.250 + 27 33 3.21 28 34 1.85 29 35 3.21
125.251 + 30 36 1.71 31 37 3.04 32 38 2.08
125.252 + 33 39 3.13 34 40 1.96 35 41 2.53
125.253 + 36 42 1.43 37 43 2.04 38 44 1.12
125.254 + 39 45 1.71 40 46 .91 41 47 1.32
125.255 + 43 1 1.80 45 3 1.13 47 5 .23
125.256 +
125.257 + [NY,*,PH,*] 1 3 .04 12 14 4.68 13 15 5.61
125.258 + 14 16 3.56 15 17 5.81 16 18 3.81
125.259 + 17 19 6.31 18 20 4.07 19 21 7.33
125.260 + 20 22 4.55 21 23 7.37 22 24 4.73
125.261 + 23 25 7.61 24 26 4.92 25 27 7.91
125.262 + 26 28 5.19 27 29 8.40 28 30 5.53
125.263 + 29 31 9.32 30 32 5.51 31 33 10.33
125.264 + 32 34 9.21 33 35 18.95 34 36 11.23
125.265 + 35 37 16.85 36 38 7.29 37 39 10.89
125.266 + 38 40 5.41 39 41 8.21 40 42 4.52
125.267 + 41 43 6.99 42 44 3.92 43 45 6.21
125.268 + 44 46 3.44 45 47 5.17 46 48 2.55
125.269 + 47 1 1.24
125.270 +
125.271 + [PH,*,WA,*] 1 4 .20 14 17 4.49 15 18 3.53
125.272 + 16 19 2.67 17 20 3.83 18 21 3.01
125.273 + 19 22 4.12 20 23 3.15 21 24 4.67
125.274 + 22 25 3.20 23 26 4.23 24 27 2.87
125.275 + 25 28 3.84 26 29 2.60 27 30 3.80
125.276 + 28 31 2.77 29 32 4.31 30 33 3.16
125.277 + 31 34 4.88 32 35 3.45 33 36 5.55
125.278 + 34 37 3.52 35 38 6.11 36 39 3.32
125.279 + 37 40 5.53 38 41 3.03 39 42 4.51
125.280 + 40 43 2.53 41 44 3.39 42 45 1.93
125.281 + 43 46 2.52 44 47 1.20 45 48 1.75
125.282 + 46 1 .88 47 2 .87 ;
125.283 +
125.284 +end;
126.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
126.2 +++ b/examples/transp.mod Mon Dec 06 13:09:21 2010 +0100
126.3 @@ -0,0 +1,63 @@
126.4 +# A TRANSPORTATION PROBLEM
126.5 +#
126.6 +# This problem finds a least cost shipping schedule that meets
126.7 +# requirements at markets and supplies at factories.
126.8 +#
126.9 +# References:
126.10 +# Dantzig G B, "Linear Programming and Extensions."
126.11 +# Princeton University Press, Princeton, New Jersey, 1963,
126.12 +# Chapter 3-3.
126.13 +
126.14 +set I;
126.15 +/* canning plants */
126.16 +
126.17 +set J;
126.18 +/* markets */
126.19 +
126.20 +param a{i in I};
126.21 +/* capacity of plant i in cases */
126.22 +
126.23 +param b{j in J};
126.24 +/* demand at market j in cases */
126.25 +
126.26 +param d{i in I, j in J};
126.27 +/* distance in thousands of miles */
126.28 +
126.29 +param f;
126.30 +/* freight in dollars per case per thousand miles */
126.31 +
126.32 +param c{i in I, j in J} := f * d[i,j] / 1000;
126.33 +/* transport cost in thousands of dollars per case */
126.34 +
126.35 +var x{i in I, j in J} >= 0;
126.36 +/* shipment quantities in cases */
126.37 +
126.38 +minimize cost: sum{i in I, j in J} c[i,j] * x[i,j];
126.39 +/* total transportation costs in thousands of dollars */
126.40 +
126.41 +s.t. supply{i in I}: sum{j in J} x[i,j] <= a[i];
126.42 +/* observe supply limit at plant i */
126.43 +
126.44 +s.t. demand{j in J}: sum{i in I} x[i,j] >= b[j];
126.45 +/* satisfy demand at market j */
126.46 +
126.47 +data;
126.48 +
126.49 +set I := Seattle San-Diego;
126.50 +
126.51 +set J := New-York Chicago Topeka;
126.52 +
126.53 +param a := Seattle 350
126.54 + San-Diego 600;
126.55 +
126.56 +param b := New-York 325
126.57 + Chicago 300
126.58 + Topeka 275;
126.59 +
126.60 +param d : New-York Chicago Topeka :=
126.61 + Seattle 2.5 1.7 1.8
126.62 + San-Diego 2.5 1.8 1.4 ;
126.63 +
126.64 +param f := 90;
126.65 +
126.66 +end;
127.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
127.2 +++ b/examples/trick.mod Mon Dec 06 13:09:21 2010 +0100
127.3 @@ -0,0 +1,72 @@
127.4 +/* TRICK, A Transportation Design Problem */
127.5 +
127.6 +/* Translated from the Mosel modeling language to GNU MathProg by
127.7 + Andrew Makhorin <mao@gnu.org> */
127.8 +
127.9 +/* This example model is described in the article "Formulations and
127.10 + Reformulations in Integer Programming" by Michael Trick (it is
127.11 + publicly available at http://mat.gsia.cmu.edu/trick/formul04.pdf).
127.12 +
127.13 + This model demonstrates an amazing effect when including in the
127.14 + formulation an additional constraint, which is redundant even for
127.15 + LP relaxation, makes the model easy for solving with the B&B. */
127.16 +
127.17 +set TRUCKS := 1..10;
127.18 +
127.19 +set PACKAGES := 1..20;
127.20 +
127.21 +param capacity{TRUCKS};
127.22 +
127.23 +param size{PACKAGES};
127.24 +
127.25 +param cost{TRUCKS};
127.26 +
127.27 +param can_use{PACKAGES, TRUCKS};
127.28 +
127.29 +var x{PACKAGES, TRUCKS}, binary;
127.30 +
127.31 +var y{TRUCKS}, binary;
127.32 +
127.33 +minimize total: sum{i in TRUCKS} cost[i] * y[i];
127.34 +
127.35 +f1{i in TRUCKS}:
127.36 + sum{j in PACKAGES} size[j] * x[j,i] <= capacity[i] * y[i];
127.37 +
127.38 +f2{i in TRUCKS, j in PACKAGES}:
127.39 + x[j,i] <= y[i];
127.40 +
127.41 +f3{j in PACKAGES}:
127.42 + sum{i in TRUCKS} can_use[j,i] * x[j,i] = 1;
127.43 +
127.44 +redundant_constraint:
127.45 + sum{i in TRUCKS} capacity[i] * y[i] >= sum{j in PACKAGES} size[j];
127.46 +
127.47 +data;
127.48 +
127.49 +param capacity :=
127.50 + [1] 100 [2] 200 [3] 100 [4] 200 [5] 100 [6] 200 [7] 100 [8] 200
127.51 + [9] 100 [10] 200;
127.52 +
127.53 +param size :=
127.54 + [1] 17 [2] 21 [3] 54 [4] 45 [5] 87 [6] 34 [7] 23 [8] 45 [9] 12
127.55 + [10] 43 [11] 54 [12] 39 [13] 31 [14] 26 [15] 75 [16] 48 [17] 16
127.56 + [18] 32 [19] 45 [20] 55;
127.57 +
127.58 +param cost :=
127.59 + [1] 1 [2] 1.8 [3] 1 [4] 1.8 [5] 1 [6] 1.8 [7] 1 [8] 1.8 [9] 1
127.60 + [10] 1.8;
127.61 +
127.62 +param can_use (tr):
127.63 + 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 :=
127.64 + 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 0 0
127.65 + 2 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 0 0 0
127.66 + 3 0 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0
127.67 + 4 0 0 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 0 0
127.68 + 5 0 0 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 0
127.69 + 6 0 0 0 1 1 1 1 0 0 0 0 0 0 1 1 1 0 0 0 0
127.70 + 7 0 0 0 0 1 1 1 1 1 0 0 0 0 0 1 1 1 1 0 0
127.71 + 8 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1
127.72 + 9 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1
127.73 + 10 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 1;
127.74 +
127.75 +end;
128.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
128.2 +++ b/examples/tsp.mod Mon Dec 06 13:09:21 2010 +0100
128.3 @@ -0,0 +1,335 @@
128.4 +/* TSP, Traveling Salesman Problem */
128.5 +
128.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
128.7 +
128.8 +/* The Traveling Salesman Problem (TSP) is stated as follows.
128.9 + Let a directed graph G = (V, E) be given, where V = {1, ..., n} is
128.10 + a set of nodes, E <= V x V is a set of arcs. Let also each arc
128.11 + e = (i,j) be assigned a number c[i,j], which is the length of the
128.12 + arc e. The problem is to find a closed path of minimal length going
128.13 + through each node of G exactly once. */
128.14 +
128.15 +param n, integer, >= 3;
128.16 +/* number of nodes */
128.17 +
128.18 +set V := 1..n;
128.19 +/* set of nodes */
128.20 +
128.21 +set E, within V cross V;
128.22 +/* set of arcs */
128.23 +
128.24 +param c{(i,j) in E};
128.25 +/* distance from node i to node j */
128.26 +
128.27 +var x{(i,j) in E}, binary;
128.28 +/* x[i,j] = 1 means that the salesman goes from node i to node j */
128.29 +
128.30 +minimize total: sum{(i,j) in E} c[i,j] * x[i,j];
128.31 +/* the objective is to make the path length as small as possible */
128.32 +
128.33 +s.t. leave{i in V}: sum{(i,j) in E} x[i,j] = 1;
128.34 +/* the salesman leaves each node i exactly once */
128.35 +
128.36 +s.t. enter{j in V}: sum{(i,j) in E} x[i,j] = 1;
128.37 +/* the salesman enters each node j exactly once */
128.38 +
128.39 +/* Constraints above are not sufficient to describe valid tours, so we
128.40 + need to add constraints to eliminate subtours, i.e. tours which have
128.41 + disconnected components. Although there are many known ways to do
128.42 + that, I invented yet another way. The general idea is the following.
128.43 + Let the salesman sells, say, cars, starting the travel from node 1,
128.44 + where he has n cars. If we require the salesman to sell exactly one
128.45 + car in each node, he will need to go through all nodes to satisfy
128.46 + this requirement, thus, all subtours will be eliminated. */
128.47 +
128.48 +var y{(i,j) in E}, >= 0;
128.49 +/* y[i,j] is the number of cars, which the salesman has after leaving
128.50 + node i and before entering node j; in terms of the network analysis,
128.51 + y[i,j] is a flow through arc (i,j) */
128.52 +
128.53 +s.t. cap{(i,j) in E}: y[i,j] <= (n-1) * x[i,j];
128.54 +/* if arc (i,j) does not belong to the salesman's tour, its capacity
128.55 + must be zero; it is obvious that on leaving a node, it is sufficient
128.56 + to have not more than n-1 cars */
128.57 +
128.58 +s.t. node{i in V}:
128.59 +/* node[i] is a conservation constraint for node i */
128.60 +
128.61 + sum{(j,i) in E} y[j,i]
128.62 + /* summary flow into node i through all ingoing arcs */
128.63 +
128.64 + + (if i = 1 then n)
128.65 + /* plus n cars which the salesman has at starting node */
128.66 +
128.67 + = /* must be equal to */
128.68 +
128.69 + sum{(i,j) in E} y[i,j]
128.70 + /* summary flow from node i through all outgoing arcs */
128.71 +
128.72 + + 1;
128.73 + /* plus one car which the salesman sells at node i */
128.74 +
128.75 +solve;
128.76 +
128.77 +printf "Optimal tour has length %d\n",
128.78 + sum{(i,j) in E} c[i,j] * x[i,j];
128.79 +printf("From node To node Distance\n");
128.80 +printf{(i,j) in E: x[i,j]} " %3d %3d %8g\n",
128.81 + i, j, c[i,j];
128.82 +
128.83 +data;
128.84 +
128.85 +/* These data correspond to the symmetric instance ulysses16 from:
128.86 +
128.87 + Reinelt, G.: TSPLIB - A travelling salesman problem library.
128.88 + ORSA-Journal of the Computing 3 (1991) 376-84;
128.89 + http://elib.zib.de/pub/Packages/mp-testdata/tsp/tsplib */
128.90 +
128.91 +/* The optimal solution is 6859 */
128.92 +
128.93 +param n := 16;
128.94 +
128.95 +param : E : c :=
128.96 + 1 2 509
128.97 + 1 3 501
128.98 + 1 4 312
128.99 + 1 5 1019
128.100 + 1 6 736
128.101 + 1 7 656
128.102 + 1 8 60
128.103 + 1 9 1039
128.104 + 1 10 726
128.105 + 1 11 2314
128.106 + 1 12 479
128.107 + 1 13 448
128.108 + 1 14 479
128.109 + 1 15 619
128.110 + 1 16 150
128.111 + 2 1 509
128.112 + 2 3 126
128.113 + 2 4 474
128.114 + 2 5 1526
128.115 + 2 6 1226
128.116 + 2 7 1133
128.117 + 2 8 532
128.118 + 2 9 1449
128.119 + 2 10 1122
128.120 + 2 11 2789
128.121 + 2 12 958
128.122 + 2 13 941
128.123 + 2 14 978
128.124 + 2 15 1127
128.125 + 2 16 542
128.126 + 3 1 501
128.127 + 3 2 126
128.128 + 3 4 541
128.129 + 3 5 1516
128.130 + 3 6 1184
128.131 + 3 7 1084
128.132 + 3 8 536
128.133 + 3 9 1371
128.134 + 3 10 1045
128.135 + 3 11 2728
128.136 + 3 12 913
128.137 + 3 13 904
128.138 + 3 14 946
128.139 + 3 15 1115
128.140 + 3 16 499
128.141 + 4 1 312
128.142 + 4 2 474
128.143 + 4 3 541
128.144 + 4 5 1157
128.145 + 4 6 980
128.146 + 4 7 919
128.147 + 4 8 271
128.148 + 4 9 1333
128.149 + 4 10 1029
128.150 + 4 11 2553
128.151 + 4 12 751
128.152 + 4 13 704
128.153 + 4 14 720
128.154 + 4 15 783
128.155 + 4 16 455
128.156 + 5 1 1019
128.157 + 5 2 1526
128.158 + 5 3 1516
128.159 + 5 4 1157
128.160 + 5 6 478
128.161 + 5 7 583
128.162 + 5 8 996
128.163 + 5 9 858
128.164 + 5 10 855
128.165 + 5 11 1504
128.166 + 5 12 677
128.167 + 5 13 651
128.168 + 5 14 600
128.169 + 5 15 401
128.170 + 5 16 1033
128.171 + 6 1 736
128.172 + 6 2 1226
128.173 + 6 3 1184
128.174 + 6 4 980
128.175 + 6 5 478
128.176 + 6 7 115
128.177 + 6 8 740
128.178 + 6 9 470
128.179 + 6 10 379
128.180 + 6 11 1581
128.181 + 6 12 271
128.182 + 6 13 289
128.183 + 6 14 261
128.184 + 6 15 308
128.185 + 6 16 687
128.186 + 7 1 656
128.187 + 7 2 1133
128.188 + 7 3 1084
128.189 + 7 4 919
128.190 + 7 5 583
128.191 + 7 6 115
128.192 + 7 8 667
128.193 + 7 9 455
128.194 + 7 10 288
128.195 + 7 11 1661
128.196 + 7 12 177
128.197 + 7 13 216
128.198 + 7 14 207
128.199 + 7 15 343
128.200 + 7 16 592
128.201 + 8 1 60
128.202 + 8 2 532
128.203 + 8 3 536
128.204 + 8 4 271
128.205 + 8 5 996
128.206 + 8 6 740
128.207 + 8 7 667
128.208 + 8 9 1066
128.209 + 8 10 759
128.210 + 8 11 2320
128.211 + 8 12 493
128.212 + 8 13 454
128.213 + 8 14 479
128.214 + 8 15 598
128.215 + 8 16 206
128.216 + 9 1 1039
128.217 + 9 2 1449
128.218 + 9 3 1371
128.219 + 9 4 1333
128.220 + 9 5 858
128.221 + 9 6 470
128.222 + 9 7 455
128.223 + 9 8 1066
128.224 + 9 10 328
128.225 + 9 11 1387
128.226 + 9 12 591
128.227 + 9 13 650
128.228 + 9 14 656
128.229 + 9 15 776
128.230 + 9 16 933
128.231 + 10 1 726
128.232 + 10 2 1122
128.233 + 10 3 1045
128.234 + 10 4 1029
128.235 + 10 5 855
128.236 + 10 6 379
128.237 + 10 7 288
128.238 + 10 8 759
128.239 + 10 9 328
128.240 + 10 11 1697
128.241 + 10 12 333
128.242 + 10 13 400
128.243 + 10 14 427
128.244 + 10 15 622
128.245 + 10 16 610
128.246 + 11 1 2314
128.247 + 11 2 2789
128.248 + 11 3 2728
128.249 + 11 4 2553
128.250 + 11 5 1504
128.251 + 11 6 1581
128.252 + 11 7 1661
128.253 + 11 8 2320
128.254 + 11 9 1387
128.255 + 11 10 1697
128.256 + 11 12 1838
128.257 + 11 13 1868
128.258 + 11 14 1841
128.259 + 11 15 1789
128.260 + 11 16 2248
128.261 + 12 1 479
128.262 + 12 2 958
128.263 + 12 3 913
128.264 + 12 4 751
128.265 + 12 5 677
128.266 + 12 6 271
128.267 + 12 7 177
128.268 + 12 8 493
128.269 + 12 9 591
128.270 + 12 10 333
128.271 + 12 11 1838
128.272 + 12 13 68
128.273 + 12 14 105
128.274 + 12 15 336
128.275 + 12 16 417
128.276 + 13 1 448
128.277 + 13 2 941
128.278 + 13 3 904
128.279 + 13 4 704
128.280 + 13 5 651
128.281 + 13 6 289
128.282 + 13 7 216
128.283 + 13 8 454
128.284 + 13 9 650
128.285 + 13 10 400
128.286 + 13 11 1868
128.287 + 13 12 68
128.288 + 13 14 52
128.289 + 13 15 287
128.290 + 13 16 406
128.291 + 14 1 479
128.292 + 14 2 978
128.293 + 14 3 946
128.294 + 14 4 720
128.295 + 14 5 600
128.296 + 14 6 261
128.297 + 14 7 207
128.298 + 14 8 479
128.299 + 14 9 656
128.300 + 14 10 427
128.301 + 14 11 1841
128.302 + 14 12 105
128.303 + 14 13 52
128.304 + 14 15 237
128.305 + 14 16 449
128.306 + 15 1 619
128.307 + 15 2 1127
128.308 + 15 3 1115
128.309 + 15 4 783
128.310 + 15 5 401
128.311 + 15 6 308
128.312 + 15 7 343
128.313 + 15 8 598
128.314 + 15 9 776
128.315 + 15 10 622
128.316 + 15 11 1789
128.317 + 15 12 336
128.318 + 15 13 287
128.319 + 15 14 237
128.320 + 15 16 636
128.321 + 16 1 150
128.322 + 16 2 542
128.323 + 16 3 499
128.324 + 16 4 455
128.325 + 16 5 1033
128.326 + 16 6 687
128.327 + 16 7 592
128.328 + 16 8 206
128.329 + 16 9 933
128.330 + 16 10 610
128.331 + 16 11 2248
128.332 + 16 12 417
128.333 + 16 13 406
128.334 + 16 14 449
128.335 + 16 15 636
128.336 +;
128.337 +
128.338 +end;
129.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
129.2 +++ b/examples/xyacfs.mod Mon Dec 06 13:09:21 2010 +0100
129.3 @@ -0,0 +1,56 @@
129.4 +/*Extended Yet Another Curve Fitting Solution (The poor man's RMA)
129.5 +
129.6 + An extension of yacfs.mod adding a Weight parameter:
129.7 + When set to 1 the model produces best fit by least squares with all error in y and none in x (YonX);
129.8 + When set to zero the model produces best fit by least squares with all error in x and none in y (XonY);
129.9 + When set to 0.5 the model assumes equal error in x and y producing results similar to fitting by Reduced Major Axis Analysis.
129.10 +
129.11 + Nigel_Galloway@operamail.com
129.12 + November 5th., 2009
129.13 +*/
129.14 +set Sample;
129.15 +param Sx {z in Sample};
129.16 +param Sy {z in Sample};
129.17 +param Weight := 0.5;
129.18 +
129.19 +var a;
129.20 +var b;
129.21 +var p;
129.22 +var q;
129.23 +
129.24 +XonY1 :sum{z in Sample} q*Sy[z]*Sy[z] + sum{z in Sample} p*Sy[z] = sum{z in Sample} Sy[z]*Sx[z];
129.25 +XonY2 :sum{z in Sample} q*Sy[z] + sum{z in Sample} p = sum{z in Sample} Sx[z];
129.26 +YonX1 :sum{z in Sample} a*Sx[z]*Sx[z] + sum{z in Sample} b*Sx[z] = sum{z in Sample} Sy[z]*Sx[z];
129.27 +YonX2 :sum{z in Sample} a*Sx[z] + sum{z in Sample} b = sum{z in Sample} Sy[z];
129.28 +
129.29 +solve;
129.30 +
129.31 +param W := Weight*a + (1-Weight)*(1/q);
129.32 +printf "\nbest linear fit is:\n\ty = %f %s %fx\n\n", b*Weight - (1-Weight)*(p/q), if W < 0 then "-" else "+", abs(W);
129.33 +
129.34 +data;
129.35 +
129.36 +param:
129.37 +Sample: Sx Sy :=
129.38 + 1 0 1
129.39 + 2 0.5 0.9
129.40 + 3 1 0.7
129.41 + 4 1.5 1.5
129.42 + 5 1.9 2
129.43 + 6 2.5 2.4
129.44 + 7 3 3.2
129.45 + 8 3.5 2
129.46 + 9 4 2.7
129.47 + 10 4.5 3.5
129.48 + 11 5 1
129.49 + 12 5.5 4
129.50 + 13 6 3.6
129.51 + 14 6.6 2.7
129.52 + 15 7 5.7
129.53 + 16 7.6 4.6
129.54 + 17 8.5 6
129.55 + 18 9 6.8
129.56 + 19 10 7.3
129.57 +;
129.58 +
129.59 +end;
130.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
130.2 +++ b/examples/yacfs.mod Mon Dec 06 13:09:21 2010 +0100
130.3 @@ -0,0 +1,48 @@
130.4 +/*Yet Another Curve Fitting Solution
130.5 +
130.6 + Obviously this solution produces the same answer
130.7 + as examples/cflsq.mod
130.8 +
130.9 + Nigel_Galloway@operamail.com
130.10 + February 1st., 2009
130.11 +*/
130.12 +set Sample;
130.13 +param Sx {z in Sample};
130.14 +param Sy {z in Sample};
130.15 +
130.16 +var a;
130.17 +var b;
130.18 +
130.19 +equalz1 :sum{z in Sample} a*Sx[z]*Sx[z] + sum{z in Sample} b*Sx[z] = sum{z in Sample} Sy[z]*Sx[z];
130.20 +equalz2 :sum{z in Sample} a*Sx[z] + sum{z in Sample} b = sum{z in Sample} Sy[z];
130.21 +
130.22 +solve;
130.23 +
130.24 +printf "\nbest linear fit is:\n\ty = %f %s %fx\n\n", b, if a < 0 then "-" else "+", abs(a);
130.25 +
130.26 +data;
130.27 +
130.28 +param:
130.29 +Sample: Sx Sy :=
130.30 + 1 0 1
130.31 + 2 0.5 0.9
130.32 + 3 1 0.7
130.33 + 4 1.5 1.5
130.34 + 5 1.9 2
130.35 + 6 2.5 2.4
130.36 + 7 3 3.2
130.37 + 8 3.5 2
130.38 + 9 4 2.7
130.39 + 10 4.5 3.5
130.40 + 11 5 1
130.41 + 12 5.5 4
130.42 + 13 6 3.6
130.43 + 14 6.6 2.7
130.44 + 15 7 5.7
130.45 + 16 7.6 4.6
130.46 + 17 8.5 6
130.47 + 18 9 6.8
130.48 + 19 10 7.3
130.49 +;
130.50 +
130.51 +end;
131.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
131.2 +++ b/examples/zebra.mod Mon Dec 06 13:09:21 2010 +0100
131.3 @@ -0,0 +1,151 @@
131.4 +/* ZEBRA, Who Owns the Zebra? */
131.5 +
131.6 +/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
131.7 +
131.8 +########################################################################
131.9 +# The Zebra Puzzle is a well-known logic puzzle.
131.10 +#
131.11 +# It is often called "Einstein's Puzzle" or "Einstein's Riddle"
131.12 +# because it is said to have been invented by Albert Einstein as a boy,
131.13 +# with the common claim that Einstein said "only 2 percent of the
131.14 +# world's population can solve". It is also sometimes attributed to
131.15 +# Lewis Carroll. However, there is no known evidence for Einstein's or
131.16 +# Carroll's authorship.
131.17 +#
131.18 +# There are several versions of this puzzle. The version below is
131.19 +# quoted from the first known publication in Life International
131.20 +# magazine on December 17, 1962.
131.21 +#
131.22 +# 1. There are five houses.
131.23 +# 2. The Englishman lives in the red house.
131.24 +# 3. The Spaniard owns the dog.
131.25 +# 4. Coffee is drunk in the green house.
131.26 +# 5. The Ukrainian drinks tea.
131.27 +# 6. The green house is immediately to the right of the ivory house.
131.28 +# 7. The Old Gold smoker owns snails.
131.29 +# 8. Kools are smoked in the yellow house.
131.30 +# 9. Milk is drunk in the middle house.
131.31 +# 10. The Norwegian lives in the first house.
131.32 +# 11. The man who smokes Chesterfields lives in the house next to the
131.33 +# man with the fox.
131.34 +# 12. Kools are smoked in the house next to the house where the horse
131.35 +# is kept.
131.36 +# 13. The Lucky Strike smoker drinks orange juice.
131.37 +# 14. The Japanese smokes Parliaments.
131.38 +# 15. The Norwegian lives next to the blue house.
131.39 +#
131.40 +# Now, who drinks water? Who owns the zebra?
131.41 +#
131.42 +# In the interest of clarity, it must be added that each of the five
131.43 +# houses is painted a different color, and their inhabitants are of
131.44 +# different national extractions, own different pets, drink different
131.45 +# beverages and smoke different brands of American cigarettes. One
131.46 +# other thing: In statement 6, right means your right.
131.47 +#
131.48 +# (From Wikipedia, the free encyclopedia.)
131.49 +########################################################################
131.50 +
131.51 +set HOUSE := { 1..5 };
131.52 +
131.53 +set COLOR := { "blue", "green", "ivory", "red", "yellow" };
131.54 +
131.55 +set NATIONALITY := { "Englishman", "Japanese", "Norwegian", "Spaniard",
131.56 + "Ukranian" };
131.57 +
131.58 +set DRINK := { "coffee", "milk", "orange_juice", "tea", "water" };
131.59 +
131.60 +set SMOKE := { "Chesterfield", "Kools", "Lucky_Strike", "Old_Gold",
131.61 + "Parliament" };
131.62 +
131.63 +set PET := { "dog", "fox", "horse", "snails", "zebra" };
131.64 +
131.65 +var color{HOUSE, COLOR}, binary;
131.66 +c1{h in HOUSE}: sum{c in COLOR} color[h,c] = 1;
131.67 +c2{c in COLOR}: sum{h in HOUSE} color[h,c] = 1;
131.68 +
131.69 +var nationality{HOUSE, NATIONALITY}, binary;
131.70 +n1{h in HOUSE}: sum{n in NATIONALITY} nationality[h,n] = 1;
131.71 +n2{n in NATIONALITY}: sum{h in HOUSE} nationality[h,n] = 1;
131.72 +
131.73 +var drink{HOUSE, DRINK}, binary;
131.74 +d1{h in HOUSE}: sum{d in DRINK} drink[h,d] = 1;
131.75 +d2{d in DRINK}: sum{h in HOUSE} drink[h,d] = 1;
131.76 +
131.77 +var smoke{HOUSE, SMOKE}, binary;
131.78 +s1{h in HOUSE}: sum{s in SMOKE} smoke[h,s] = 1;
131.79 +s2{s in SMOKE}: sum{h in HOUSE} smoke[h,s] = 1;
131.80 +
131.81 +var pet{HOUSE, PET}, binary;
131.82 +p1{h in HOUSE}: sum{p in PET} pet[h,p] = 1;
131.83 +p2{p in PET}: sum{h in HOUSE} pet[h,p] = 1;
131.84 +
131.85 +/* the Englishman lives in the red house */
131.86 +f2{h in HOUSE}: nationality[h,"Englishman"] = color[h,"red"];
131.87 +
131.88 +/* the Spaniard owns the dog */
131.89 +f3{h in HOUSE}: nationality[h,"Spaniard"] = pet[h,"dog"];
131.90 +
131.91 +/* coffee is drunk in the green house */
131.92 +f4{h in HOUSE}: drink[h,"coffee"] = color[h,"green"];
131.93 +
131.94 +/* the Ukrainian drinks tea */
131.95 +f5{h in HOUSE}: nationality[h,"Ukranian"] = drink[h,"tea"];
131.96 +
131.97 +/* the green house is immediately to the right of the ivory house */
131.98 +f6{h in HOUSE}:
131.99 + color[h,"green"] = if h = 1 then 0 else color[h-1,"ivory"];
131.100 +
131.101 +/* the Old Gold smoker owns snails */
131.102 +f7{h in HOUSE}: smoke[h,"Old_Gold"] = pet[h,"snails"];
131.103 +
131.104 +/* Kools are smoked in the yellow house */
131.105 +f8{h in HOUSE}: smoke[h,"Kools"] = color[h,"yellow"];
131.106 +
131.107 +/* milk is drunk in the middle house */
131.108 +f9: drink[3,"milk"] = 1;
131.109 +
131.110 +/* the Norwegian lives in the first house */
131.111 +f10: nationality[1,"Norwegian"] = 1;
131.112 +
131.113 +/* the man who smokes Chesterfields lives in the house next to the man
131.114 + with the fox */
131.115 +f11{h in HOUSE}:
131.116 + (1 - smoke[h,"Chesterfield"]) +
131.117 + (if h = 1 then 0 else pet[h-1,"fox"]) +
131.118 + (if h = 5 then 0 else pet[h+1,"fox"]) >= 1;
131.119 +
131.120 +/* Kools are smoked in the house next to the house where the horse is
131.121 + kept */
131.122 +f12{h in HOUSE}:
131.123 + (1 - smoke[h,"Kools"]) +
131.124 + (if h = 1 then 0 else pet[h-1,"horse"]) +
131.125 + (if h = 5 then 0 else pet[h+1,"horse"]) >= 1;
131.126 +
131.127 +/* the Lucky Strike smoker drinks orange juice */
131.128 +f13{h in HOUSE}: smoke[h,"Lucky_Strike"] = drink[h,"orange_juice"];
131.129 +
131.130 +/* the Japanese smokes Parliaments */
131.131 +f14{h in HOUSE}: nationality[h,"Japanese"] = smoke[h,"Parliament"];
131.132 +
131.133 +/* the Norwegian lives next to the blue house */
131.134 +f15{h in HOUSE}:
131.135 + (1 - nationality[h,"Norwegian"]) +
131.136 + (if h = 1 then 0 else color[h-1,"blue"]) +
131.137 + (if h = 5 then 0 else color[h+1,"blue"]) >= 1;
131.138 +
131.139 +solve;
131.140 +
131.141 +printf "\n";
131.142 +printf "HOUSE COLOR NATIONALITY DRINK SMOKE PET\n";
131.143 +for {h in HOUSE}
131.144 +{ printf "%5d", h;
131.145 + printf{c in COLOR: color[h,c]} " %-6s", c;
131.146 + printf{n in NATIONALITY: nationality[h,n]} " %-11s", n;
131.147 + printf{d in DRINK: drink[h,d]} " %-12s", d;
131.148 + printf{s in SMOKE: smoke[h,s]} " %-12s", s;
131.149 + printf{p in PET: pet[h,p]} " %-6s", p;
131.150 + printf "\n";
131.151 +}
131.152 +printf "\n";
131.153 +
131.154 +end;
132.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
132.2 +++ b/include/Makefile.am Mon Dec 06 13:09:21 2010 +0100
132.3 @@ -0,0 +1,5 @@
132.4 +## Process this file with automake to produce Makefile.in ##
132.5 +
132.6 +include_HEADERS = glpk.h
132.7 +
132.8 +## eof ##
133.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
133.2 +++ b/include/glpk.h Mon Dec 06 13:09:21 2010 +0100
133.3 @@ -0,0 +1,1750 @@
133.4 +/* glpk.h */
133.5 +
133.6 +/***********************************************************************
133.7 +* This code is part of GLPK (GNU Linear Programming Kit).
133.8 +*
133.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
133.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
133.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
133.12 +* E-mail: <mao@gnu.org>.
133.13 +*
133.14 +* GLPK is free software: you can redistribute it and/or modify it
133.15 +* under the terms of the GNU General Public License as published by
133.16 +* the Free Software Foundation, either version 3 of the License, or
133.17 +* (at your option) any later version.
133.18 +*
133.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
133.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
133.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
133.22 +* License for more details.
133.23 +*
133.24 +* You should have received a copy of the GNU General Public License
133.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
133.26 +***********************************************************************/
133.27 +
133.28 +#ifndef GLPK_H
133.29 +#define GLPK_H
133.30 +
133.31 +#include <stdarg.h>
133.32 +#include <stddef.h>
133.33 +
133.34 +#ifdef __cplusplus
133.35 +extern "C" {
133.36 +#endif
133.37 +
133.38 +/* library version numbers: */
133.39 +#define GLP_MAJOR_VERSION 4
133.40 +#define GLP_MINOR_VERSION 45
133.41 +
133.42 +#ifndef GLP_PROB_DEFINED
133.43 +#define GLP_PROB_DEFINED
133.44 +typedef struct { double _opaque_prob[100]; } glp_prob;
133.45 +/* LP/MIP problem object */
133.46 +#endif
133.47 +
133.48 +/* optimization direction flag: */
133.49 +#define GLP_MIN 1 /* minimization */
133.50 +#define GLP_MAX 2 /* maximization */
133.51 +
133.52 +/* kind of structural variable: */
133.53 +#define GLP_CV 1 /* continuous variable */
133.54 +#define GLP_IV 2 /* integer variable */
133.55 +#define GLP_BV 3 /* binary variable */
133.56 +
133.57 +/* type of auxiliary/structural variable: */
133.58 +#define GLP_FR 1 /* free variable */
133.59 +#define GLP_LO 2 /* variable with lower bound */
133.60 +#define GLP_UP 3 /* variable with upper bound */
133.61 +#define GLP_DB 4 /* double-bounded variable */
133.62 +#define GLP_FX 5 /* fixed variable */
133.63 +
133.64 +/* status of auxiliary/structural variable: */
133.65 +#define GLP_BS 1 /* basic variable */
133.66 +#define GLP_NL 2 /* non-basic variable on lower bound */
133.67 +#define GLP_NU 3 /* non-basic variable on upper bound */
133.68 +#define GLP_NF 4 /* non-basic free variable */
133.69 +#define GLP_NS 5 /* non-basic fixed variable */
133.70 +
133.71 +/* scaling options: */
133.72 +#define GLP_SF_GM 0x01 /* perform geometric mean scaling */
133.73 +#define GLP_SF_EQ 0x10 /* perform equilibration scaling */
133.74 +#define GLP_SF_2N 0x20 /* round scale factors to power of two */
133.75 +#define GLP_SF_SKIP 0x40 /* skip if problem is well scaled */
133.76 +#define GLP_SF_AUTO 0x80 /* choose scaling options automatically */
133.77 +
133.78 +/* solution indicator: */
133.79 +#define GLP_SOL 1 /* basic solution */
133.80 +#define GLP_IPT 2 /* interior-point solution */
133.81 +#define GLP_MIP 3 /* mixed integer solution */
133.82 +
133.83 +/* solution status: */
133.84 +#define GLP_UNDEF 1 /* solution is undefined */
133.85 +#define GLP_FEAS 2 /* solution is feasible */
133.86 +#define GLP_INFEAS 3 /* solution is infeasible */
133.87 +#define GLP_NOFEAS 4 /* no feasible solution exists */
133.88 +#define GLP_OPT 5 /* solution is optimal */
133.89 +#define GLP_UNBND 6 /* solution is unbounded */
133.90 +
133.91 +typedef struct
133.92 +{ /* basis factorization control parameters */
133.93 + int msg_lev; /* (reserved) */
133.94 + int type; /* factorization type: */
133.95 +#define GLP_BF_FT 1 /* LUF + Forrest-Tomlin */
133.96 +#define GLP_BF_BG 2 /* LUF + Schur compl. + Bartels-Golub */
133.97 +#define GLP_BF_GR 3 /* LUF + Schur compl. + Givens rotation */
133.98 + int lu_size; /* luf.sv_size */
133.99 + double piv_tol; /* luf.piv_tol */
133.100 + int piv_lim; /* luf.piv_lim */
133.101 + int suhl; /* luf.suhl */
133.102 + double eps_tol; /* luf.eps_tol */
133.103 + double max_gro; /* luf.max_gro */
133.104 + int nfs_max; /* fhv.hh_max */
133.105 + double upd_tol; /* fhv.upd_tol */
133.106 + int nrs_max; /* lpf.n_max */
133.107 + int rs_size; /* lpf.v_size */
133.108 + double foo_bar[38]; /* (reserved) */
133.109 +} glp_bfcp;
133.110 +
133.111 +typedef struct
133.112 +{ /* simplex method control parameters */
133.113 + int msg_lev; /* message level: */
133.114 +#define GLP_MSG_OFF 0 /* no output */
133.115 +#define GLP_MSG_ERR 1 /* warning and error messages only */
133.116 +#define GLP_MSG_ON 2 /* normal output */
133.117 +#define GLP_MSG_ALL 3 /* full output */
133.118 +#define GLP_MSG_DBG 4 /* debug output */
133.119 + int meth; /* simplex method option: */
133.120 +#define GLP_PRIMAL 1 /* use primal simplex */
133.121 +#define GLP_DUALP 2 /* use dual; if it fails, use primal */
133.122 +#define GLP_DUAL 3 /* use dual simplex */
133.123 + int pricing; /* pricing technique: */
133.124 +#define GLP_PT_STD 0x11 /* standard (Dantzig rule) */
133.125 +#define GLP_PT_PSE 0x22 /* projected steepest edge */
133.126 + int r_test; /* ratio test technique: */
133.127 +#define GLP_RT_STD 0x11 /* standard (textbook) */
133.128 +#define GLP_RT_HAR 0x22 /* two-pass Harris' ratio test */
133.129 + double tol_bnd; /* spx.tol_bnd */
133.130 + double tol_dj; /* spx.tol_dj */
133.131 + double tol_piv; /* spx.tol_piv */
133.132 + double obj_ll; /* spx.obj_ll */
133.133 + double obj_ul; /* spx.obj_ul */
133.134 + int it_lim; /* spx.it_lim */
133.135 + int tm_lim; /* spx.tm_lim (milliseconds) */
133.136 + int out_frq; /* spx.out_frq */
133.137 + int out_dly; /* spx.out_dly (milliseconds) */
133.138 + int presolve; /* enable/disable using LP presolver */
133.139 + double foo_bar[36]; /* (reserved) */
133.140 +} glp_smcp;
133.141 +
133.142 +typedef struct
133.143 +{ /* interior-point solver control parameters */
133.144 + int msg_lev; /* message level (see glp_smcp) */
133.145 + int ord_alg; /* ordering algorithm: */
133.146 +#define GLP_ORD_NONE 0 /* natural (original) ordering */
133.147 +#define GLP_ORD_QMD 1 /* quotient minimum degree (QMD) */
133.148 +#define GLP_ORD_AMD 2 /* approx. minimum degree (AMD) */
133.149 +#define GLP_ORD_SYMAMD 3 /* approx. minimum degree (SYMAMD) */
133.150 + double foo_bar[48]; /* (reserved) */
133.151 +} glp_iptcp;
133.152 +
133.153 +#ifndef GLP_TREE_DEFINED
133.154 +#define GLP_TREE_DEFINED
133.155 +typedef struct { double _opaque_tree[100]; } glp_tree;
133.156 +/* branch-and-bound tree */
133.157 +#endif
133.158 +
133.159 +typedef struct
133.160 +{ /* integer optimizer control parameters */
133.161 + int msg_lev; /* message level (see glp_smcp) */
133.162 + int br_tech; /* branching technique: */
133.163 +#define GLP_BR_FFV 1 /* first fractional variable */
133.164 +#define GLP_BR_LFV 2 /* last fractional variable */
133.165 +#define GLP_BR_MFV 3 /* most fractional variable */
133.166 +#define GLP_BR_DTH 4 /* heuristic by Driebeck and Tomlin */
133.167 +#define GLP_BR_PCH 5 /* hybrid pseudocost heuristic */
133.168 + int bt_tech; /* backtracking technique: */
133.169 +#define GLP_BT_DFS 1 /* depth first search */
133.170 +#define GLP_BT_BFS 2 /* breadth first search */
133.171 +#define GLP_BT_BLB 3 /* best local bound */
133.172 +#define GLP_BT_BPH 4 /* best projection heuristic */
133.173 + double tol_int; /* mip.tol_int */
133.174 + double tol_obj; /* mip.tol_obj */
133.175 + int tm_lim; /* mip.tm_lim (milliseconds) */
133.176 + int out_frq; /* mip.out_frq (milliseconds) */
133.177 + int out_dly; /* mip.out_dly (milliseconds) */
133.178 + void (*cb_func)(glp_tree *T, void *info);
133.179 + /* mip.cb_func */
133.180 + void *cb_info; /* mip.cb_info */
133.181 + int cb_size; /* mip.cb_size */
133.182 + int pp_tech; /* preprocessing technique: */
133.183 +#define GLP_PP_NONE 0 /* disable preprocessing */
133.184 +#define GLP_PP_ROOT 1 /* preprocessing only on root level */
133.185 +#define GLP_PP_ALL 2 /* preprocessing on all levels */
133.186 + double mip_gap; /* relative MIP gap tolerance */
133.187 + int mir_cuts; /* MIR cuts (GLP_ON/GLP_OFF) */
133.188 + int gmi_cuts; /* Gomory's cuts (GLP_ON/GLP_OFF) */
133.189 + int cov_cuts; /* cover cuts (GLP_ON/GLP_OFF) */
133.190 + int clq_cuts; /* clique cuts (GLP_ON/GLP_OFF) */
133.191 + int presolve; /* enable/disable using MIP presolver */
133.192 + int binarize; /* try to binarize integer variables */
133.193 + int fp_heur; /* feasibility pump heuristic */
133.194 +#if 1 /* 28/V-2010 */
133.195 + int alien; /* use alien solver */
133.196 +#endif
133.197 + double foo_bar[29]; /* (reserved) */
133.198 +} glp_iocp;
133.199 +
133.200 +typedef struct
133.201 +{ /* additional row attributes */
133.202 + int level;
133.203 + /* subproblem level at which the row was added */
133.204 + int origin;
133.205 + /* row origin flag: */
133.206 +#define GLP_RF_REG 0 /* regular constraint */
133.207 +#define GLP_RF_LAZY 1 /* "lazy" constraint */
133.208 +#define GLP_RF_CUT 2 /* cutting plane constraint */
133.209 + int klass;
133.210 + /* row class descriptor: */
133.211 +#define GLP_RF_GMI 1 /* Gomory's mixed integer cut */
133.212 +#define GLP_RF_MIR 2 /* mixed integer rounding cut */
133.213 +#define GLP_RF_COV 3 /* mixed cover cut */
133.214 +#define GLP_RF_CLQ 4 /* clique cut */
133.215 + double foo_bar[7];
133.216 + /* (reserved) */
133.217 +} glp_attr;
133.218 +
133.219 +/* enable/disable flag: */
133.220 +#define GLP_ON 1 /* enable something */
133.221 +#define GLP_OFF 0 /* disable something */
133.222 +
133.223 +/* reason codes: */
133.224 +#define GLP_IROWGEN 0x01 /* request for row generation */
133.225 +#define GLP_IBINGO 0x02 /* better integer solution found */
133.226 +#define GLP_IHEUR 0x03 /* request for heuristic solution */
133.227 +#define GLP_ICUTGEN 0x04 /* request for cut generation */
133.228 +#define GLP_IBRANCH 0x05 /* request for branching */
133.229 +#define GLP_ISELECT 0x06 /* request for subproblem selection */
133.230 +#define GLP_IPREPRO 0x07 /* request for preprocessing */
133.231 +
133.232 +/* branch selection indicator: */
133.233 +#define GLP_NO_BRNCH 0 /* select no branch */
133.234 +#define GLP_DN_BRNCH 1 /* select down-branch */
133.235 +#define GLP_UP_BRNCH 2 /* select up-branch */
133.236 +
133.237 +/* return codes: */
133.238 +#define GLP_EBADB 0x01 /* invalid basis */
133.239 +#define GLP_ESING 0x02 /* singular matrix */
133.240 +#define GLP_ECOND 0x03 /* ill-conditioned matrix */
133.241 +#define GLP_EBOUND 0x04 /* invalid bounds */
133.242 +#define GLP_EFAIL 0x05 /* solver failed */
133.243 +#define GLP_EOBJLL 0x06 /* objective lower limit reached */
133.244 +#define GLP_EOBJUL 0x07 /* objective upper limit reached */
133.245 +#define GLP_EITLIM 0x08 /* iteration limit exceeded */
133.246 +#define GLP_ETMLIM 0x09 /* time limit exceeded */
133.247 +#define GLP_ENOPFS 0x0A /* no primal feasible solution */
133.248 +#define GLP_ENODFS 0x0B /* no dual feasible solution */
133.249 +#define GLP_EROOT 0x0C /* root LP optimum not provided */
133.250 +#define GLP_ESTOP 0x0D /* search terminated by application */
133.251 +#define GLP_EMIPGAP 0x0E /* relative mip gap tolerance reached */
133.252 +#define GLP_ENOFEAS 0x0F /* no primal/dual feasible solution */
133.253 +#define GLP_ENOCVG 0x10 /* no convergence */
133.254 +#define GLP_EINSTAB 0x11 /* numerical instability */
133.255 +#define GLP_EDATA 0x12 /* invalid data */
133.256 +#define GLP_ERANGE 0x13 /* result out of range */
133.257 +
133.258 +/* condition indicator: */
133.259 +#define GLP_KKT_PE 1 /* primal equalities */
133.260 +#define GLP_KKT_PB 2 /* primal bounds */
133.261 +#define GLP_KKT_DE 3 /* dual equalities */
133.262 +#define GLP_KKT_DB 4 /* dual bounds */
133.263 +#define GLP_KKT_CS 5 /* complementary slackness */
133.264 +
133.265 +/* MPS file format: */
133.266 +#define GLP_MPS_DECK 1 /* fixed (ancient) */
133.267 +#define GLP_MPS_FILE 2 /* free (modern) */
133.268 +
133.269 +typedef struct
133.270 +{ /* MPS format control parameters */
133.271 + int blank;
133.272 + /* character code to replace blanks in symbolic names */
133.273 + char *obj_name;
133.274 + /* objective row name */
133.275 + double tol_mps;
133.276 + /* zero tolerance for MPS data */
133.277 + double foo_bar[17];
133.278 + /* (reserved for use in the future) */
133.279 +} glp_mpscp;
133.280 +
133.281 +typedef struct
133.282 +{ /* CPLEX LP format control parameters */
133.283 + double foo_bar[20];
133.284 + /* (reserved for use in the future) */
133.285 +} glp_cpxcp;
133.286 +
133.287 +#ifndef GLP_TRAN_DEFINED
133.288 +#define GLP_TRAN_DEFINED
133.289 +typedef struct { double _opaque_tran[100]; } glp_tran;
133.290 +/* MathProg translator workspace */
133.291 +#endif
133.292 +
133.293 +glp_prob *glp_create_prob(void);
133.294 +/* create problem object */
133.295 +
133.296 +void glp_set_prob_name(glp_prob *P, const char *name);
133.297 +/* assign (change) problem name */
133.298 +
133.299 +void glp_set_obj_name(glp_prob *P, const char *name);
133.300 +/* assign (change) objective function name */
133.301 +
133.302 +void glp_set_obj_dir(glp_prob *P, int dir);
133.303 +/* set (change) optimization direction flag */
133.304 +
133.305 +int glp_add_rows(glp_prob *P, int nrs);
133.306 +/* add new rows to problem object */
133.307 +
133.308 +int glp_add_cols(glp_prob *P, int ncs);
133.309 +/* add new columns to problem object */
133.310 +
133.311 +void glp_set_row_name(glp_prob *P, int i, const char *name);
133.312 +/* assign (change) row name */
133.313 +
133.314 +void glp_set_col_name(glp_prob *P, int j, const char *name);
133.315 +/* assign (change) column name */
133.316 +
133.317 +void glp_set_row_bnds(glp_prob *P, int i, int type, double lb,
133.318 + double ub);
133.319 +/* set (change) row bounds */
133.320 +
133.321 +void glp_set_col_bnds(glp_prob *P, int j, int type, double lb,
133.322 + double ub);
133.323 +/* set (change) column bounds */
133.324 +
133.325 +void glp_set_obj_coef(glp_prob *P, int j, double coef);
133.326 +/* set (change) obj. coefficient or constant term */
133.327 +
133.328 +void glp_set_mat_row(glp_prob *P, int i, int len, const int ind[],
133.329 + const double val[]);
133.330 +/* set (replace) row of the constraint matrix */
133.331 +
133.332 +void glp_set_mat_col(glp_prob *P, int j, int len, const int ind[],
133.333 + const double val[]);
133.334 +/* set (replace) column of the constraint matrix */
133.335 +
133.336 +void glp_load_matrix(glp_prob *P, int ne, const int ia[],
133.337 + const int ja[], const double ar[]);
133.338 +/* load (replace) the whole constraint matrix */
133.339 +
133.340 +int glp_check_dup(int m, int n, int ne, const int ia[], const int ja[]);
133.341 +/* check for duplicate elements in sparse matrix */
133.342 +
133.343 +void glp_sort_matrix(glp_prob *P);
133.344 +/* sort elements of the constraint matrix */
133.345 +
133.346 +void glp_del_rows(glp_prob *P, int nrs, const int num[]);
133.347 +/* delete specified rows from problem object */
133.348 +
133.349 +void glp_del_cols(glp_prob *P, int ncs, const int num[]);
133.350 +/* delete specified columns from problem object */
133.351 +
133.352 +void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names);
133.353 +/* copy problem object content */
133.354 +
133.355 +void glp_erase_prob(glp_prob *P);
133.356 +/* erase problem object content */
133.357 +
133.358 +void glp_delete_prob(glp_prob *P);
133.359 +/* delete problem object */
133.360 +
133.361 +const char *glp_get_prob_name(glp_prob *P);
133.362 +/* retrieve problem name */
133.363 +
133.364 +const char *glp_get_obj_name(glp_prob *P);
133.365 +/* retrieve objective function name */
133.366 +
133.367 +int glp_get_obj_dir(glp_prob *P);
133.368 +/* retrieve optimization direction flag */
133.369 +
133.370 +int glp_get_num_rows(glp_prob *P);
133.371 +/* retrieve number of rows */
133.372 +
133.373 +int glp_get_num_cols(glp_prob *P);
133.374 +/* retrieve number of columns */
133.375 +
133.376 +const char *glp_get_row_name(glp_prob *P, int i);
133.377 +/* retrieve row name */
133.378 +
133.379 +const char *glp_get_col_name(glp_prob *P, int j);
133.380 +/* retrieve column name */
133.381 +
133.382 +int glp_get_row_type(glp_prob *P, int i);
133.383 +/* retrieve row type */
133.384 +
133.385 +double glp_get_row_lb(glp_prob *P, int i);
133.386 +/* retrieve row lower bound */
133.387 +
133.388 +double glp_get_row_ub(glp_prob *P, int i);
133.389 +/* retrieve row upper bound */
133.390 +
133.391 +int glp_get_col_type(glp_prob *P, int j);
133.392 +/* retrieve column type */
133.393 +
133.394 +double glp_get_col_lb(glp_prob *P, int j);
133.395 +/* retrieve column lower bound */
133.396 +
133.397 +double glp_get_col_ub(glp_prob *P, int j);
133.398 +/* retrieve column upper bound */
133.399 +
133.400 +double glp_get_obj_coef(glp_prob *P, int j);
133.401 +/* retrieve obj. coefficient or constant term */
133.402 +
133.403 +int glp_get_num_nz(glp_prob *P);
133.404 +/* retrieve number of constraint coefficients */
133.405 +
133.406 +int glp_get_mat_row(glp_prob *P, int i, int ind[], double val[]);
133.407 +/* retrieve row of the constraint matrix */
133.408 +
133.409 +int glp_get_mat_col(glp_prob *P, int j, int ind[], double val[]);
133.410 +/* retrieve column of the constraint matrix */
133.411 +
133.412 +void glp_create_index(glp_prob *P);
133.413 +/* create the name index */
133.414 +
133.415 +int glp_find_row(glp_prob *P, const char *name);
133.416 +/* find row by its name */
133.417 +
133.418 +int glp_find_col(glp_prob *P, const char *name);
133.419 +/* find column by its name */
133.420 +
133.421 +void glp_delete_index(glp_prob *P);
133.422 +/* delete the name index */
133.423 +
133.424 +void glp_set_rii(glp_prob *P, int i, double rii);
133.425 +/* set (change) row scale factor */
133.426 +
133.427 +void glp_set_sjj(glp_prob *P, int j, double sjj);
133.428 +/* set (change) column scale factor */
133.429 +
133.430 +double glp_get_rii(glp_prob *P, int i);
133.431 +/* retrieve row scale factor */
133.432 +
133.433 +double glp_get_sjj(glp_prob *P, int j);
133.434 +/* retrieve column scale factor */
133.435 +
133.436 +void glp_scale_prob(glp_prob *P, int flags);
133.437 +/* scale problem data */
133.438 +
133.439 +void glp_unscale_prob(glp_prob *P);
133.440 +/* unscale problem data */
133.441 +
133.442 +void glp_set_row_stat(glp_prob *P, int i, int stat);
133.443 +/* set (change) row status */
133.444 +
133.445 +void glp_set_col_stat(glp_prob *P, int j, int stat);
133.446 +/* set (change) column status */
133.447 +
133.448 +void glp_std_basis(glp_prob *P);
133.449 +/* construct standard initial LP basis */
133.450 +
133.451 +void glp_adv_basis(glp_prob *P, int flags);
133.452 +/* construct advanced initial LP basis */
133.453 +
133.454 +void glp_cpx_basis(glp_prob *P);
133.455 +/* construct Bixby's initial LP basis */
133.456 +
133.457 +int glp_simplex(glp_prob *P, const glp_smcp *parm);
133.458 +/* solve LP problem with the simplex method */
133.459 +
133.460 +int glp_exact(glp_prob *P, const glp_smcp *parm);
133.461 +/* solve LP problem in exact arithmetic */
133.462 +
133.463 +void glp_init_smcp(glp_smcp *parm);
133.464 +/* initialize simplex method control parameters */
133.465 +
133.466 +int glp_get_status(glp_prob *P);
133.467 +/* retrieve generic status of basic solution */
133.468 +
133.469 +int glp_get_prim_stat(glp_prob *P);
133.470 +/* retrieve status of primal basic solution */
133.471 +
133.472 +int glp_get_dual_stat(glp_prob *P);
133.473 +/* retrieve status of dual basic solution */
133.474 +
133.475 +double glp_get_obj_val(glp_prob *P);
133.476 +/* retrieve objective value (basic solution) */
133.477 +
133.478 +int glp_get_row_stat(glp_prob *P, int i);
133.479 +/* retrieve row status */
133.480 +
133.481 +double glp_get_row_prim(glp_prob *P, int i);
133.482 +/* retrieve row primal value (basic solution) */
133.483 +
133.484 +double glp_get_row_dual(glp_prob *P, int i);
133.485 +/* retrieve row dual value (basic solution) */
133.486 +
133.487 +int glp_get_col_stat(glp_prob *P, int j);
133.488 +/* retrieve column status */
133.489 +
133.490 +double glp_get_col_prim(glp_prob *P, int j);
133.491 +/* retrieve column primal value (basic solution) */
133.492 +
133.493 +double glp_get_col_dual(glp_prob *P, int j);
133.494 +/* retrieve column dual value (basic solution) */
133.495 +
133.496 +int glp_get_unbnd_ray(glp_prob *P);
133.497 +/* determine variable causing unboundedness */
133.498 +
133.499 +int glp_interior(glp_prob *P, const glp_iptcp *parm);
133.500 +/* solve LP problem with the interior-point method */
133.501 +
133.502 +void glp_init_iptcp(glp_iptcp *parm);
133.503 +/* initialize interior-point solver control parameters */
133.504 +
133.505 +int glp_ipt_status(glp_prob *P);
133.506 +/* retrieve status of interior-point solution */
133.507 +
133.508 +double glp_ipt_obj_val(glp_prob *P);
133.509 +/* retrieve objective value (interior point) */
133.510 +
133.511 +double glp_ipt_row_prim(glp_prob *P, int i);
133.512 +/* retrieve row primal value (interior point) */
133.513 +
133.514 +double glp_ipt_row_dual(glp_prob *P, int i);
133.515 +/* retrieve row dual value (interior point) */
133.516 +
133.517 +double glp_ipt_col_prim(glp_prob *P, int j);
133.518 +/* retrieve column primal value (interior point) */
133.519 +
133.520 +double glp_ipt_col_dual(glp_prob *P, int j);
133.521 +/* retrieve column dual value (interior point) */
133.522 +
133.523 +void glp_set_col_kind(glp_prob *P, int j, int kind);
133.524 +/* set (change) column kind */
133.525 +
133.526 +int glp_get_col_kind(glp_prob *P, int j);
133.527 +/* retrieve column kind */
133.528 +
133.529 +int glp_get_num_int(glp_prob *P);
133.530 +/* retrieve number of integer columns */
133.531 +
133.532 +int glp_get_num_bin(glp_prob *P);
133.533 +/* retrieve number of binary columns */
133.534 +
133.535 +int glp_intopt(glp_prob *P, const glp_iocp *parm);
133.536 +/* solve MIP problem with the branch-and-bound method */
133.537 +
133.538 +void glp_init_iocp(glp_iocp *parm);
133.539 +/* initialize integer optimizer control parameters */
133.540 +
133.541 +int glp_mip_status(glp_prob *P);
133.542 +/* retrieve status of MIP solution */
133.543 +
133.544 +double glp_mip_obj_val(glp_prob *P);
133.545 +/* retrieve objective value (MIP solution) */
133.546 +
133.547 +double glp_mip_row_val(glp_prob *P, int i);
133.548 +/* retrieve row value (MIP solution) */
133.549 +
133.550 +double glp_mip_col_val(glp_prob *P, int j);
133.551 +/* retrieve column value (MIP solution) */
133.552 +
133.553 +int glp_print_sol(glp_prob *P, const char *fname);
133.554 +/* write basic solution in printable format */
133.555 +
133.556 +int glp_read_sol(glp_prob *P, const char *fname);
133.557 +/* read basic solution from text file */
133.558 +
133.559 +int glp_write_sol(glp_prob *P, const char *fname);
133.560 +/* write basic solution to text file */
133.561 +
133.562 +int glp_print_ranges(glp_prob *P, int len, const int list[],
133.563 + int flags, const char *fname);
133.564 +/* print sensitivity analysis report */
133.565 +
133.566 +int glp_print_ipt(glp_prob *P, const char *fname);
133.567 +/* write interior-point solution in printable format */
133.568 +
133.569 +int glp_read_ipt(glp_prob *P, const char *fname);
133.570 +/* read interior-point solution from text file */
133.571 +
133.572 +int glp_write_ipt(glp_prob *P, const char *fname);
133.573 +/* write interior-point solution to text file */
133.574 +
133.575 +int glp_print_mip(glp_prob *P, const char *fname);
133.576 +/* write MIP solution in printable format */
133.577 +
133.578 +int glp_read_mip(glp_prob *P, const char *fname);
133.579 +/* read MIP solution from text file */
133.580 +
133.581 +int glp_write_mip(glp_prob *P, const char *fname);
133.582 +/* write MIP solution to text file */
133.583 +
133.584 +int glp_bf_exists(glp_prob *P);
133.585 +/* check if the basis factorization exists */
133.586 +
133.587 +int glp_factorize(glp_prob *P);
133.588 +/* compute the basis factorization */
133.589 +
133.590 +int glp_bf_updated(glp_prob *P);
133.591 +/* check if the basis factorization has been updated */
133.592 +
133.593 +void glp_get_bfcp(glp_prob *P, glp_bfcp *parm);
133.594 +/* retrieve basis factorization control parameters */
133.595 +
133.596 +void glp_set_bfcp(glp_prob *P, const glp_bfcp *parm);
133.597 +/* change basis factorization control parameters */
133.598 +
133.599 +int glp_get_bhead(glp_prob *P, int k);
133.600 +/* retrieve the basis header information */
133.601 +
133.602 +int glp_get_row_bind(glp_prob *P, int i);
133.603 +/* retrieve row index in the basis header */
133.604 +
133.605 +int glp_get_col_bind(glp_prob *P, int j);
133.606 +/* retrieve column index in the basis header */
133.607 +
133.608 +void glp_ftran(glp_prob *P, double x[]);
133.609 +/* perform forward transformation (solve system B*x = b) */
133.610 +
133.611 +void glp_btran(glp_prob *P, double x[]);
133.612 +/* perform backward transformation (solve system B'*x = b) */
133.613 +
133.614 +int glp_warm_up(glp_prob *P);
133.615 +/* "warm up" LP basis */
133.616 +
133.617 +int glp_eval_tab_row(glp_prob *P, int k, int ind[], double val[]);
133.618 +/* compute row of the simplex tableau */
133.619 +
133.620 +int glp_eval_tab_col(glp_prob *P, int k, int ind[], double val[]);
133.621 +/* compute column of the simplex tableau */
133.622 +
133.623 +int glp_transform_row(glp_prob *P, int len, int ind[], double val[]);
133.624 +/* transform explicitly specified row */
133.625 +
133.626 +int glp_transform_col(glp_prob *P, int len, int ind[], double val[]);
133.627 +/* transform explicitly specified column */
133.628 +
133.629 +int glp_prim_rtest(glp_prob *P, int len, const int ind[],
133.630 + const double val[], int dir, double eps);
133.631 +/* perform primal ratio test */
133.632 +
133.633 +int glp_dual_rtest(glp_prob *P, int len, const int ind[],
133.634 + const double val[], int dir, double eps);
133.635 +/* perform dual ratio test */
133.636 +
133.637 +void glp_analyze_bound(glp_prob *P, int k, double *value1, int *var1,
133.638 + double *value2, int *var2);
133.639 +/* analyze active bound of non-basic variable */
133.640 +
133.641 +void glp_analyze_coef(glp_prob *P, int k, double *coef1, int *var1,
133.642 + double *value1, double *coef2, int *var2, double *value2);
133.643 +/* analyze objective coefficient at basic variable */
133.644 +
133.645 +int glp_ios_reason(glp_tree *T);
133.646 +/* determine reason for calling the callback routine */
133.647 +
133.648 +glp_prob *glp_ios_get_prob(glp_tree *T);
133.649 +/* access the problem object */
133.650 +
133.651 +void glp_ios_tree_size(glp_tree *T, int *a_cnt, int *n_cnt,
133.652 + int *t_cnt);
133.653 +/* determine size of the branch-and-bound tree */
133.654 +
133.655 +int glp_ios_curr_node(glp_tree *T);
133.656 +/* determine current active subproblem */
133.657 +
133.658 +int glp_ios_next_node(glp_tree *T, int p);
133.659 +/* determine next active subproblem */
133.660 +
133.661 +int glp_ios_prev_node(glp_tree *T, int p);
133.662 +/* determine previous active subproblem */
133.663 +
133.664 +int glp_ios_up_node(glp_tree *T, int p);
133.665 +/* determine parent subproblem */
133.666 +
133.667 +int glp_ios_node_level(glp_tree *T, int p);
133.668 +/* determine subproblem level */
133.669 +
133.670 +double glp_ios_node_bound(glp_tree *T, int p);
133.671 +/* determine subproblem local bound */
133.672 +
133.673 +int glp_ios_best_node(glp_tree *T);
133.674 +/* find active subproblem with best local bound */
133.675 +
133.676 +double glp_ios_mip_gap(glp_tree *T);
133.677 +/* compute relative MIP gap */
133.678 +
133.679 +void *glp_ios_node_data(glp_tree *T, int p);
133.680 +/* access subproblem application-specific data */
133.681 +
133.682 +void glp_ios_row_attr(glp_tree *T, int i, glp_attr *attr);
133.683 +/* retrieve additional row attributes */
133.684 +
133.685 +int glp_ios_pool_size(glp_tree *T);
133.686 +/* determine current size of the cut pool */
133.687 +
133.688 +int glp_ios_add_row(glp_tree *T,
133.689 + const char *name, int klass, int flags, int len, const int ind[],
133.690 + const double val[], int type, double rhs);
133.691 +/* add row (constraint) to the cut pool */
133.692 +
133.693 +void glp_ios_del_row(glp_tree *T, int i);
133.694 +/* remove row (constraint) from the cut pool */
133.695 +
133.696 +void glp_ios_clear_pool(glp_tree *T);
133.697 +/* remove all rows (constraints) from the cut pool */
133.698 +
133.699 +int glp_ios_can_branch(glp_tree *T, int j);
133.700 +/* check if can branch upon specified variable */
133.701 +
133.702 +void glp_ios_branch_upon(glp_tree *T, int j, int sel);
133.703 +/* choose variable to branch upon */
133.704 +
133.705 +void glp_ios_select_node(glp_tree *T, int p);
133.706 +/* select subproblem to continue the search */
133.707 +
133.708 +int glp_ios_heur_sol(glp_tree *T, const double x[]);
133.709 +/* provide solution found by heuristic */
133.710 +
133.711 +void glp_ios_terminate(glp_tree *T);
133.712 +/* terminate the solution process */
133.713 +
133.714 +void glp_init_mpscp(glp_mpscp *parm);
133.715 +/* initialize MPS format control parameters */
133.716 +
133.717 +int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
133.718 + const char *fname);
133.719 +/* read problem data in MPS format */
133.720 +
133.721 +int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
133.722 + const char *fname);
133.723 +/* write problem data in MPS format */
133.724 +
133.725 +void glp_init_cpxcp(glp_cpxcp *parm);
133.726 +/* initialize CPLEX LP format control parameters */
133.727 +
133.728 +int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname);
133.729 +/* read problem data in CPLEX LP format */
133.730 +
133.731 +int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname);
133.732 +/* write problem data in CPLEX LP format */
133.733 +
133.734 +int glp_read_prob(glp_prob *P, int flags, const char *fname);
133.735 +/* read problem data in GLPK format */
133.736 +
133.737 +int glp_write_prob(glp_prob *P, int flags, const char *fname);
133.738 +/* write problem data in GLPK format */
133.739 +
133.740 +glp_tran *glp_mpl_alloc_wksp(void);
133.741 +/* allocate the MathProg translator workspace */
133.742 +
133.743 +int glp_mpl_read_model(glp_tran *tran, const char *fname, int skip);
133.744 +/* read and translate model section */
133.745 +
133.746 +int glp_mpl_read_data(glp_tran *tran, const char *fname);
133.747 +/* read and translate data section */
133.748 +
133.749 +int glp_mpl_generate(glp_tran *tran, const char *fname);
133.750 +/* generate the model */
133.751 +
133.752 +void glp_mpl_build_prob(glp_tran *tran, glp_prob *prob);
133.753 +/* build LP/MIP problem instance from the model */
133.754 +
133.755 +int glp_mpl_postsolve(glp_tran *tran, glp_prob *prob, int sol);
133.756 +/* postsolve the model */
133.757 +
133.758 +void glp_mpl_free_wksp(glp_tran *tran);
133.759 +/* free the MathProg translator workspace */
133.760 +
133.761 +int glp_main(int argc, const char *argv[]);
133.762 +/* stand-alone LP/MIP solver */
133.763 +
133.764 +/**********************************************************************/
133.765 +
133.766 +#ifndef GLP_LONG_DEFINED
133.767 +#define GLP_LONG_DEFINED
133.768 +typedef struct { int lo, hi; } glp_long;
133.769 +/* long integer data type */
133.770 +#endif
133.771 +
133.772 +int glp_init_env(void);
133.773 +/* initialize GLPK environment */
133.774 +
133.775 +const char *glp_version(void);
133.776 +/* determine library version */
133.777 +
133.778 +int glp_free_env(void);
133.779 +/* free GLPK environment */
133.780 +
133.781 +void glp_printf(const char *fmt, ...);
133.782 +/* write formatted output to terminal */
133.783 +
133.784 +void glp_vprintf(const char *fmt, va_list arg);
133.785 +/* write formatted output to terminal */
133.786 +
133.787 +int glp_term_out(int flag);
133.788 +/* enable/disable terminal output */
133.789 +
133.790 +void glp_term_hook(int (*func)(void *info, const char *s), void *info);
133.791 +/* install hook to intercept terminal output */
133.792 +
133.793 +int glp_open_tee(const char *fname);
133.794 +/* start copying terminal output to text file */
133.795 +
133.796 +int glp_close_tee(void);
133.797 +/* stop copying terminal output to text file */
133.798 +
133.799 +#ifndef GLP_ERROR_DEFINED
133.800 +#define GLP_ERROR_DEFINED
133.801 +typedef void (*_glp_error)(const char *fmt, ...);
133.802 +#endif
133.803 +
133.804 +#define glp_error glp_error_(__FILE__, __LINE__)
133.805 +_glp_error glp_error_(const char *file, int line);
133.806 +/* display error message and terminate execution */
133.807 +
133.808 +#define glp_assert(expr) \
133.809 + ((void)((expr) || (glp_assert_(#expr, __FILE__, __LINE__), 1)))
133.810 +void glp_assert_(const char *expr, const char *file, int line);
133.811 +/* check for logical condition */
133.812 +
133.813 +void glp_error_hook(void (*func)(void *info), void *info);
133.814 +/* install hook to intercept abnormal termination */
133.815 +
133.816 +void *glp_malloc(int size);
133.817 +/* allocate memory block */
133.818 +
133.819 +void *glp_calloc(int n, int size);
133.820 +/* allocate memory block */
133.821 +
133.822 +void glp_free(void *ptr);
133.823 +/* free memory block */
133.824 +
133.825 +void glp_mem_limit(int limit);
133.826 +/* set memory usage limit */
133.827 +
133.828 +void glp_mem_usage(int *count, int *cpeak, glp_long *total,
133.829 + glp_long *tpeak);
133.830 +/* get memory usage information */
133.831 +
133.832 +glp_long glp_time(void);
133.833 +/* determine current universal time */
133.834 +
133.835 +double glp_difftime(glp_long t1, glp_long t0);
133.836 +/* compute difference between two time values */
133.837 +
133.838 +/**********************************************************************/
133.839 +
133.840 +#ifndef GLP_DATA_DEFINED
133.841 +#define GLP_DATA_DEFINED
133.842 +typedef struct { double _opaque_data[100]; } glp_data;
133.843 +/* plain data file */
133.844 +#endif
133.845 +
133.846 +glp_data *glp_sdf_open_file(const char *fname);
133.847 +/* open plain data file */
133.848 +
133.849 +void glp_sdf_set_jump(glp_data *data, void *jump);
133.850 +/* set up error handling */
133.851 +
133.852 +void glp_sdf_error(glp_data *data, const char *fmt, ...);
133.853 +/* print error message */
133.854 +
133.855 +void glp_sdf_warning(glp_data *data, const char *fmt, ...);
133.856 +/* print warning message */
133.857 +
133.858 +int glp_sdf_read_int(glp_data *data);
133.859 +/* read integer number */
133.860 +
133.861 +double glp_sdf_read_num(glp_data *data);
133.862 +/* read floating-point number */
133.863 +
133.864 +const char *glp_sdf_read_item(glp_data *data);
133.865 +/* read data item */
133.866 +
133.867 +const char *glp_sdf_read_text(glp_data *data);
133.868 +/* read text until end of line */
133.869 +
133.870 +int glp_sdf_line(glp_data *data);
133.871 +/* determine current line number */
133.872 +
133.873 +void glp_sdf_close_file(glp_data *data);
133.874 +/* close plain data file */
133.875 +
133.876 +/**********************************************************************/
133.877 +
133.878 +typedef struct _glp_graph glp_graph;
133.879 +typedef struct _glp_vertex glp_vertex;
133.880 +typedef struct _glp_arc glp_arc;
133.881 +
133.882 +struct _glp_graph
133.883 +{ /* graph descriptor */
133.884 + void *pool; /* DMP *pool; */
133.885 + /* memory pool to store graph components */
133.886 + char *name;
133.887 + /* graph name (1 to 255 chars); NULL means no name is assigned
133.888 + to the graph */
133.889 + int nv_max;
133.890 + /* length of the vertex list (enlarged automatically) */
133.891 + int nv;
133.892 + /* number of vertices in the graph, 0 <= nv <= nv_max */
133.893 + int na;
133.894 + /* number of arcs in the graph, na >= 0 */
133.895 + glp_vertex **v; /* glp_vertex *v[1+nv_max]; */
133.896 + /* v[i], 1 <= i <= nv, is a pointer to i-th vertex */
133.897 + void *index; /* AVL *index; */
133.898 + /* vertex index to find vertices by their names; NULL means the
133.899 + index does not exist */
133.900 + int v_size;
133.901 + /* size of data associated with each vertex (0 to 256 bytes) */
133.902 + int a_size;
133.903 + /* size of data associated with each arc (0 to 256 bytes) */
133.904 +};
133.905 +
133.906 +struct _glp_vertex
133.907 +{ /* vertex descriptor */
133.908 + int i;
133.909 + /* vertex ordinal number, 1 <= i <= nv */
133.910 + char *name;
133.911 + /* vertex name (1 to 255 chars); NULL means no name is assigned
133.912 + to the vertex */
133.913 + void *entry; /* AVLNODE *entry; */
133.914 + /* pointer to corresponding entry in the vertex index; NULL means
133.915 + that either the index does not exist or the vertex has no name
133.916 + assigned */
133.917 + void *data;
133.918 + /* pointer to data associated with the vertex */
133.919 + void *temp;
133.920 + /* working pointer */
133.921 + glp_arc *in;
133.922 + /* pointer to the (unordered) list of incoming arcs */
133.923 + glp_arc *out;
133.924 + /* pointer to the (unordered) list of outgoing arcs */
133.925 +};
133.926 +
133.927 +struct _glp_arc
133.928 +{ /* arc descriptor */
133.929 + glp_vertex *tail;
133.930 + /* pointer to the tail endpoint */
133.931 + glp_vertex *head;
133.932 + /* pointer to the head endpoint */
133.933 + void *data;
133.934 + /* pointer to data associated with the arc */
133.935 + void *temp;
133.936 + /* working pointer */
133.937 + glp_arc *t_prev;
133.938 + /* pointer to previous arc having the same tail endpoint */
133.939 + glp_arc *t_next;
133.940 + /* pointer to next arc having the same tail endpoint */
133.941 + glp_arc *h_prev;
133.942 + /* pointer to previous arc having the same head endpoint */
133.943 + glp_arc *h_next;
133.944 + /* pointer to next arc having the same head endpoint */
133.945 +};
133.946 +
133.947 +glp_graph *glp_create_graph(int v_size, int a_size);
133.948 +/* create graph */
133.949 +
133.950 +void glp_set_graph_name(glp_graph *G, const char *name);
133.951 +/* assign (change) graph name */
133.952 +
133.953 +int glp_add_vertices(glp_graph *G, int nadd);
133.954 +/* add new vertices to graph */
133.955 +
133.956 +void glp_set_vertex_name(glp_graph *G, int i, const char *name);
133.957 +/* assign (change) vertex name */
133.958 +
133.959 +glp_arc *glp_add_arc(glp_graph *G, int i, int j);
133.960 +/* add new arc to graph */
133.961 +
133.962 +void glp_del_vertices(glp_graph *G, int ndel, const int num[]);
133.963 +/* delete vertices from graph */
133.964 +
133.965 +void glp_del_arc(glp_graph *G, glp_arc *a);
133.966 +/* delete arc from graph */
133.967 +
133.968 +void glp_erase_graph(glp_graph *G, int v_size, int a_size);
133.969 +/* erase graph content */
133.970 +
133.971 +void glp_delete_graph(glp_graph *G);
133.972 +/* delete graph */
133.973 +
133.974 +void glp_create_v_index(glp_graph *G);
133.975 +/* create vertex name index */
133.976 +
133.977 +int glp_find_vertex(glp_graph *G, const char *name);
133.978 +/* find vertex by its name */
133.979 +
133.980 +void glp_delete_v_index(glp_graph *G);
133.981 +/* delete vertex name index */
133.982 +
133.983 +int glp_read_graph(glp_graph *G, const char *fname);
133.984 +/* read graph from plain text file */
133.985 +
133.986 +int glp_write_graph(glp_graph *G, const char *fname);
133.987 +/* write graph to plain text file */
133.988 +
133.989 +void glp_mincost_lp(glp_prob *P, glp_graph *G, int names, int v_rhs,
133.990 + int a_low, int a_cap, int a_cost);
133.991 +/* convert minimum cost flow problem to LP */
133.992 +
133.993 +int glp_mincost_okalg(glp_graph *G, int v_rhs, int a_low, int a_cap,
133.994 + int a_cost, double *sol, int a_x, int v_pi);
133.995 +/* find minimum-cost flow with out-of-kilter algorithm */
133.996 +
133.997 +void glp_maxflow_lp(glp_prob *P, glp_graph *G, int names, int s,
133.998 + int t, int a_cap);
133.999 +/* convert maximum flow problem to LP */
133.1000 +
133.1001 +int glp_maxflow_ffalg(glp_graph *G, int s, int t, int a_cap,
133.1002 + double *sol, int a_x, int v_cut);
133.1003 +/* find maximal flow with Ford-Fulkerson algorithm */
133.1004 +
133.1005 +int glp_check_asnprob(glp_graph *G, int v_set);
133.1006 +/* check correctness of assignment problem data */
133.1007 +
133.1008 +/* assignment problem formulation: */
133.1009 +#define GLP_ASN_MIN 1 /* perfect matching (minimization) */
133.1010 +#define GLP_ASN_MAX 2 /* perfect matching (maximization) */
133.1011 +#define GLP_ASN_MMP 3 /* maximum matching */
133.1012 +
133.1013 +int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names,
133.1014 + int v_set, int a_cost);
133.1015 +/* convert assignment problem to LP */
133.1016 +
133.1017 +int glp_asnprob_okalg(int form, glp_graph *G, int v_set, int a_cost,
133.1018 + double *sol, int a_x);
133.1019 +/* solve assignment problem with out-of-kilter algorithm */
133.1020 +
133.1021 +int glp_asnprob_hall(glp_graph *G, int v_set, int a_x);
133.1022 +/* find bipartite matching of maximum cardinality */
133.1023 +
133.1024 +double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls);
133.1025 +/* solve critical path problem */
133.1026 +
133.1027 +int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
133.1028 + int a_cost, const char *fname);
133.1029 +/* read min-cost flow problem data in DIMACS format */
133.1030 +
133.1031 +int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
133.1032 + int a_cost, const char *fname);
133.1033 +/* write min-cost flow problem data in DIMACS format */
133.1034 +
133.1035 +int glp_read_maxflow(glp_graph *G, int *s, int *t, int a_cap,
133.1036 + const char *fname);
133.1037 +/* read maximum flow problem data in DIMACS format */
133.1038 +
133.1039 +int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
133.1040 + const char *fname);
133.1041 +/* write maximum flow problem data in DIMACS format */
133.1042 +
133.1043 +int glp_read_asnprob(glp_graph *G, int v_set, int a_cost, const char
133.1044 + *fname);
133.1045 +/* read assignment problem data in DIMACS format */
133.1046 +
133.1047 +int glp_write_asnprob(glp_graph *G, int v_set, int a_cost, const char
133.1048 + *fname);
133.1049 +/* write assignment problem data in DIMACS format */
133.1050 +
133.1051 +int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname);
133.1052 +/* read graph in DIMACS clique/coloring format */
133.1053 +
133.1054 +int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname);
133.1055 +/* write graph in DIMACS clique/coloring format */
133.1056 +
133.1057 +int glp_netgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
133.1058 + const int parm[1+15]);
133.1059 +/* Klingman's network problem generator */
133.1060 +
133.1061 +int glp_gridgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
133.1062 + const int parm[1+14]);
133.1063 +/* grid-like network problem generator */
133.1064 +
133.1065 +int glp_rmfgen(glp_graph *G, int *s, int *t, int a_cap,
133.1066 + const int parm[1+5]);
133.1067 +/* Goldfarb's maximum flow problem generator */
133.1068 +
133.1069 +int glp_weak_comp(glp_graph *G, int v_num);
133.1070 +/* find all weakly connected components of graph */
133.1071 +
133.1072 +int glp_strong_comp(glp_graph *G, int v_num);
133.1073 +/* find all strongly connected components of graph */
133.1074 +
133.1075 +int glp_top_sort(glp_graph *G, int v_num);
133.1076 +/* topological sorting of acyclic digraph */
133.1077 +
133.1078 +int glp_wclique_exact(glp_graph *G, int v_wgt, double *sol, int v_set);
133.1079 +/* find maximum weight clique with exact algorithm */
133.1080 +
133.1081 +/***********************************************************************
133.1082 +* NOTE: All symbols defined below are obsolete and kept here only for
133.1083 +* backward compatibility.
133.1084 +***********************************************************************/
133.1085 +
133.1086 +#define LPX glp_prob
133.1087 +
133.1088 +/* problem class: */
133.1089 +#define LPX_LP 100 /* linear programming (LP) */
133.1090 +#define LPX_MIP 101 /* mixed integer programming (MIP) */
133.1091 +
133.1092 +/* type of auxiliary/structural variable: */
133.1093 +#define LPX_FR 110 /* free variable */
133.1094 +#define LPX_LO 111 /* variable with lower bound */
133.1095 +#define LPX_UP 112 /* variable with upper bound */
133.1096 +#define LPX_DB 113 /* double-bounded variable */
133.1097 +#define LPX_FX 114 /* fixed variable */
133.1098 +
133.1099 +/* optimization direction flag: */
133.1100 +#define LPX_MIN 120 /* minimization */
133.1101 +#define LPX_MAX 121 /* maximization */
133.1102 +
133.1103 +/* status of primal basic solution: */
133.1104 +#define LPX_P_UNDEF 132 /* primal solution is undefined */
133.1105 +#define LPX_P_FEAS 133 /* solution is primal feasible */
133.1106 +#define LPX_P_INFEAS 134 /* solution is primal infeasible */
133.1107 +#define LPX_P_NOFEAS 135 /* no primal feasible solution exists */
133.1108 +
133.1109 +/* status of dual basic solution: */
133.1110 +#define LPX_D_UNDEF 136 /* dual solution is undefined */
133.1111 +#define LPX_D_FEAS 137 /* solution is dual feasible */
133.1112 +#define LPX_D_INFEAS 138 /* solution is dual infeasible */
133.1113 +#define LPX_D_NOFEAS 139 /* no dual feasible solution exists */
133.1114 +
133.1115 +/* status of auxiliary/structural variable: */
133.1116 +#define LPX_BS 140 /* basic variable */
133.1117 +#define LPX_NL 141 /* non-basic variable on lower bound */
133.1118 +#define LPX_NU 142 /* non-basic variable on upper bound */
133.1119 +#define LPX_NF 143 /* non-basic free variable */
133.1120 +#define LPX_NS 144 /* non-basic fixed variable */
133.1121 +
133.1122 +/* status of interior-point solution: */
133.1123 +#define LPX_T_UNDEF 150 /* interior solution is undefined */
133.1124 +#define LPX_T_OPT 151 /* interior solution is optimal */
133.1125 +
133.1126 +/* kind of structural variable: */
133.1127 +#define LPX_CV 160 /* continuous variable */
133.1128 +#define LPX_IV 161 /* integer variable */
133.1129 +
133.1130 +/* status of integer solution: */
133.1131 +#define LPX_I_UNDEF 170 /* integer solution is undefined */
133.1132 +#define LPX_I_OPT 171 /* integer solution is optimal */
133.1133 +#define LPX_I_FEAS 172 /* integer solution is feasible */
133.1134 +#define LPX_I_NOFEAS 173 /* no integer solution exists */
133.1135 +
133.1136 +/* status codes reported by the routine lpx_get_status: */
133.1137 +#define LPX_OPT 180 /* optimal */
133.1138 +#define LPX_FEAS 181 /* feasible */
133.1139 +#define LPX_INFEAS 182 /* infeasible */
133.1140 +#define LPX_NOFEAS 183 /* no feasible */
133.1141 +#define LPX_UNBND 184 /* unbounded */
133.1142 +#define LPX_UNDEF 185 /* undefined */
133.1143 +
133.1144 +/* exit codes returned by solver routines: */
133.1145 +#define LPX_E_OK 200 /* success */
133.1146 +#define LPX_E_EMPTY 201 /* empty problem */
133.1147 +#define LPX_E_BADB 202 /* invalid initial basis */
133.1148 +#define LPX_E_INFEAS 203 /* infeasible initial solution */
133.1149 +#define LPX_E_FAULT 204 /* unable to start the search */
133.1150 +#define LPX_E_OBJLL 205 /* objective lower limit reached */
133.1151 +#define LPX_E_OBJUL 206 /* objective upper limit reached */
133.1152 +#define LPX_E_ITLIM 207 /* iterations limit exhausted */
133.1153 +#define LPX_E_TMLIM 208 /* time limit exhausted */
133.1154 +#define LPX_E_NOFEAS 209 /* no feasible solution */
133.1155 +#define LPX_E_INSTAB 210 /* numerical instability */
133.1156 +#define LPX_E_SING 211 /* problems with basis matrix */
133.1157 +#define LPX_E_NOCONV 212 /* no convergence (interior) */
133.1158 +#define LPX_E_NOPFS 213 /* no primal feas. sol. (LP presolver) */
133.1159 +#define LPX_E_NODFS 214 /* no dual feas. sol. (LP presolver) */
133.1160 +#define LPX_E_MIPGAP 215 /* relative mip gap tolerance reached */
133.1161 +
133.1162 +/* control parameter identifiers: */
133.1163 +#define LPX_K_MSGLEV 300 /* lp->msg_lev */
133.1164 +#define LPX_K_SCALE 301 /* lp->scale */
133.1165 +#define LPX_K_DUAL 302 /* lp->dual */
133.1166 +#define LPX_K_PRICE 303 /* lp->price */
133.1167 +#define LPX_K_RELAX 304 /* lp->relax */
133.1168 +#define LPX_K_TOLBND 305 /* lp->tol_bnd */
133.1169 +#define LPX_K_TOLDJ 306 /* lp->tol_dj */
133.1170 +#define LPX_K_TOLPIV 307 /* lp->tol_piv */
133.1171 +#define LPX_K_ROUND 308 /* lp->round */
133.1172 +#define LPX_K_OBJLL 309 /* lp->obj_ll */
133.1173 +#define LPX_K_OBJUL 310 /* lp->obj_ul */
133.1174 +#define LPX_K_ITLIM 311 /* lp->it_lim */
133.1175 +#define LPX_K_ITCNT 312 /* lp->it_cnt */
133.1176 +#define LPX_K_TMLIM 313 /* lp->tm_lim */
133.1177 +#define LPX_K_OUTFRQ 314 /* lp->out_frq */
133.1178 +#define LPX_K_OUTDLY 315 /* lp->out_dly */
133.1179 +#define LPX_K_BRANCH 316 /* lp->branch */
133.1180 +#define LPX_K_BTRACK 317 /* lp->btrack */
133.1181 +#define LPX_K_TOLINT 318 /* lp->tol_int */
133.1182 +#define LPX_K_TOLOBJ 319 /* lp->tol_obj */
133.1183 +#define LPX_K_MPSINFO 320 /* lp->mps_info */
133.1184 +#define LPX_K_MPSOBJ 321 /* lp->mps_obj */
133.1185 +#define LPX_K_MPSORIG 322 /* lp->mps_orig */
133.1186 +#define LPX_K_MPSWIDE 323 /* lp->mps_wide */
133.1187 +#define LPX_K_MPSFREE 324 /* lp->mps_free */
133.1188 +#define LPX_K_MPSSKIP 325 /* lp->mps_skip */
133.1189 +#define LPX_K_LPTORIG 326 /* lp->lpt_orig */
133.1190 +#define LPX_K_PRESOL 327 /* lp->presol */
133.1191 +#define LPX_K_BINARIZE 328 /* lp->binarize */
133.1192 +#define LPX_K_USECUTS 329 /* lp->use_cuts */
133.1193 +#define LPX_K_BFTYPE 330 /* lp->bfcp->type */
133.1194 +#define LPX_K_MIPGAP 331 /* lp->mip_gap */
133.1195 +
133.1196 +#define LPX_C_COVER 0x01 /* mixed cover cuts */
133.1197 +#define LPX_C_CLIQUE 0x02 /* clique cuts */
133.1198 +#define LPX_C_GOMORY 0x04 /* Gomory's mixed integer cuts */
133.1199 +#define LPX_C_MIR 0x08 /* mixed integer rounding cuts */
133.1200 +#define LPX_C_ALL 0xFF /* all cuts */
133.1201 +
133.1202 +typedef struct
133.1203 +{ /* this structure contains results reported by the routines which
133.1204 + checks Karush-Kuhn-Tucker conditions (for details see comments
133.1205 + to those routines) */
133.1206 + /*--------------------------------------------------------------*/
133.1207 + /* xR - A * xS = 0 (KKT.PE) */
133.1208 + double pe_ae_max;
133.1209 + /* largest absolute error */
133.1210 + int pe_ae_row;
133.1211 + /* number of row with largest absolute error */
133.1212 + double pe_re_max;
133.1213 + /* largest relative error */
133.1214 + int pe_re_row;
133.1215 + /* number of row with largest relative error */
133.1216 + int pe_quality;
133.1217 + /* quality of primal solution:
133.1218 + 'H' - high
133.1219 + 'M' - medium
133.1220 + 'L' - low
133.1221 + '?' - primal solution is wrong */
133.1222 + /*--------------------------------------------------------------*/
133.1223 + /* l[k] <= x[k] <= u[k] (KKT.PB) */
133.1224 + double pb_ae_max;
133.1225 + /* largest absolute error */
133.1226 + int pb_ae_ind;
133.1227 + /* number of variable with largest absolute error */
133.1228 + double pb_re_max;
133.1229 + /* largest relative error */
133.1230 + int pb_re_ind;
133.1231 + /* number of variable with largest relative error */
133.1232 + int pb_quality;
133.1233 + /* quality of primal feasibility:
133.1234 + 'H' - high
133.1235 + 'M' - medium
133.1236 + 'L' - low
133.1237 + '?' - primal solution is infeasible */
133.1238 + /*--------------------------------------------------------------*/
133.1239 + /* A' * (dR - cR) + (dS - cS) = 0 (KKT.DE) */
133.1240 + double de_ae_max;
133.1241 + /* largest absolute error */
133.1242 + int de_ae_col;
133.1243 + /* number of column with largest absolute error */
133.1244 + double de_re_max;
133.1245 + /* largest relative error */
133.1246 + int de_re_col;
133.1247 + /* number of column with largest relative error */
133.1248 + int de_quality;
133.1249 + /* quality of dual solution:
133.1250 + 'H' - high
133.1251 + 'M' - medium
133.1252 + 'L' - low
133.1253 + '?' - dual solution is wrong */
133.1254 + /*--------------------------------------------------------------*/
133.1255 + /* d[k] >= 0 or d[k] <= 0 (KKT.DB) */
133.1256 + double db_ae_max;
133.1257 + /* largest absolute error */
133.1258 + int db_ae_ind;
133.1259 + /* number of variable with largest absolute error */
133.1260 + double db_re_max;
133.1261 + /* largest relative error */
133.1262 + int db_re_ind;
133.1263 + /* number of variable with largest relative error */
133.1264 + int db_quality;
133.1265 + /* quality of dual feasibility:
133.1266 + 'H' - high
133.1267 + 'M' - medium
133.1268 + 'L' - low
133.1269 + '?' - dual solution is infeasible */
133.1270 + /*--------------------------------------------------------------*/
133.1271 + /* (x[k] - bound of x[k]) * d[k] = 0 (KKT.CS) */
133.1272 + double cs_ae_max;
133.1273 + /* largest absolute error */
133.1274 + int cs_ae_ind;
133.1275 + /* number of variable with largest absolute error */
133.1276 + double cs_re_max;
133.1277 + /* largest relative error */
133.1278 + int cs_re_ind;
133.1279 + /* number of variable with largest relative error */
133.1280 + int cs_quality;
133.1281 + /* quality of complementary slackness:
133.1282 + 'H' - high
133.1283 + 'M' - medium
133.1284 + 'L' - low
133.1285 + '?' - primal and dual solutions are not complementary */
133.1286 +} LPXKKT;
133.1287 +
133.1288 +#define lpx_create_prob _glp_lpx_create_prob
133.1289 +LPX *lpx_create_prob(void);
133.1290 +/* create problem object */
133.1291 +
133.1292 +#define lpx_set_prob_name _glp_lpx_set_prob_name
133.1293 +void lpx_set_prob_name(LPX *lp, const char *name);
133.1294 +/* assign (change) problem name */
133.1295 +
133.1296 +#define lpx_set_obj_name _glp_lpx_set_obj_name
133.1297 +void lpx_set_obj_name(LPX *lp, const char *name);
133.1298 +/* assign (change) objective function name */
133.1299 +
133.1300 +#define lpx_set_obj_dir _glp_lpx_set_obj_dir
133.1301 +void lpx_set_obj_dir(LPX *lp, int dir);
133.1302 +/* set (change) optimization direction flag */
133.1303 +
133.1304 +#define lpx_add_rows _glp_lpx_add_rows
133.1305 +int lpx_add_rows(LPX *lp, int nrs);
133.1306 +/* add new rows to problem object */
133.1307 +
133.1308 +#define lpx_add_cols _glp_lpx_add_cols
133.1309 +int lpx_add_cols(LPX *lp, int ncs);
133.1310 +/* add new columns to problem object */
133.1311 +
133.1312 +#define lpx_set_row_name _glp_lpx_set_row_name
133.1313 +void lpx_set_row_name(LPX *lp, int i, const char *name);
133.1314 +/* assign (change) row name */
133.1315 +
133.1316 +#define lpx_set_col_name _glp_lpx_set_col_name
133.1317 +void lpx_set_col_name(LPX *lp, int j, const char *name);
133.1318 +/* assign (change) column name */
133.1319 +
133.1320 +#define lpx_set_row_bnds _glp_lpx_set_row_bnds
133.1321 +void lpx_set_row_bnds(LPX *lp, int i, int type, double lb, double ub);
133.1322 +/* set (change) row bounds */
133.1323 +
133.1324 +#define lpx_set_col_bnds _glp_lpx_set_col_bnds
133.1325 +void lpx_set_col_bnds(LPX *lp, int j, int type, double lb, double ub);
133.1326 +/* set (change) column bounds */
133.1327 +
133.1328 +#define lpx_set_obj_coef _glp_lpx_set_obj_coef
133.1329 +void lpx_set_obj_coef(glp_prob *lp, int j, double coef);
133.1330 +/* set (change) obj. coefficient or constant term */
133.1331 +
133.1332 +#define lpx_set_mat_row _glp_lpx_set_mat_row
133.1333 +void lpx_set_mat_row(LPX *lp, int i, int len, const int ind[],
133.1334 + const double val[]);
133.1335 +/* set (replace) row of the constraint matrix */
133.1336 +
133.1337 +#define lpx_set_mat_col _glp_lpx_set_mat_col
133.1338 +void lpx_set_mat_col(LPX *lp, int j, int len, const int ind[],
133.1339 + const double val[]);
133.1340 +/* set (replace) column of the constraint matrix */
133.1341 +
133.1342 +#define lpx_load_matrix _glp_lpx_load_matrix
133.1343 +void lpx_load_matrix(LPX *lp, int ne, const int ia[], const int ja[],
133.1344 + const double ar[]);
133.1345 +/* load (replace) the whole constraint matrix */
133.1346 +
133.1347 +#define lpx_del_rows _glp_lpx_del_rows
133.1348 +void lpx_del_rows(LPX *lp, int nrs, const int num[]);
133.1349 +/* delete specified rows from problem object */
133.1350 +
133.1351 +#define lpx_del_cols _glp_lpx_del_cols
133.1352 +void lpx_del_cols(LPX *lp, int ncs, const int num[]);
133.1353 +/* delete specified columns from problem object */
133.1354 +
133.1355 +#define lpx_delete_prob _glp_lpx_delete_prob
133.1356 +void lpx_delete_prob(LPX *lp);
133.1357 +/* delete problem object */
133.1358 +
133.1359 +#define lpx_get_prob_name _glp_lpx_get_prob_name
133.1360 +const char *lpx_get_prob_name(LPX *lp);
133.1361 +/* retrieve problem name */
133.1362 +
133.1363 +#define lpx_get_obj_name _glp_lpx_get_obj_name
133.1364 +const char *lpx_get_obj_name(LPX *lp);
133.1365 +/* retrieve objective function name */
133.1366 +
133.1367 +#define lpx_get_obj_dir _glp_lpx_get_obj_dir
133.1368 +int lpx_get_obj_dir(LPX *lp);
133.1369 +/* retrieve optimization direction flag */
133.1370 +
133.1371 +#define lpx_get_num_rows _glp_lpx_get_num_rows
133.1372 +int lpx_get_num_rows(LPX *lp);
133.1373 +/* retrieve number of rows */
133.1374 +
133.1375 +#define lpx_get_num_cols _glp_lpx_get_num_cols
133.1376 +int lpx_get_num_cols(LPX *lp);
133.1377 +/* retrieve number of columns */
133.1378 +
133.1379 +#define lpx_get_row_name _glp_lpx_get_row_name
133.1380 +const char *lpx_get_row_name(LPX *lp, int i);
133.1381 +/* retrieve row name */
133.1382 +
133.1383 +#define lpx_get_col_name _glp_lpx_get_col_name
133.1384 +const char *lpx_get_col_name(LPX *lp, int j);
133.1385 +/* retrieve column name */
133.1386 +
133.1387 +#define lpx_get_row_type _glp_lpx_get_row_type
133.1388 +int lpx_get_row_type(LPX *lp, int i);
133.1389 +/* retrieve row type */
133.1390 +
133.1391 +#define lpx_get_row_lb _glp_lpx_get_row_lb
133.1392 +double lpx_get_row_lb(LPX *lp, int i);
133.1393 +/* retrieve row lower bound */
133.1394 +
133.1395 +#define lpx_get_row_ub _glp_lpx_get_row_ub
133.1396 +double lpx_get_row_ub(LPX *lp, int i);
133.1397 +/* retrieve row upper bound */
133.1398 +
133.1399 +#define lpx_get_row_bnds _glp_lpx_get_row_bnds
133.1400 +void lpx_get_row_bnds(LPX *lp, int i, int *typx, double *lb,
133.1401 + double *ub);
133.1402 +/* retrieve row bounds */
133.1403 +
133.1404 +#define lpx_get_col_type _glp_lpx_get_col_type
133.1405 +int lpx_get_col_type(LPX *lp, int j);
133.1406 +/* retrieve column type */
133.1407 +
133.1408 +#define lpx_get_col_lb _glp_lpx_get_col_lb
133.1409 +double lpx_get_col_lb(LPX *lp, int j);
133.1410 +/* retrieve column lower bound */
133.1411 +
133.1412 +#define lpx_get_col_ub _glp_lpx_get_col_ub
133.1413 +double lpx_get_col_ub(LPX *lp, int j);
133.1414 +/* retrieve column upper bound */
133.1415 +
133.1416 +#define lpx_get_col_bnds _glp_lpx_get_col_bnds
133.1417 +void lpx_get_col_bnds(LPX *lp, int j, int *typx, double *lb,
133.1418 + double *ub);
133.1419 +/* retrieve column bounds */
133.1420 +
133.1421 +#define lpx_get_obj_coef _glp_lpx_get_obj_coef
133.1422 +double lpx_get_obj_coef(LPX *lp, int j);
133.1423 +/* retrieve obj. coefficient or constant term */
133.1424 +
133.1425 +#define lpx_get_num_nz _glp_lpx_get_num_nz
133.1426 +int lpx_get_num_nz(LPX *lp);
133.1427 +/* retrieve number of constraint coefficients */
133.1428 +
133.1429 +#define lpx_get_mat_row _glp_lpx_get_mat_row
133.1430 +int lpx_get_mat_row(LPX *lp, int i, int ind[], double val[]);
133.1431 +/* retrieve row of the constraint matrix */
133.1432 +
133.1433 +#define lpx_get_mat_col _glp_lpx_get_mat_col
133.1434 +int lpx_get_mat_col(LPX *lp, int j, int ind[], double val[]);
133.1435 +/* retrieve column of the constraint matrix */
133.1436 +
133.1437 +#define lpx_create_index _glp_lpx_create_index
133.1438 +void lpx_create_index(LPX *lp);
133.1439 +/* create the name index */
133.1440 +
133.1441 +#define lpx_find_row _glp_lpx_find_row
133.1442 +int lpx_find_row(LPX *lp, const char *name);
133.1443 +/* find row by its name */
133.1444 +
133.1445 +#define lpx_find_col _glp_lpx_find_col
133.1446 +int lpx_find_col(LPX *lp, const char *name);
133.1447 +/* find column by its name */
133.1448 +
133.1449 +#define lpx_delete_index _glp_lpx_delete_index
133.1450 +void lpx_delete_index(LPX *lp);
133.1451 +/* delete the name index */
133.1452 +
133.1453 +#define lpx_scale_prob _glp_lpx_scale_prob
133.1454 +void lpx_scale_prob(LPX *lp);
133.1455 +/* scale problem data */
133.1456 +
133.1457 +#define lpx_unscale_prob _glp_lpx_unscale_prob
133.1458 +void lpx_unscale_prob(LPX *lp);
133.1459 +/* unscale problem data */
133.1460 +
133.1461 +#define lpx_set_row_stat _glp_lpx_set_row_stat
133.1462 +void lpx_set_row_stat(LPX *lp, int i, int stat);
133.1463 +/* set (change) row status */
133.1464 +
133.1465 +#define lpx_set_col_stat _glp_lpx_set_col_stat
133.1466 +void lpx_set_col_stat(LPX *lp, int j, int stat);
133.1467 +/* set (change) column status */
133.1468 +
133.1469 +#define lpx_std_basis _glp_lpx_std_basis
133.1470 +void lpx_std_basis(LPX *lp);
133.1471 +/* construct standard initial LP basis */
133.1472 +
133.1473 +#define lpx_adv_basis _glp_lpx_adv_basis
133.1474 +void lpx_adv_basis(LPX *lp);
133.1475 +/* construct advanced initial LP basis */
133.1476 +
133.1477 +#define lpx_cpx_basis _glp_lpx_cpx_basis
133.1478 +void lpx_cpx_basis(LPX *lp);
133.1479 +/* construct Bixby's initial LP basis */
133.1480 +
133.1481 +#define lpx_simplex _glp_lpx_simplex
133.1482 +int lpx_simplex(LPX *lp);
133.1483 +/* easy-to-use driver to the simplex method */
133.1484 +
133.1485 +#define lpx_exact _glp_lpx_exact
133.1486 +int lpx_exact(LPX *lp);
133.1487 +/* easy-to-use driver to the exact simplex method */
133.1488 +
133.1489 +#define lpx_get_status _glp_lpx_get_status
133.1490 +int lpx_get_status(LPX *lp);
133.1491 +/* retrieve generic status of basic solution */
133.1492 +
133.1493 +#define lpx_get_prim_stat _glp_lpx_get_prim_stat
133.1494 +int lpx_get_prim_stat(LPX *lp);
133.1495 +/* retrieve primal status of basic solution */
133.1496 +
133.1497 +#define lpx_get_dual_stat _glp_lpx_get_dual_stat
133.1498 +int lpx_get_dual_stat(LPX *lp);
133.1499 +/* retrieve dual status of basic solution */
133.1500 +
133.1501 +#define lpx_get_obj_val _glp_lpx_get_obj_val
133.1502 +double lpx_get_obj_val(LPX *lp);
133.1503 +/* retrieve objective value (basic solution) */
133.1504 +
133.1505 +#define lpx_get_row_stat _glp_lpx_get_row_stat
133.1506 +int lpx_get_row_stat(LPX *lp, int i);
133.1507 +/* retrieve row status (basic solution) */
133.1508 +
133.1509 +#define lpx_get_row_prim _glp_lpx_get_row_prim
133.1510 +double lpx_get_row_prim(LPX *lp, int i);
133.1511 +/* retrieve row primal value (basic solution) */
133.1512 +
133.1513 +#define lpx_get_row_dual _glp_lpx_get_row_dual
133.1514 +double lpx_get_row_dual(LPX *lp, int i);
133.1515 +/* retrieve row dual value (basic solution) */
133.1516 +
133.1517 +#define lpx_get_row_info _glp_lpx_get_row_info
133.1518 +void lpx_get_row_info(LPX *lp, int i, int *tagx, double *vx,
133.1519 + double *dx);
133.1520 +/* obtain row solution information */
133.1521 +
133.1522 +#define lpx_get_col_stat _glp_lpx_get_col_stat
133.1523 +int lpx_get_col_stat(LPX *lp, int j);
133.1524 +/* retrieve column status (basic solution) */
133.1525 +
133.1526 +#define lpx_get_col_prim _glp_lpx_get_col_prim
133.1527 +double lpx_get_col_prim(LPX *lp, int j);
133.1528 +/* retrieve column primal value (basic solution) */
133.1529 +
133.1530 +#define lpx_get_col_dual _glp_lpx_get_col_dual
133.1531 +double lpx_get_col_dual(glp_prob *lp, int j);
133.1532 +/* retrieve column dual value (basic solution) */
133.1533 +
133.1534 +#define lpx_get_col_info _glp_lpx_get_col_info
133.1535 +void lpx_get_col_info(LPX *lp, int j, int *tagx, double *vx,
133.1536 + double *dx);
133.1537 +/* obtain column solution information (obsolete) */
133.1538 +
133.1539 +#define lpx_get_ray_info _glp_lpx_get_ray_info
133.1540 +int lpx_get_ray_info(LPX *lp);
133.1541 +/* determine what causes primal unboundness */
133.1542 +
133.1543 +#define lpx_check_kkt _glp_lpx_check_kkt
133.1544 +void lpx_check_kkt(LPX *lp, int scaled, LPXKKT *kkt);
133.1545 +/* check Karush-Kuhn-Tucker conditions */
133.1546 +
133.1547 +#define lpx_warm_up _glp_lpx_warm_up
133.1548 +int lpx_warm_up(LPX *lp);
133.1549 +/* "warm up" LP basis */
133.1550 +
133.1551 +#define lpx_eval_tab_row _glp_lpx_eval_tab_row
133.1552 +int lpx_eval_tab_row(LPX *lp, int k, int ind[], double val[]);
133.1553 +/* compute row of the simplex table */
133.1554 +
133.1555 +#define lpx_eval_tab_col _glp_lpx_eval_tab_col
133.1556 +int lpx_eval_tab_col(LPX *lp, int k, int ind[], double val[]);
133.1557 +/* compute column of the simplex table */
133.1558 +
133.1559 +#define lpx_transform_row _glp_lpx_transform_row
133.1560 +int lpx_transform_row(LPX *lp, int len, int ind[], double val[]);
133.1561 +/* transform explicitly specified row */
133.1562 +
133.1563 +#define lpx_transform_col _glp_lpx_transform_col
133.1564 +int lpx_transform_col(LPX *lp, int len, int ind[], double val[]);
133.1565 +/* transform explicitly specified column */
133.1566 +
133.1567 +#define lpx_prim_ratio_test _glp_lpx_prim_ratio_test
133.1568 +int lpx_prim_ratio_test(LPX *lp, int len, const int ind[],
133.1569 + const double val[], int how, double tol);
133.1570 +/* perform primal ratio test */
133.1571 +
133.1572 +#define lpx_dual_ratio_test _glp_lpx_dual_ratio_test
133.1573 +int lpx_dual_ratio_test(LPX *lp, int len, const int ind[],
133.1574 + const double val[], int how, double tol);
133.1575 +/* perform dual ratio test */
133.1576 +
133.1577 +#define lpx_interior _glp_lpx_interior
133.1578 +int lpx_interior(LPX *lp);
133.1579 +/* easy-to-use driver to the interior point method */
133.1580 +
133.1581 +#define lpx_ipt_status _glp_lpx_ipt_status
133.1582 +int lpx_ipt_status(LPX *lp);
133.1583 +/* retrieve status of interior-point solution */
133.1584 +
133.1585 +#define lpx_ipt_obj_val _glp_lpx_ipt_obj_val
133.1586 +double lpx_ipt_obj_val(LPX *lp);
133.1587 +/* retrieve objective value (interior point) */
133.1588 +
133.1589 +#define lpx_ipt_row_prim _glp_lpx_ipt_row_prim
133.1590 +double lpx_ipt_row_prim(LPX *lp, int i);
133.1591 +/* retrieve row primal value (interior point) */
133.1592 +
133.1593 +#define lpx_ipt_row_dual _glp_lpx_ipt_row_dual
133.1594 +double lpx_ipt_row_dual(LPX *lp, int i);
133.1595 +/* retrieve row dual value (interior point) */
133.1596 +
133.1597 +#define lpx_ipt_col_prim _glp_lpx_ipt_col_prim
133.1598 +double lpx_ipt_col_prim(LPX *lp, int j);
133.1599 +/* retrieve column primal value (interior point) */
133.1600 +
133.1601 +#define lpx_ipt_col_dual _glp_lpx_ipt_col_dual
133.1602 +double lpx_ipt_col_dual(LPX *lp, int j);
133.1603 +/* retrieve column dual value (interior point) */
133.1604 +
133.1605 +#define lpx_set_class _glp_lpx_set_class
133.1606 +void lpx_set_class(LPX *lp, int klass);
133.1607 +/* set problem class */
133.1608 +
133.1609 +#define lpx_get_class _glp_lpx_get_class
133.1610 +int lpx_get_class(LPX *lp);
133.1611 +/* determine problem klass */
133.1612 +
133.1613 +#define lpx_set_col_kind _glp_lpx_set_col_kind
133.1614 +void lpx_set_col_kind(LPX *lp, int j, int kind);
133.1615 +/* set (change) column kind */
133.1616 +
133.1617 +#define lpx_get_col_kind _glp_lpx_get_col_kind
133.1618 +int lpx_get_col_kind(LPX *lp, int j);
133.1619 +/* retrieve column kind */
133.1620 +
133.1621 +#define lpx_get_num_int _glp_lpx_get_num_int
133.1622 +int lpx_get_num_int(LPX *lp);
133.1623 +/* retrieve number of integer columns */
133.1624 +
133.1625 +#define lpx_get_num_bin _glp_lpx_get_num_bin
133.1626 +int lpx_get_num_bin(LPX *lp);
133.1627 +/* retrieve number of binary columns */
133.1628 +
133.1629 +#define lpx_integer _glp_lpx_integer
133.1630 +int lpx_integer(LPX *lp);
133.1631 +/* easy-to-use driver to the branch-and-bound method */
133.1632 +
133.1633 +#define lpx_intopt _glp_lpx_intopt
133.1634 +int lpx_intopt(LPX *lp);
133.1635 +/* easy-to-use driver to the branch-and-bound method */
133.1636 +
133.1637 +#define lpx_mip_status _glp_lpx_mip_status
133.1638 +int lpx_mip_status(LPX *lp);
133.1639 +/* retrieve status of MIP solution */
133.1640 +
133.1641 +#define lpx_mip_obj_val _glp_lpx_mip_obj_val
133.1642 +double lpx_mip_obj_val(LPX *lp);
133.1643 +/* retrieve objective value (MIP solution) */
133.1644 +
133.1645 +#define lpx_mip_row_val _glp_lpx_mip_row_val
133.1646 +double lpx_mip_row_val(LPX *lp, int i);
133.1647 +/* retrieve row value (MIP solution) */
133.1648 +
133.1649 +#define lpx_mip_col_val _glp_lpx_mip_col_val
133.1650 +double lpx_mip_col_val(LPX *lp, int j);
133.1651 +/* retrieve column value (MIP solution) */
133.1652 +
133.1653 +#define lpx_check_int _glp_lpx_check_int
133.1654 +void lpx_check_int(LPX *lp, LPXKKT *kkt);
133.1655 +/* check integer feasibility conditions */
133.1656 +
133.1657 +#define lpx_reset_parms _glp_lpx_reset_parms
133.1658 +void lpx_reset_parms(LPX *lp);
133.1659 +/* reset control parameters to default values */
133.1660 +
133.1661 +#define lpx_set_int_parm _glp_lpx_set_int_parm
133.1662 +void lpx_set_int_parm(LPX *lp, int parm, int val);
133.1663 +/* set (change) integer control parameter */
133.1664 +
133.1665 +#define lpx_get_int_parm _glp_lpx_get_int_parm
133.1666 +int lpx_get_int_parm(LPX *lp, int parm);
133.1667 +/* query integer control parameter */
133.1668 +
133.1669 +#define lpx_set_real_parm _glp_lpx_set_real_parm
133.1670 +void lpx_set_real_parm(LPX *lp, int parm, double val);
133.1671 +/* set (change) real control parameter */
133.1672 +
133.1673 +#define lpx_get_real_parm _glp_lpx_get_real_parm
133.1674 +double lpx_get_real_parm(LPX *lp, int parm);
133.1675 +/* query real control parameter */
133.1676 +
133.1677 +#define lpx_read_mps _glp_lpx_read_mps
133.1678 +LPX *lpx_read_mps(const char *fname);
133.1679 +/* read problem data in fixed MPS format */
133.1680 +
133.1681 +#define lpx_write_mps _glp_lpx_write_mps
133.1682 +int lpx_write_mps(LPX *lp, const char *fname);
133.1683 +/* write problem data in fixed MPS format */
133.1684 +
133.1685 +#define lpx_read_bas _glp_lpx_read_bas
133.1686 +int lpx_read_bas(LPX *lp, const char *fname);
133.1687 +/* read LP basis in fixed MPS format */
133.1688 +
133.1689 +#define lpx_write_bas _glp_lpx_write_bas
133.1690 +int lpx_write_bas(LPX *lp, const char *fname);
133.1691 +/* write LP basis in fixed MPS format */
133.1692 +
133.1693 +#define lpx_read_freemps _glp_lpx_read_freemps
133.1694 +LPX *lpx_read_freemps(const char *fname);
133.1695 +/* read problem data in free MPS format */
133.1696 +
133.1697 +#define lpx_write_freemps _glp_lpx_write_freemps
133.1698 +int lpx_write_freemps(LPX *lp, const char *fname);
133.1699 +/* write problem data in free MPS format */
133.1700 +
133.1701 +#define lpx_read_cpxlp _glp_lpx_read_cpxlp
133.1702 +LPX *lpx_read_cpxlp(const char *fname);
133.1703 +/* read problem data in CPLEX LP format */
133.1704 +
133.1705 +#define lpx_write_cpxlp _glp_lpx_write_cpxlp
133.1706 +int lpx_write_cpxlp(LPX *lp, const char *fname);
133.1707 +/* write problem data in CPLEX LP format */
133.1708 +
133.1709 +#define lpx_read_model _glp_lpx_read_model
133.1710 +LPX *lpx_read_model(const char *model, const char *data,
133.1711 + const char *output);
133.1712 +/* read LP/MIP model written in GNU MathProg language */
133.1713 +
133.1714 +#define lpx_print_prob _glp_lpx_print_prob
133.1715 +int lpx_print_prob(LPX *lp, const char *fname);
133.1716 +/* write problem data in plain text format */
133.1717 +
133.1718 +#define lpx_print_sol _glp_lpx_print_sol
133.1719 +int lpx_print_sol(LPX *lp, const char *fname);
133.1720 +/* write LP problem solution in printable format */
133.1721 +
133.1722 +#define lpx_print_sens_bnds _glp_lpx_print_sens_bnds
133.1723 +int lpx_print_sens_bnds(LPX *lp, const char *fname);
133.1724 +/* write bounds sensitivity information */
133.1725 +
133.1726 +#define lpx_print_ips _glp_lpx_print_ips
133.1727 +int lpx_print_ips(LPX *lp, const char *fname);
133.1728 +/* write interior point solution in printable format */
133.1729 +
133.1730 +#define lpx_print_mip _glp_lpx_print_mip
133.1731 +int lpx_print_mip(LPX *lp, const char *fname);
133.1732 +/* write MIP problem solution in printable format */
133.1733 +
133.1734 +#define lpx_is_b_avail _glp_lpx_is_b_avail
133.1735 +int lpx_is_b_avail(LPX *lp);
133.1736 +/* check if LP basis is available */
133.1737 +
133.1738 +#define lpx_write_pb _glp_lpx_write_pb
133.1739 +int lpx_write_pb(LPX *lp, const char *fname, int normalized,
133.1740 + int binarize);
133.1741 +/* write problem data in (normalized) OPB format */
133.1742 +
133.1743 +#define lpx_main _glp_lpx_main
133.1744 +int lpx_main(int argc, const char *argv[]);
133.1745 +/* stand-alone LP/MIP solver */
133.1746 +
133.1747 +#ifdef __cplusplus
133.1748 +}
133.1749 +#endif
133.1750 +
133.1751 +#endif
133.1752 +
133.1753 +/* eof */
134.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
134.2 +++ b/src/Makefile.am Mon Dec 06 13:09:21 2010 +0100
134.3 @@ -0,0 +1,121 @@
134.4 +## Process this file with automake to produce Makefile.in ##
134.5 +
134.6 +INCLUDES = -I$(srcdir)/../include
134.7 +
134.8 +lib_LTLIBRARIES = libglpk.la
134.9 +
134.10 +libglpk_la_LDFLAGS = -version-info 30:0:30 \
134.11 +-export-symbols-regex '^(glp_|_glp_lpx_).*'
134.12 +
134.13 +libglpk_la_SOURCES = \
134.14 +glpapi01.c \
134.15 +glpapi02.c \
134.16 +glpapi03.c \
134.17 +glpapi04.c \
134.18 +glpapi05.c \
134.19 +glpapi06.c \
134.20 +glpapi07.c \
134.21 +glpapi08.c \
134.22 +glpapi09.c \
134.23 +glpapi10.c \
134.24 +glpapi11.c \
134.25 +glpapi12.c \
134.26 +glpapi13.c \
134.27 +glpapi14.c \
134.28 +glpapi15.c \
134.29 +glpapi16.c \
134.30 +glpapi17.c \
134.31 +glpapi18.c \
134.32 +glpapi19.c \
134.33 +glpavl.c \
134.34 +glpbfd.c \
134.35 +glpbfx.c \
134.36 +glpcpx.c \
134.37 +glpdmp.c \
134.38 +glpdmx.c \
134.39 +glpenv01.c \
134.40 +glpenv02.c \
134.41 +glpenv03.c \
134.42 +glpenv04.c \
134.43 +glpenv05.c \
134.44 +glpenv06.c \
134.45 +glpenv07.c \
134.46 +glpenv08.c \
134.47 +glpfhv.c \
134.48 +glpgmp.c \
134.49 +glphbm.c \
134.50 +glpini01.c \
134.51 +glpini02.c \
134.52 +glpios01.c \
134.53 +glpios02.c \
134.54 +glpios03.c \
134.55 +glpios04.c \
134.56 +glpios05.c \
134.57 +glpios06.c \
134.58 +glpios07.c \
134.59 +glpios08.c \
134.60 +glpios09.c \
134.61 +glpios10.c \
134.62 +glpios11.c \
134.63 +glpios12.c \
134.64 +glpipm.c \
134.65 +glplib01.c \
134.66 +glplib02.c \
134.67 +glplib03.c \
134.68 +glplpf.c \
134.69 +glplpx01.c \
134.70 +glplpx02.c \
134.71 +glplpx03.c \
134.72 +glpluf.c \
134.73 +glplux.c \
134.74 +glpmat.c \
134.75 +glpmpl01.c \
134.76 +glpmpl02.c \
134.77 +glpmpl03.c \
134.78 +glpmpl04.c \
134.79 +glpmpl05.c \
134.80 +glpmpl06.c \
134.81 +glpmps.c \
134.82 +glpnet01.c \
134.83 +glpnet02.c \
134.84 +glpnet03.c \
134.85 +glpnet04.c \
134.86 +glpnet05.c \
134.87 +glpnet06.c \
134.88 +glpnet07.c \
134.89 +glpnet08.c \
134.90 +glpnet09.c \
134.91 +glpnpp01.c \
134.92 +glpnpp02.c \
134.93 +glpnpp03.c \
134.94 +glpnpp04.c \
134.95 +glpnpp05.c \
134.96 +glpqmd.c \
134.97 +glprgr.c \
134.98 +glprng01.c \
134.99 +glprng02.c \
134.100 +glpscf.c \
134.101 +glpscl.c \
134.102 +glpsdf.c \
134.103 +glpspm.c \
134.104 +glpspx01.c \
134.105 +glpspx02.c \
134.106 +glpsql.c \
134.107 +glpssx01.c \
134.108 +glpssx02.c \
134.109 +glptsp.c \
134.110 +amd/amd_1.c \
134.111 +amd/amd_2.c \
134.112 +amd/amd_aat.c \
134.113 +amd/amd_control.c \
134.114 +amd/amd_defaults.c \
134.115 +amd/amd_dump.c \
134.116 +amd/amd_info.c \
134.117 +amd/amd_order.c \
134.118 +amd/amd_post_tree.c \
134.119 +amd/amd_postorder.c \
134.120 +amd/amd_preprocess.c \
134.121 +amd/amd_valid.c \
134.122 +colamd/colamd.c
134.123 +
134.124 +## eof ##
135.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
135.2 +++ b/src/amd/COPYING Mon Dec 06 13:09:21 2010 +0100
135.3 @@ -0,0 +1,502 @@
135.4 + GNU LESSER GENERAL PUBLIC LICENSE
135.5 + Version 2.1, February 1999
135.6 +
135.7 + Copyright (C) 1991, 1999 Free Software Foundation, Inc.
135.8 + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
135.9 + Everyone is permitted to copy and distribute verbatim copies
135.10 + of this license document, but changing it is not allowed.
135.11 +
135.12 +[This is the first released version of the Lesser GPL. It also counts
135.13 + as the successor of the GNU Library Public License, version 2, hence
135.14 + the version number 2.1.]
135.15 +
135.16 + Preamble
135.17 +
135.18 + The licenses for most software are designed to take away your
135.19 +freedom to share and change it. By contrast, the GNU General Public
135.20 +Licenses are intended to guarantee your freedom to share and change
135.21 +free software--to make sure the software is free for all its users.
135.22 +
135.23 + This license, the Lesser General Public License, applies to some
135.24 +specially designated software packages--typically libraries--of the
135.25 +Free Software Foundation and other authors who decide to use it. You
135.26 +can use it too, but we suggest you first think carefully about whether
135.27 +this license or the ordinary General Public License is the better
135.28 +strategy to use in any particular case, based on the explanations below.
135.29 +
135.30 + When we speak of free software, we are referring to freedom of use,
135.31 +not price. Our General Public Licenses are designed to make sure that
135.32 +you have the freedom to distribute copies of free software (and charge
135.33 +for this service if you wish); that you receive source code or can get
135.34 +it if you want it; that you can change the software and use pieces of
135.35 +it in new free programs; and that you are informed that you can do
135.36 +these things.
135.37 +
135.38 + To protect your rights, we need to make restrictions that forbid
135.39 +distributors to deny you these rights or to ask you to surrender these
135.40 +rights. These restrictions translate to certain responsibilities for
135.41 +you if you distribute copies of the library or if you modify it.
135.42 +
135.43 + For example, if you distribute copies of the library, whether gratis
135.44 +or for a fee, you must give the recipients all the rights that we gave
135.45 +you. You must make sure that they, too, receive or can get the source
135.46 +code. If you link other code with the library, you must provide
135.47 +complete object files to the recipients, so that they can relink them
135.48 +with the library after making changes to the library and recompiling
135.49 +it. And you must show them these terms so they know their rights.
135.50 +
135.51 + We protect your rights with a two-step method: (1) we copyright the
135.52 +library, and (2) we offer you this license, which gives you legal
135.53 +permission to copy, distribute and/or modify the library.
135.54 +
135.55 + To protect each distributor, we want to make it very clear that
135.56 +there is no warranty for the free library. Also, if the library is
135.57 +modified by someone else and passed on, the recipients should know
135.58 +that what they have is not the original version, so that the original
135.59 +author's reputation will not be affected by problems that might be
135.60 +introduced by others.
135.61 +
135.62 + Finally, software patents pose a constant threat to the existence of
135.63 +any free program. We wish to make sure that a company cannot
135.64 +effectively restrict the users of a free program by obtaining a
135.65 +restrictive license from a patent holder. Therefore, we insist that
135.66 +any patent license obtained for a version of the library must be
135.67 +consistent with the full freedom of use specified in this license.
135.68 +
135.69 + Most GNU software, including some libraries, is covered by the
135.70 +ordinary GNU General Public License. This license, the GNU Lesser
135.71 +General Public License, applies to certain designated libraries, and
135.72 +is quite different from the ordinary General Public License. We use
135.73 +this license for certain libraries in order to permit linking those
135.74 +libraries into non-free programs.
135.75 +
135.76 + When a program is linked with a library, whether statically or using
135.77 +a shared library, the combination of the two is legally speaking a
135.78 +combined work, a derivative of the original library. The ordinary
135.79 +General Public License therefore permits such linking only if the
135.80 +entire combination fits its criteria of freedom. The Lesser General
135.81 +Public License permits more lax criteria for linking other code with
135.82 +the library.
135.83 +
135.84 + We call this license the "Lesser" General Public License because it
135.85 +does Less to protect the user's freedom than the ordinary General
135.86 +Public License. It also provides other free software developers Less
135.87 +of an advantage over competing non-free programs. These disadvantages
135.88 +are the reason we use the ordinary General Public License for many
135.89 +libraries. However, the Lesser license provides advantages in certain
135.90 +special circumstances.
135.91 +
135.92 + For example, on rare occasions, there may be a special need to
135.93 +encourage the widest possible use of a certain library, so that it becomes
135.94 +a de-facto standard. To achieve this, non-free programs must be
135.95 +allowed to use the library. A more frequent case is that a free
135.96 +library does the same job as widely used non-free libraries. In this
135.97 +case, there is little to gain by limiting the free library to free
135.98 +software only, so we use the Lesser General Public License.
135.99 +
135.100 + In other cases, permission to use a particular library in non-free
135.101 +programs enables a greater number of people to use a large body of
135.102 +free software. For example, permission to use the GNU C Library in
135.103 +non-free programs enables many more people to use the whole GNU
135.104 +operating system, as well as its variant, the GNU/Linux operating
135.105 +system.
135.106 +
135.107 + Although the Lesser General Public License is Less protective of the
135.108 +users' freedom, it does ensure that the user of a program that is
135.109 +linked with the Library has the freedom and the wherewithal to run
135.110 +that program using a modified version of the Library.
135.111 +
135.112 + The precise terms and conditions for copying, distribution and
135.113 +modification follow. Pay close attention to the difference between a
135.114 +"work based on the library" and a "work that uses the library". The
135.115 +former contains code derived from the library, whereas the latter must
135.116 +be combined with the library in order to run.
135.117 +
135.118 + GNU LESSER GENERAL PUBLIC LICENSE
135.119 + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
135.120 +
135.121 + 0. This License Agreement applies to any software library or other
135.122 +program which contains a notice placed by the copyright holder or
135.123 +other authorized party saying it may be distributed under the terms of
135.124 +this Lesser General Public License (also called "this License").
135.125 +Each licensee is addressed as "you".
135.126 +
135.127 + A "library" means a collection of software functions and/or data
135.128 +prepared so as to be conveniently linked with application programs
135.129 +(which use some of those functions and data) to form executables.
135.130 +
135.131 + The "Library", below, refers to any such software library or work
135.132 +which has been distributed under these terms. A "work based on the
135.133 +Library" means either the Library or any derivative work under
135.134 +copyright law: that is to say, a work containing the Library or a
135.135 +portion of it, either verbatim or with modifications and/or translated
135.136 +straightforwardly into another language. (Hereinafter, translation is
135.137 +included without limitation in the term "modification".)
135.138 +
135.139 + "Source code" for a work means the preferred form of the work for
135.140 +making modifications to it. For a library, complete source code means
135.141 +all the source code for all modules it contains, plus any associated
135.142 +interface definition files, plus the scripts used to control compilation
135.143 +and installation of the library.
135.144 +
135.145 + Activities other than copying, distribution and modification are not
135.146 +covered by this License; they are outside its scope. The act of
135.147 +running a program using the Library is not restricted, and output from
135.148 +such a program is covered only if its contents constitute a work based
135.149 +on the Library (independent of the use of the Library in a tool for
135.150 +writing it). Whether that is true depends on what the Library does
135.151 +and what the program that uses the Library does.
135.152 +
135.153 + 1. You may copy and distribute verbatim copies of the Library's
135.154 +complete source code as you receive it, in any medium, provided that
135.155 +you conspicuously and appropriately publish on each copy an
135.156 +appropriate copyright notice and disclaimer of warranty; keep intact
135.157 +all the notices that refer to this License and to the absence of any
135.158 +warranty; and distribute a copy of this License along with the
135.159 +Library.
135.160 +
135.161 + You may charge a fee for the physical act of transferring a copy,
135.162 +and you may at your option offer warranty protection in exchange for a
135.163 +fee.
135.164 +
135.165 + 2. You may modify your copy or copies of the Library or any portion
135.166 +of it, thus forming a work based on the Library, and copy and
135.167 +distribute such modifications or work under the terms of Section 1
135.168 +above, provided that you also meet all of these conditions:
135.169 +
135.170 + a) The modified work must itself be a software library.
135.171 +
135.172 + b) You must cause the files modified to carry prominent notices
135.173 + stating that you changed the files and the date of any change.
135.174 +
135.175 + c) You must cause the whole of the work to be licensed at no
135.176 + charge to all third parties under the terms of this License.
135.177 +
135.178 + d) If a facility in the modified Library refers to a function or a
135.179 + table of data to be supplied by an application program that uses
135.180 + the facility, other than as an argument passed when the facility
135.181 + is invoked, then you must make a good faith effort to ensure that,
135.182 + in the event an application does not supply such function or
135.183 + table, the facility still operates, and performs whatever part of
135.184 + its purpose remains meaningful.
135.185 +
135.186 + (For example, a function in a library to compute square roots has
135.187 + a purpose that is entirely well-defined independent of the
135.188 + application. Therefore, Subsection 2d requires that any
135.189 + application-supplied function or table used by this function must
135.190 + be optional: if the application does not supply it, the square
135.191 + root function must still compute square roots.)
135.192 +
135.193 +These requirements apply to the modified work as a whole. If
135.194 +identifiable sections of that work are not derived from the Library,
135.195 +and can be reasonably considered independent and separate works in
135.196 +themselves, then this License, and its terms, do not apply to those
135.197 +sections when you distribute them as separate works. But when you
135.198 +distribute the same sections as part of a whole which is a work based
135.199 +on the Library, the distribution of the whole must be on the terms of
135.200 +this License, whose permissions for other licensees extend to the
135.201 +entire whole, and thus to each and every part regardless of who wrote
135.202 +it.
135.203 +
135.204 +Thus, it is not the intent of this section to claim rights or contest
135.205 +your rights to work written entirely by you; rather, the intent is to
135.206 +exercise the right to control the distribution of derivative or
135.207 +collective works based on the Library.
135.208 +
135.209 +In addition, mere aggregation of another work not based on the Library
135.210 +with the Library (or with a work based on the Library) on a volume of
135.211 +a storage or distribution medium does not bring the other work under
135.212 +the scope of this License.
135.213 +
135.214 + 3. You may opt to apply the terms of the ordinary GNU General Public
135.215 +License instead of this License to a given copy of the Library. To do
135.216 +this, you must alter all the notices that refer to this License, so
135.217 +that they refer to the ordinary GNU General Public License, version 2,
135.218 +instead of to this License. (If a newer version than version 2 of the
135.219 +ordinary GNU General Public License has appeared, then you can specify
135.220 +that version instead if you wish.) Do not make any other change in
135.221 +these notices.
135.222 +
135.223 + Once this change is made in a given copy, it is irreversible for
135.224 +that copy, so the ordinary GNU General Public License applies to all
135.225 +subsequent copies and derivative works made from that copy.
135.226 +
135.227 + This option is useful when you wish to copy part of the code of
135.228 +the Library into a program that is not a library.
135.229 +
135.230 + 4. You may copy and distribute the Library (or a portion or
135.231 +derivative of it, under Section 2) in object code or executable form
135.232 +under the terms of Sections 1 and 2 above provided that you accompany
135.233 +it with the complete corresponding machine-readable source code, which
135.234 +must be distributed under the terms of Sections 1 and 2 above on a
135.235 +medium customarily used for software interchange.
135.236 +
135.237 + If distribution of object code is made by offering access to copy
135.238 +from a designated place, then offering equivalent access to copy the
135.239 +source code from the same place satisfies the requirement to
135.240 +distribute the source code, even though third parties are not
135.241 +compelled to copy the source along with the object code.
135.242 +
135.243 + 5. A program that contains no derivative of any portion of the
135.244 +Library, but is designed to work with the Library by being compiled or
135.245 +linked with it, is called a "work that uses the Library". Such a
135.246 +work, in isolation, is not a derivative work of the Library, and
135.247 +therefore falls outside the scope of this License.
135.248 +
135.249 + However, linking a "work that uses the Library" with the Library
135.250 +creates an executable that is a derivative of the Library (because it
135.251 +contains portions of the Library), rather than a "work that uses the
135.252 +library". The executable is therefore covered by this License.
135.253 +Section 6 states terms for distribution of such executables.
135.254 +
135.255 + When a "work that uses the Library" uses material from a header file
135.256 +that is part of the Library, the object code for the work may be a
135.257 +derivative work of the Library even though the source code is not.
135.258 +Whether this is true is especially significant if the work can be
135.259 +linked without the Library, or if the work is itself a library. The
135.260 +threshold for this to be true is not precisely defined by law.
135.261 +
135.262 + If such an object file uses only numerical parameters, data
135.263 +structure layouts and accessors, and small macros and small inline
135.264 +functions (ten lines or less in length), then the use of the object
135.265 +file is unrestricted, regardless of whether it is legally a derivative
135.266 +work. (Executables containing this object code plus portions of the
135.267 +Library will still fall under Section 6.)
135.268 +
135.269 + Otherwise, if the work is a derivative of the Library, you may
135.270 +distribute the object code for the work under the terms of Section 6.
135.271 +Any executables containing that work also fall under Section 6,
135.272 +whether or not they are linked directly with the Library itself.
135.273 +
135.274 + 6. As an exception to the Sections above, you may also combine or
135.275 +link a "work that uses the Library" with the Library to produce a
135.276 +work containing portions of the Library, and distribute that work
135.277 +under terms of your choice, provided that the terms permit
135.278 +modification of the work for the customer's own use and reverse
135.279 +engineering for debugging such modifications.
135.280 +
135.281 + You must give prominent notice with each copy of the work that the
135.282 +Library is used in it and that the Library and its use are covered by
135.283 +this License. You must supply a copy of this License. If the work
135.284 +during execution displays copyright notices, you must include the
135.285 +copyright notice for the Library among them, as well as a reference
135.286 +directing the user to the copy of this License. Also, you must do one
135.287 +of these things:
135.288 +
135.289 + a) Accompany the work with the complete corresponding
135.290 + machine-readable source code for the Library including whatever
135.291 + changes were used in the work (which must be distributed under
135.292 + Sections 1 and 2 above); and, if the work is an executable linked
135.293 + with the Library, with the complete machine-readable "work that
135.294 + uses the Library", as object code and/or source code, so that the
135.295 + user can modify the Library and then relink to produce a modified
135.296 + executable containing the modified Library. (It is understood
135.297 + that the user who changes the contents of definitions files in the
135.298 + Library will not necessarily be able to recompile the application
135.299 + to use the modified definitions.)
135.300 +
135.301 + b) Use a suitable shared library mechanism for linking with the
135.302 + Library. A suitable mechanism is one that (1) uses at run time a
135.303 + copy of the library already present on the user's computer system,
135.304 + rather than copying library functions into the executable, and (2)
135.305 + will operate properly with a modified version of the library, if
135.306 + the user installs one, as long as the modified version is
135.307 + interface-compatible with the version that the work was made with.
135.308 +
135.309 + c) Accompany the work with a written offer, valid for at
135.310 + least three years, to give the same user the materials
135.311 + specified in Subsection 6a, above, for a charge no more
135.312 + than the cost of performing this distribution.
135.313 +
135.314 + d) If distribution of the work is made by offering access to copy
135.315 + from a designated place, offer equivalent access to copy the above
135.316 + specified materials from the same place.
135.317 +
135.318 + e) Verify that the user has already received a copy of these
135.319 + materials or that you have already sent this user a copy.
135.320 +
135.321 + For an executable, the required form of the "work that uses the
135.322 +Library" must include any data and utility programs needed for
135.323 +reproducing the executable from it. However, as a special exception,
135.324 +the materials to be distributed need not include anything that is
135.325 +normally distributed (in either source or binary form) with the major
135.326 +components (compiler, kernel, and so on) of the operating system on
135.327 +which the executable runs, unless that component itself accompanies
135.328 +the executable.
135.329 +
135.330 + It may happen that this requirement contradicts the license
135.331 +restrictions of other proprietary libraries that do not normally
135.332 +accompany the operating system. Such a contradiction means you cannot
135.333 +use both them and the Library together in an executable that you
135.334 +distribute.
135.335 +
135.336 + 7. You may place library facilities that are a work based on the
135.337 +Library side-by-side in a single library together with other library
135.338 +facilities not covered by this License, and distribute such a combined
135.339 +library, provided that the separate distribution of the work based on
135.340 +the Library and of the other library facilities is otherwise
135.341 +permitted, and provided that you do these two things:
135.342 +
135.343 + a) Accompany the combined library with a copy of the same work
135.344 + based on the Library, uncombined with any other library
135.345 + facilities. This must be distributed under the terms of the
135.346 + Sections above.
135.347 +
135.348 + b) Give prominent notice with the combined library of the fact
135.349 + that part of it is a work based on the Library, and explaining
135.350 + where to find the accompanying uncombined form of the same work.
135.351 +
135.352 + 8. You may not copy, modify, sublicense, link with, or distribute
135.353 +the Library except as expressly provided under this License. Any
135.354 +attempt otherwise to copy, modify, sublicense, link with, or
135.355 +distribute the Library is void, and will automatically terminate your
135.356 +rights under this License. However, parties who have received copies,
135.357 +or rights, from you under this License will not have their licenses
135.358 +terminated so long as such parties remain in full compliance.
135.359 +
135.360 + 9. You are not required to accept this License, since you have not
135.361 +signed it. However, nothing else grants you permission to modify or
135.362 +distribute the Library or its derivative works. These actions are
135.363 +prohibited by law if you do not accept this License. Therefore, by
135.364 +modifying or distributing the Library (or any work based on the
135.365 +Library), you indicate your acceptance of this License to do so, and
135.366 +all its terms and conditions for copying, distributing or modifying
135.367 +the Library or works based on it.
135.368 +
135.369 + 10. Each time you redistribute the Library (or any work based on the
135.370 +Library), the recipient automatically receives a license from the
135.371 +original licensor to copy, distribute, link with or modify the Library
135.372 +subject to these terms and conditions. You may not impose any further
135.373 +restrictions on the recipients' exercise of the rights granted herein.
135.374 +You are not responsible for enforcing compliance by third parties with
135.375 +this License.
135.376 +
135.377 + 11. If, as a consequence of a court judgment or allegation of patent
135.378 +infringement or for any other reason (not limited to patent issues),
135.379 +conditions are imposed on you (whether by court order, agreement or
135.380 +otherwise) that contradict the conditions of this License, they do not
135.381 +excuse you from the conditions of this License. If you cannot
135.382 +distribute so as to satisfy simultaneously your obligations under this
135.383 +License and any other pertinent obligations, then as a consequence you
135.384 +may not distribute the Library at all. For example, if a patent
135.385 +license would not permit royalty-free redistribution of the Library by
135.386 +all those who receive copies directly or indirectly through you, then
135.387 +the only way you could satisfy both it and this License would be to
135.388 +refrain entirely from distribution of the Library.
135.389 +
135.390 +If any portion of this section is held invalid or unenforceable under any
135.391 +particular circumstance, the balance of the section is intended to apply,
135.392 +and the section as a whole is intended to apply in other circumstances.
135.393 +
135.394 +It is not the purpose of this section to induce you to infringe any
135.395 +patents or other property right claims or to contest validity of any
135.396 +such claims; this section has the sole purpose of protecting the
135.397 +integrity of the free software distribution system which is
135.398 +implemented by public license practices. Many people have made
135.399 +generous contributions to the wide range of software distributed
135.400 +through that system in reliance on consistent application of that
135.401 +system; it is up to the author/donor to decide if he or she is willing
135.402 +to distribute software through any other system and a licensee cannot
135.403 +impose that choice.
135.404 +
135.405 +This section is intended to make thoroughly clear what is believed to
135.406 +be a consequence of the rest of this License.
135.407 +
135.408 + 12. If the distribution and/or use of the Library is restricted in
135.409 +certain countries either by patents or by copyrighted interfaces, the
135.410 +original copyright holder who places the Library under this License may add
135.411 +an explicit geographical distribution limitation excluding those countries,
135.412 +so that distribution is permitted only in or among countries not thus
135.413 +excluded. In such case, this License incorporates the limitation as if
135.414 +written in the body of this License.
135.415 +
135.416 + 13. The Free Software Foundation may publish revised and/or new
135.417 +versions of the Lesser General Public License from time to time.
135.418 +Such new versions will be similar in spirit to the present version,
135.419 +but may differ in detail to address new problems or concerns.
135.420 +
135.421 +Each version is given a distinguishing version number. If the Library
135.422 +specifies a version number of this License which applies to it and
135.423 +"any later version", you have the option of following the terms and
135.424 +conditions either of that version or of any later version published by
135.425 +the Free Software Foundation. If the Library does not specify a
135.426 +license version number, you may choose any version ever published by
135.427 +the Free Software Foundation.
135.428 +
135.429 + 14. If you wish to incorporate parts of the Library into other free
135.430 +programs whose distribution conditions are incompatible with these,
135.431 +write to the author to ask for permission. For software which is
135.432 +copyrighted by the Free Software Foundation, write to the Free
135.433 +Software Foundation; we sometimes make exceptions for this. Our
135.434 +decision will be guided by the two goals of preserving the free status
135.435 +of all derivatives of our free software and of promoting the sharing
135.436 +and reuse of software generally.
135.437 +
135.438 + NO WARRANTY
135.439 +
135.440 + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
135.441 +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
135.442 +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
135.443 +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
135.444 +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
135.445 +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
135.446 +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
135.447 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
135.448 +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
135.449 +
135.450 + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
135.451 +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
135.452 +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
135.453 +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
135.454 +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
135.455 +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
135.456 +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
135.457 +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
135.458 +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
135.459 +DAMAGES.
135.460 +
135.461 + END OF TERMS AND CONDITIONS
135.462 +
135.463 + How to Apply These Terms to Your New Libraries
135.464 +
135.465 + If you develop a new library, and you want it to be of the greatest
135.466 +possible use to the public, we recommend making it free software that
135.467 +everyone can redistribute and change. You can do so by permitting
135.468 +redistribution under these terms (or, alternatively, under the terms of the
135.469 +ordinary General Public License).
135.470 +
135.471 + To apply these terms, attach the following notices to the library. It is
135.472 +safest to attach them to the start of each source file to most effectively
135.473 +convey the exclusion of warranty; and each file should have at least the
135.474 +"copyright" line and a pointer to where the full notice is found.
135.475 +
135.476 + <one line to give the library's name and a brief idea of what it does.>
135.477 + Copyright (C) <year> <name of author>
135.478 +
135.479 + This library is free software; you can redistribute it and/or
135.480 + modify it under the terms of the GNU Lesser General Public
135.481 + License as published by the Free Software Foundation; either
135.482 + version 2.1 of the License, or (at your option) any later version.
135.483 +
135.484 + This library is distributed in the hope that it will be useful,
135.485 + but WITHOUT ANY WARRANTY; without even the implied warranty of
135.486 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
135.487 + Lesser General Public License for more details.
135.488 +
135.489 + You should have received a copy of the GNU Lesser General Public
135.490 + License along with this library; if not, write to the Free Software
135.491 + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
135.492 +
135.493 +Also add information on how to contact you by electronic and paper mail.
135.494 +
135.495 +You should also get your employer (if you work as a programmer) or your
135.496 +school, if any, to sign a "copyright disclaimer" for the library, if
135.497 +necessary. Here is a sample; alter the names:
135.498 +
135.499 + Yoyodyne, Inc., hereby disclaims all copyright interest in the
135.500 + library `Frob' (a library for tweaking knobs) written by James Random Hacker.
135.501 +
135.502 + <signature of Ty Coon>, 1 April 1990
135.503 + Ty Coon, President of Vice
135.504 +
135.505 +That's all there is to it!
136.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
136.2 +++ b/src/amd/README Mon Dec 06 13:09:21 2010 +0100
136.3 @@ -0,0 +1,58 @@
136.4 +NOTE: Files in this subdirectory are NOT part of the GLPK package, but
136.5 + are used with GLPK.
136.6 +
136.7 + The original code was modified according to GLPK requirements by
136.8 + Andrew Makhorin <mao@gnu.org>.
136.9 +************************************************************************
136.10 +AMD Version 2.2, Copyright (C) 2007 by Timothy A. Davis,
136.11 +Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved.
136.12 +
136.13 +Description:
136.14 +
136.15 + AMD is a set of routines for pre-ordering sparse matrices prior to
136.16 + Cholesky or LU factorization, using the approximate minimum degree
136.17 + ordering algorithm. Written in ANSI/ISO C with a MATLAB interface,
136.18 + and in Fortran 77.
136.19 +
136.20 +Authors:
136.21 +
136.22 + Timothy A. Davis (davis at cise.ufl.edu), University of Florida.
136.23 + Patrick R. Amestoy, ENSEEIHT, Toulouse, France.
136.24 + Iain S. Duff, Rutherford Appleton Laboratory, UK.
136.25 +
136.26 +AMD License:
136.27 +
136.28 + Your use or distribution of AMD or any modified version of AMD
136.29 + implies that you agree to this License.
136.30 +
136.31 + This library is free software; you can redistribute it and/or
136.32 + modify it under the terms of the GNU Lesser General Public License
136.33 + as published by the Free Software Foundation; either version 2.1 of
136.34 + the License, or (at your option) any later version.
136.35 +
136.36 + This library is distributed in the hope that it will be useful,
136.37 + but WITHOUT ANY WARRANTY; without even the implied warranty of
136.38 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
136.39 + Lesser General Public License for more details.
136.40 +
136.41 + You should have received a copy of the GNU Lesser General Public
136.42 + License along with this library; if not, write to the Free Software
136.43 + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
136.44 + USA.
136.45 +
136.46 + Permission is hereby granted to use or copy this program under the
136.47 + terms of the GNU LGPL, provided that the Copyright, this License,
136.48 + and the Availability of the original version is retained on all
136.49 + copies. User documentation of any code that uses this code or any
136.50 + modified version of this code must cite the Copyright, this License,
136.51 + the Availability note, and "Used by permission." Permission to
136.52 + modify the code and to distribute modified code is granted, provided
136.53 + the Copyright, this License, and the Availability note are retained,
136.54 + and a notice that the code was modified is included.
136.55 +
136.56 + AMD is available under alternate licences; contact T. Davis for
136.57 + details.
136.58 +
136.59 +Availability:
136.60 +
136.61 + http://www.cise.ufl.edu/research/sparse/amd
137.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
137.2 +++ b/src/amd/amd.h Mon Dec 06 13:09:21 2010 +0100
137.3 @@ -0,0 +1,67 @@
137.4 +/* amd.h */
137.5 +
137.6 +/* Written by Andrew Makhorin <mao@gnu.org>. */
137.7 +
137.8 +#ifndef GLPAMD_H
137.9 +#define GLPAMD_H
137.10 +
137.11 +#define AMD_DATE "May 31, 2007"
137.12 +#define AMD_VERSION_CODE(main, sub) ((main) * 1000 + (sub))
137.13 +#define AMD_MAIN_VERSION 2
137.14 +#define AMD_SUB_VERSION 2
137.15 +#define AMD_SUBSUB_VERSION 0
137.16 +#define AMD_VERSION AMD_VERSION_CODE(AMD_MAIN_VERSION, AMD_SUB_VERSION)
137.17 +
137.18 +#define AMD_CONTROL 5
137.19 +#define AMD_INFO 20
137.20 +
137.21 +#define AMD_DENSE 0
137.22 +#define AMD_AGGRESSIVE 1
137.23 +
137.24 +#define AMD_DEFAULT_DENSE 10.0
137.25 +#define AMD_DEFAULT_AGGRESSIVE 1
137.26 +
137.27 +#define AMD_STATUS 0
137.28 +#define AMD_N 1
137.29 +#define AMD_NZ 2
137.30 +#define AMD_SYMMETRY 3
137.31 +#define AMD_NZDIAG 4
137.32 +#define AMD_NZ_A_PLUS_AT 5
137.33 +#define AMD_NDENSE 6
137.34 +#define AMD_MEMORY 7
137.35 +#define AMD_NCMPA 8
137.36 +#define AMD_LNZ 9
137.37 +#define AMD_NDIV 10
137.38 +#define AMD_NMULTSUBS_LDL 11
137.39 +#define AMD_NMULTSUBS_LU 12
137.40 +#define AMD_DMAX 13
137.41 +
137.42 +#define AMD_OK 0
137.43 +#define AMD_OUT_OF_MEMORY (-1)
137.44 +#define AMD_INVALID (-2)
137.45 +#define AMD_OK_BUT_JUMBLED 1
137.46 +
137.47 +#define amd_order _glp_amd_order
137.48 +int amd_order(int n, const int Ap[], const int Ai[], int P[],
137.49 + double Control[], double Info[]);
137.50 +
137.51 +#define amd_2 _glp_amd_2
137.52 +void amd_2(int n, int Pe[], int Iw[], int Len[], int iwlen, int pfree,
137.53 + int Nv[], int Next[], int Last[], int Head[], int Elen[],
137.54 + int Degree[], int W[], double Control[], double Info[]);
137.55 +
137.56 +#define amd_valid _glp_amd_valid
137.57 +int amd_valid(int n_row, int n_col, const int Ap[], const int Ai[]);
137.58 +
137.59 +#define amd_defaults _glp_amd_defaults
137.60 +void amd_defaults(double Control[]);
137.61 +
137.62 +#define amd_control _glp_amd_control
137.63 +void amd_control(double Control[]);
137.64 +
137.65 +#define amd_info _glp_amd_info
137.66 +void amd_info(double Info[]);
137.67 +
137.68 +#endif
137.69 +
137.70 +/* eof */
138.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
138.2 +++ b/src/amd/amd_1.c Mon Dec 06 13:09:21 2010 +0100
138.3 @@ -0,0 +1,181 @@
138.4 +/* ========================================================================= */
138.5 +/* === AMD_1 =============================================================== */
138.6 +/* ========================================================================= */
138.7 +
138.8 +/* ------------------------------------------------------------------------- */
138.9 +/* AMD, Copyright (c) Timothy A. Davis, */
138.10 +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
138.11 +/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
138.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd */
138.13 +/* ------------------------------------------------------------------------- */
138.14 +
138.15 +/* AMD_1: Construct A+A' for a sparse matrix A and perform the AMD ordering.
138.16 + *
138.17 + * The n-by-n sparse matrix A can be unsymmetric. It is stored in MATLAB-style
138.18 + * compressed-column form, with sorted row indices in each column, and no
138.19 + * duplicate entries. Diagonal entries may be present, but they are ignored.
138.20 + * Row indices of column j of A are stored in Ai [Ap [j] ... Ap [j+1]-1].
138.21 + * Ap [0] must be zero, and nz = Ap [n] is the number of entries in A. The
138.22 + * size of the matrix, n, must be greater than or equal to zero.
138.23 + *
138.24 + * This routine must be preceded by a call to AMD_aat, which computes the
138.25 + * number of entries in each row/column in A+A', excluding the diagonal.
138.26 + * Len [j], on input, is the number of entries in row/column j of A+A'. This
138.27 + * routine constructs the matrix A+A' and then calls AMD_2. No error checking
138.28 + * is performed (this was done in AMD_valid).
138.29 + */
138.30 +
138.31 +#include "amd_internal.h"
138.32 +
138.33 +GLOBAL void AMD_1
138.34 +(
138.35 + Int n, /* n > 0 */
138.36 + const Int Ap [ ], /* input of size n+1, not modified */
138.37 + const Int Ai [ ], /* input of size nz = Ap [n], not modified */
138.38 + Int P [ ], /* size n output permutation */
138.39 + Int Pinv [ ], /* size n output inverse permutation */
138.40 + Int Len [ ], /* size n input, undefined on output */
138.41 + Int slen, /* slen >= sum (Len [0..n-1]) + 7n,
138.42 + * ideally slen = 1.2 * sum (Len) + 8n */
138.43 + Int S [ ], /* size slen workspace */
138.44 + double Control [ ], /* input array of size AMD_CONTROL */
138.45 + double Info [ ] /* output array of size AMD_INFO */
138.46 +)
138.47 +{
138.48 + Int i, j, k, p, pfree, iwlen, pj, p1, p2, pj2, *Iw, *Pe, *Nv, *Head,
138.49 + *Elen, *Degree, *s, *W, *Sp, *Tp ;
138.50 +
138.51 + /* --------------------------------------------------------------------- */
138.52 + /* construct the matrix for AMD_2 */
138.53 + /* --------------------------------------------------------------------- */
138.54 +
138.55 + ASSERT (n > 0) ;
138.56 +
138.57 + iwlen = slen - 6*n ;
138.58 + s = S ;
138.59 + Pe = s ; s += n ;
138.60 + Nv = s ; s += n ;
138.61 + Head = s ; s += n ;
138.62 + Elen = s ; s += n ;
138.63 + Degree = s ; s += n ;
138.64 + W = s ; s += n ;
138.65 + Iw = s ; s += iwlen ;
138.66 +
138.67 + ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ;
138.68 +
138.69 + /* construct the pointers for A+A' */
138.70 + Sp = Nv ; /* use Nv and W as workspace for Sp and Tp [ */
138.71 + Tp = W ;
138.72 + pfree = 0 ;
138.73 + for (j = 0 ; j < n ; j++)
138.74 + {
138.75 + Pe [j] = pfree ;
138.76 + Sp [j] = pfree ;
138.77 + pfree += Len [j] ;
138.78 + }
138.79 +
138.80 + /* Note that this restriction on iwlen is slightly more restrictive than
138.81 + * what is strictly required in AMD_2. AMD_2 can operate with no elbow
138.82 + * room at all, but it will be very slow. For better performance, at
138.83 + * least size-n elbow room is enforced. */
138.84 + ASSERT (iwlen >= pfree + n) ;
138.85 +
138.86 +#ifndef NDEBUG
138.87 + for (p = 0 ; p < iwlen ; p++) Iw [p] = EMPTY ;
138.88 +#endif
138.89 +
138.90 + for (k = 0 ; k < n ; k++)
138.91 + {
138.92 + AMD_DEBUG1 (("Construct row/column k= "ID" of A+A'\n", k)) ;
138.93 + p1 = Ap [k] ;
138.94 + p2 = Ap [k+1] ;
138.95 +
138.96 + /* construct A+A' */
138.97 + for (p = p1 ; p < p2 ; )
138.98 + {
138.99 + /* scan the upper triangular part of A */
138.100 + j = Ai [p] ;
138.101 + ASSERT (j >= 0 && j < n) ;
138.102 + if (j < k)
138.103 + {
138.104 + /* entry A (j,k) in the strictly upper triangular part */
138.105 + ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
138.106 + ASSERT (Sp [k] < (k == n-1 ? pfree : Pe [k+1])) ;
138.107 + Iw [Sp [j]++] = k ;
138.108 + Iw [Sp [k]++] = j ;
138.109 + p++ ;
138.110 + }
138.111 + else if (j == k)
138.112 + {
138.113 + /* skip the diagonal */
138.114 + p++ ;
138.115 + break ;
138.116 + }
138.117 + else /* j > k */
138.118 + {
138.119 + /* first entry below the diagonal */
138.120 + break ;
138.121 + }
138.122 + /* scan lower triangular part of A, in column j until reaching
138.123 + * row k. Start where last scan left off. */
138.124 + ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
138.125 + pj2 = Ap [j+1] ;
138.126 + for (pj = Tp [j] ; pj < pj2 ; )
138.127 + {
138.128 + i = Ai [pj] ;
138.129 + ASSERT (i >= 0 && i < n) ;
138.130 + if (i < k)
138.131 + {
138.132 + /* A (i,j) is only in the lower part, not in upper */
138.133 + ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
138.134 + ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
138.135 + Iw [Sp [i]++] = j ;
138.136 + Iw [Sp [j]++] = i ;
138.137 + pj++ ;
138.138 + }
138.139 + else if (i == k)
138.140 + {
138.141 + /* entry A (k,j) in lower part and A (j,k) in upper */
138.142 + pj++ ;
138.143 + break ;
138.144 + }
138.145 + else /* i > k */
138.146 + {
138.147 + /* consider this entry later, when k advances to i */
138.148 + break ;
138.149 + }
138.150 + }
138.151 + Tp [j] = pj ;
138.152 + }
138.153 + Tp [k] = p ;
138.154 + }
138.155 +
138.156 + /* clean up, for remaining mismatched entries */
138.157 + for (j = 0 ; j < n ; j++)
138.158 + {
138.159 + for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
138.160 + {
138.161 + i = Ai [pj] ;
138.162 + ASSERT (i >= 0 && i < n) ;
138.163 + /* A (i,j) is only in the lower part, not in upper */
138.164 + ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
138.165 + ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
138.166 + Iw [Sp [i]++] = j ;
138.167 + Iw [Sp [j]++] = i ;
138.168 + }
138.169 + }
138.170 +
138.171 +#ifndef NDEBUG
138.172 + for (j = 0 ; j < n-1 ; j++) ASSERT (Sp [j] == Pe [j+1]) ;
138.173 + ASSERT (Sp [n-1] == pfree) ;
138.174 +#endif
138.175 +
138.176 + /* Tp and Sp no longer needed ] */
138.177 +
138.178 + /* --------------------------------------------------------------------- */
138.179 + /* order the matrix */
138.180 + /* --------------------------------------------------------------------- */
138.181 +
138.182 + AMD_2 (n, Pe, Iw, Len, iwlen, pfree,
138.183 + Nv, Pinv, P, Head, Elen, Degree, W, Control, Info) ;
138.184 +}
139.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
139.2 +++ b/src/amd/amd_2.c Mon Dec 06 13:09:21 2010 +0100
139.3 @@ -0,0 +1,1842 @@
139.4 +/* ========================================================================= */
139.5 +/* === AMD_2 =============================================================== */
139.6 +/* ========================================================================= */
139.7 +
139.8 +/* ------------------------------------------------------------------------- */
139.9 +/* AMD, Copyright (c) Timothy A. Davis, */
139.10 +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
139.11 +/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
139.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd */
139.13 +/* ------------------------------------------------------------------------- */
139.14 +
139.15 +/* AMD_2: performs the AMD ordering on a symmetric sparse matrix A, followed
139.16 + * by a postordering (via depth-first search) of the assembly tree using the
139.17 + * AMD_postorder routine.
139.18 + */
139.19 +
139.20 +#include "amd_internal.h"
139.21 +
139.22 +/* ========================================================================= */
139.23 +/* === clear_flag ========================================================== */
139.24 +/* ========================================================================= */
139.25 +
139.26 +static Int clear_flag (Int wflg, Int wbig, Int W [ ], Int n)
139.27 +{
139.28 + Int x ;
139.29 + if (wflg < 2 || wflg >= wbig)
139.30 + {
139.31 + for (x = 0 ; x < n ; x++)
139.32 + {
139.33 + if (W [x] != 0) W [x] = 1 ;
139.34 + }
139.35 + wflg = 2 ;
139.36 + }
139.37 + /* at this point, W [0..n-1] < wflg holds */
139.38 + return (wflg) ;
139.39 +}
139.40 +
139.41 +
139.42 +/* ========================================================================= */
139.43 +/* === AMD_2 =============================================================== */
139.44 +/* ========================================================================= */
139.45 +
139.46 +GLOBAL void AMD_2
139.47 +(
139.48 + Int n, /* A is n-by-n, where n > 0 */
139.49 + Int Pe [ ], /* Pe [0..n-1]: index in Iw of row i on input */
139.50 + Int Iw [ ], /* workspace of size iwlen. Iw [0..pfree-1]
139.51 + * holds the matrix on input */
139.52 + Int Len [ ], /* Len [0..n-1]: length for row/column i on input */
139.53 + Int iwlen, /* length of Iw. iwlen >= pfree + n */
139.54 + Int pfree, /* Iw [pfree ... iwlen-1] is empty on input */
139.55 +
139.56 + /* 7 size-n workspaces, not defined on input: */
139.57 + Int Nv [ ], /* the size of each supernode on output */
139.58 + Int Next [ ], /* the output inverse permutation */
139.59 + Int Last [ ], /* the output permutation */
139.60 + Int Head [ ],
139.61 + Int Elen [ ], /* the size columns of L for each supernode */
139.62 + Int Degree [ ],
139.63 + Int W [ ],
139.64 +
139.65 + /* control parameters and output statistics */
139.66 + double Control [ ], /* array of size AMD_CONTROL */
139.67 + double Info [ ] /* array of size AMD_INFO */
139.68 +)
139.69 +{
139.70 +
139.71 +/*
139.72 + * Given a representation of the nonzero pattern of a symmetric matrix, A,
139.73 + * (excluding the diagonal) perform an approximate minimum (UMFPACK/MA38-style)
139.74 + * degree ordering to compute a pivot order such that the introduction of
139.75 + * nonzeros (fill-in) in the Cholesky factors A = LL' is kept low. At each
139.76 + * step, the pivot selected is the one with the minimum UMFAPACK/MA38-style
139.77 + * upper-bound on the external degree. This routine can optionally perform
139.78 + * aggresive absorption (as done by MC47B in the Harwell Subroutine
139.79 + * Library).
139.80 + *
139.81 + * The approximate degree algorithm implemented here is the symmetric analog of
139.82 + * the degree update algorithm in MA38 and UMFPACK (the Unsymmetric-pattern
139.83 + * MultiFrontal PACKage, both by Davis and Duff). The routine is based on the
139.84 + * MA27 minimum degree ordering algorithm by Iain Duff and John Reid.
139.85 + *
139.86 + * This routine is a translation of the original AMDBAR and MC47B routines,
139.87 + * in Fortran, with the following modifications:
139.88 + *
139.89 + * (1) dense rows/columns are removed prior to ordering the matrix, and placed
139.90 + * last in the output order. The presence of a dense row/column can
139.91 + * increase the ordering time by up to O(n^2), unless they are removed
139.92 + * prior to ordering.
139.93 + *
139.94 + * (2) the minimum degree ordering is followed by a postordering (depth-first
139.95 + * search) of the assembly tree. Note that mass elimination (discussed
139.96 + * below) combined with the approximate degree update can lead to the mass
139.97 + * elimination of nodes with lower exact degree than the current pivot
139.98 + * element. No additional fill-in is caused in the representation of the
139.99 + * Schur complement. The mass-eliminated nodes merge with the current
139.100 + * pivot element. They are ordered prior to the current pivot element.
139.101 + * Because they can have lower exact degree than the current element, the
139.102 + * merger of two or more of these nodes in the current pivot element can
139.103 + * lead to a single element that is not a "fundamental supernode". The
139.104 + * diagonal block can have zeros in it. Thus, the assembly tree used here
139.105 + * is not guaranteed to be the precise supernodal elemination tree (with
139.106 + * "funadmental" supernodes), and the postordering performed by this
139.107 + * routine is not guaranteed to be a precise postordering of the
139.108 + * elimination tree.
139.109 + *
139.110 + * (3) input parameters are added, to control aggressive absorption and the
139.111 + * detection of "dense" rows/columns of A.
139.112 + *
139.113 + * (4) additional statistical information is returned, such as the number of
139.114 + * nonzeros in L, and the flop counts for subsequent LDL' and LU
139.115 + * factorizations. These are slight upper bounds, because of the mass
139.116 + * elimination issue discussed above.
139.117 + *
139.118 + * (5) additional routines are added to interface this routine to MATLAB
139.119 + * to provide a simple C-callable user-interface, to check inputs for
139.120 + * errors, compute the symmetry of the pattern of A and the number of
139.121 + * nonzeros in each row/column of A+A', to compute the pattern of A+A',
139.122 + * to perform the assembly tree postordering, and to provide debugging
139.123 + * ouput. Many of these functions are also provided by the Fortran
139.124 + * Harwell Subroutine Library routine MC47A.
139.125 + *
139.126 + * (6) both int and UF_long versions are provided. In the descriptions below
139.127 + * and integer is and int or UF_long depending on which version is
139.128 + * being used.
139.129 +
139.130 + **********************************************************************
139.131 + ***** CAUTION: ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT. ******
139.132 + **********************************************************************
139.133 + ** If you want error checking, a more versatile input format, and a **
139.134 + ** simpler user interface, use amd_order or amd_l_order instead. **
139.135 + ** This routine is not meant to be user-callable. **
139.136 + **********************************************************************
139.137 +
139.138 + * ----------------------------------------------------------------------------
139.139 + * References:
139.140 + * ----------------------------------------------------------------------------
139.141 + *
139.142 + * [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern multifrontal
139.143 + * method for sparse LU factorization", SIAM J. Matrix Analysis and
139.144 + * Applications, vol. 18, no. 1, pp. 140-158. Discusses UMFPACK / MA38,
139.145 + * which first introduced the approximate minimum degree used by this
139.146 + * routine.
139.147 + *
139.148 + * [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An approximate
139.149 + * minimum degree ordering algorithm," SIAM J. Matrix Analysis and
139.150 + * Applications, vol. 17, no. 4, pp. 886-905, 1996. Discusses AMDBAR and
139.151 + * MC47B, which are the Fortran versions of this routine.
139.152 + *
139.153 + * [3] Alan George and Joseph Liu, "The evolution of the minimum degree
139.154 + * ordering algorithm," SIAM Review, vol. 31, no. 1, pp. 1-19, 1989.
139.155 + * We list below the features mentioned in that paper that this code
139.156 + * includes:
139.157 + *
139.158 + * mass elimination:
139.159 + * Yes. MA27 relied on supervariable detection for mass elimination.
139.160 + *
139.161 + * indistinguishable nodes:
139.162 + * Yes (we call these "supervariables"). This was also in the MA27
139.163 + * code - although we modified the method of detecting them (the
139.164 + * previous hash was the true degree, which we no longer keep track
139.165 + * of). A supervariable is a set of rows with identical nonzero
139.166 + * pattern. All variables in a supervariable are eliminated together.
139.167 + * Each supervariable has as its numerical name that of one of its
139.168 + * variables (its principal variable).
139.169 + *
139.170 + * quotient graph representation:
139.171 + * Yes. We use the term "element" for the cliques formed during
139.172 + * elimination. This was also in the MA27 code. The algorithm can
139.173 + * operate in place, but it will work more efficiently if given some
139.174 + * "elbow room."
139.175 + *
139.176 + * element absorption:
139.177 + * Yes. This was also in the MA27 code.
139.178 + *
139.179 + * external degree:
139.180 + * Yes. The MA27 code was based on the true degree.
139.181 + *
139.182 + * incomplete degree update and multiple elimination:
139.183 + * No. This was not in MA27, either. Our method of degree update
139.184 + * within MC47B is element-based, not variable-based. It is thus
139.185 + * not well-suited for use with incomplete degree update or multiple
139.186 + * elimination.
139.187 + *
139.188 + * Authors, and Copyright (C) 2004 by:
139.189 + * Timothy A. Davis, Patrick Amestoy, Iain S. Duff, John K. Reid.
139.190 + *
139.191 + * Acknowledgements: This work (and the UMFPACK package) was supported by the
139.192 + * National Science Foundation (ASC-9111263, DMS-9223088, and CCR-0203270).
139.193 + * The UMFPACK/MA38 approximate degree update algorithm, the unsymmetric analog
139.194 + * which forms the basis of AMD, was developed while Tim Davis was supported by
139.195 + * CERFACS (Toulouse, France) in a post-doctoral position. This C version, and
139.196 + * the etree postorder, were written while Tim Davis was on sabbatical at
139.197 + * Stanford University and Lawrence Berkeley National Laboratory.
139.198 +
139.199 + * ----------------------------------------------------------------------------
139.200 + * INPUT ARGUMENTS (unaltered):
139.201 + * ----------------------------------------------------------------------------
139.202 +
139.203 + * n: The matrix order. Restriction: n >= 1.
139.204 + *
139.205 + * iwlen: The size of the Iw array. On input, the matrix is stored in
139.206 + * Iw [0..pfree-1]. However, Iw [0..iwlen-1] should be slightly larger
139.207 + * than what is required to hold the matrix, at least iwlen >= pfree + n.
139.208 + * Otherwise, excessive compressions will take place. The recommended
139.209 + * value of iwlen is 1.2 * pfree + n, which is the value used in the
139.210 + * user-callable interface to this routine (amd_order.c). The algorithm
139.211 + * will not run at all if iwlen < pfree. Restriction: iwlen >= pfree + n.
139.212 + * Note that this is slightly more restrictive than the actual minimum
139.213 + * (iwlen >= pfree), but AMD_2 will be very slow with no elbow room.
139.214 + * Thus, this routine enforces a bare minimum elbow room of size n.
139.215 + *
139.216 + * pfree: On input the tail end of the array, Iw [pfree..iwlen-1], is empty,
139.217 + * and the matrix is stored in Iw [0..pfree-1]. During execution,
139.218 + * additional data is placed in Iw, and pfree is modified so that
139.219 + * Iw [pfree..iwlen-1] is always the unused part of Iw.
139.220 + *
139.221 + * Control: A double array of size AMD_CONTROL containing input parameters
139.222 + * that affect how the ordering is computed. If NULL, then default
139.223 + * settings are used.
139.224 + *
139.225 + * Control [AMD_DENSE] is used to determine whether or not a given input
139.226 + * row is "dense". A row is "dense" if the number of entries in the row
139.227 + * exceeds Control [AMD_DENSE] times sqrt (n), except that rows with 16 or
139.228 + * fewer entries are never considered "dense". To turn off the detection
139.229 + * of dense rows, set Control [AMD_DENSE] to a negative number, or to a
139.230 + * number larger than sqrt (n). The default value of Control [AMD_DENSE]
139.231 + * is AMD_DEFAULT_DENSE, which is defined in amd.h as 10.
139.232 + *
139.233 + * Control [AMD_AGGRESSIVE] is used to determine whether or not aggressive
139.234 + * absorption is to be performed. If nonzero, then aggressive absorption
139.235 + * is performed (this is the default).
139.236 +
139.237 + * ----------------------------------------------------------------------------
139.238 + * INPUT/OUPUT ARGUMENTS:
139.239 + * ----------------------------------------------------------------------------
139.240 + *
139.241 + * Pe: An integer array of size n. On input, Pe [i] is the index in Iw of
139.242 + * the start of row i. Pe [i] is ignored if row i has no off-diagonal
139.243 + * entries. Thus Pe [i] must be in the range 0 to pfree-1 for non-empty
139.244 + * rows.
139.245 + *
139.246 + * During execution, it is used for both supervariables and elements:
139.247 + *
139.248 + * Principal supervariable i: index into Iw of the description of
139.249 + * supervariable i. A supervariable represents one or more rows of
139.250 + * the matrix with identical nonzero pattern. In this case,
139.251 + * Pe [i] >= 0.
139.252 + *
139.253 + * Non-principal supervariable i: if i has been absorbed into another
139.254 + * supervariable j, then Pe [i] = FLIP (j), where FLIP (j) is defined
139.255 + * as (-(j)-2). Row j has the same pattern as row i. Note that j
139.256 + * might later be absorbed into another supervariable j2, in which
139.257 + * case Pe [i] is still FLIP (j), and Pe [j] = FLIP (j2) which is
139.258 + * < EMPTY, where EMPTY is defined as (-1) in amd_internal.h.
139.259 + *
139.260 + * Unabsorbed element e: the index into Iw of the description of element
139.261 + * e, if e has not yet been absorbed by a subsequent element. Element
139.262 + * e is created when the supervariable of the same name is selected as
139.263 + * the pivot. In this case, Pe [i] >= 0.
139.264 + *
139.265 + * Absorbed element e: if element e is absorbed into element e2, then
139.266 + * Pe [e] = FLIP (e2). This occurs when the pattern of e (which we
139.267 + * refer to as Le) is found to be a subset of the pattern of e2 (that
139.268 + * is, Le2). In this case, Pe [i] < EMPTY. If element e is "null"
139.269 + * (it has no nonzeros outside its pivot block), then Pe [e] = EMPTY,
139.270 + * and e is the root of an assembly subtree (or the whole tree if
139.271 + * there is just one such root).
139.272 + *
139.273 + * Dense variable i: if i is "dense", then Pe [i] = EMPTY.
139.274 + *
139.275 + * On output, Pe holds the assembly tree/forest, which implicitly
139.276 + * represents a pivot order with identical fill-in as the actual order
139.277 + * (via a depth-first search of the tree), as follows. If Nv [i] > 0,
139.278 + * then i represents a node in the assembly tree, and the parent of i is
139.279 + * Pe [i], or EMPTY if i is a root. If Nv [i] = 0, then (i, Pe [i])
139.280 + * represents an edge in a subtree, the root of which is a node in the
139.281 + * assembly tree. Note that i refers to a row/column in the original
139.282 + * matrix, not the permuted matrix.
139.283 + *
139.284 + * Info: A double array of size AMD_INFO. If present, (that is, not NULL),
139.285 + * then statistics about the ordering are returned in the Info array.
139.286 + * See amd.h for a description.
139.287 +
139.288 + * ----------------------------------------------------------------------------
139.289 + * INPUT/MODIFIED (undefined on output):
139.290 + * ----------------------------------------------------------------------------
139.291 + *
139.292 + * Len: An integer array of size n. On input, Len [i] holds the number of
139.293 + * entries in row i of the matrix, excluding the diagonal. The contents
139.294 + * of Len are undefined on output.
139.295 + *
139.296 + * Iw: An integer array of size iwlen. On input, Iw [0..pfree-1] holds the
139.297 + * description of each row i in the matrix. The matrix must be symmetric,
139.298 + * and both upper and lower triangular parts must be present. The
139.299 + * diagonal must not be present. Row i is held as follows:
139.300 + *
139.301 + * Len [i]: the length of the row i data structure in the Iw array.
139.302 + * Iw [Pe [i] ... Pe [i] + Len [i] - 1]:
139.303 + * the list of column indices for nonzeros in row i (simple
139.304 + * supervariables), excluding the diagonal. All supervariables
139.305 + * start with one row/column each (supervariable i is just row i).
139.306 + * If Len [i] is zero on input, then Pe [i] is ignored on input.
139.307 + *
139.308 + * Note that the rows need not be in any particular order, and there
139.309 + * may be empty space between the rows.
139.310 + *
139.311 + * During execution, the supervariable i experiences fill-in. This is
139.312 + * represented by placing in i a list of the elements that cause fill-in
139.313 + * in supervariable i:
139.314 + *
139.315 + * Len [i]: the length of supervariable i in the Iw array.
139.316 + * Iw [Pe [i] ... Pe [i] + Elen [i] - 1]:
139.317 + * the list of elements that contain i. This list is kept short
139.318 + * by removing absorbed elements.
139.319 + * Iw [Pe [i] + Elen [i] ... Pe [i] + Len [i] - 1]:
139.320 + * the list of supervariables in i. This list is kept short by
139.321 + * removing nonprincipal variables, and any entry j that is also
139.322 + * contained in at least one of the elements (j in Le) in the list
139.323 + * for i (e in row i).
139.324 + *
139.325 + * When supervariable i is selected as pivot, we create an element e of
139.326 + * the same name (e=i):
139.327 + *
139.328 + * Len [e]: the length of element e in the Iw array.
139.329 + * Iw [Pe [e] ... Pe [e] + Len [e] - 1]:
139.330 + * the list of supervariables in element e.
139.331 + *
139.332 + * An element represents the fill-in that occurs when supervariable i is
139.333 + * selected as pivot (which represents the selection of row i and all
139.334 + * non-principal variables whose principal variable is i). We use the
139.335 + * term Le to denote the set of all supervariables in element e. Absorbed
139.336 + * supervariables and elements are pruned from these lists when
139.337 + * computationally convenient.
139.338 + *
139.339 + * CAUTION: THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
139.340 + * The contents of Iw are undefined on output.
139.341 +
139.342 + * ----------------------------------------------------------------------------
139.343 + * OUTPUT (need not be set on input):
139.344 + * ----------------------------------------------------------------------------
139.345 + *
139.346 + * Nv: An integer array of size n. During execution, ABS (Nv [i]) is equal to
139.347 + * the number of rows that are represented by the principal supervariable
139.348 + * i. If i is a nonprincipal or dense variable, then Nv [i] = 0.
139.349 + * Initially, Nv [i] = 1 for all i. Nv [i] < 0 signifies that i is a
139.350 + * principal variable in the pattern Lme of the current pivot element me.
139.351 + * After element me is constructed, Nv [i] is set back to a positive
139.352 + * value.
139.353 + *
139.354 + * On output, Nv [i] holds the number of pivots represented by super
139.355 + * row/column i of the original matrix, or Nv [i] = 0 for non-principal
139.356 + * rows/columns. Note that i refers to a row/column in the original
139.357 + * matrix, not the permuted matrix.
139.358 + *
139.359 + * Elen: An integer array of size n. See the description of Iw above. At the
139.360 + * start of execution, Elen [i] is set to zero for all rows i. During
139.361 + * execution, Elen [i] is the number of elements in the list for
139.362 + * supervariable i. When e becomes an element, Elen [e] = FLIP (esize) is
139.363 + * set, where esize is the size of the element (the number of pivots, plus
139.364 + * the number of nonpivotal entries). Thus Elen [e] < EMPTY.
139.365 + * Elen (i) = EMPTY set when variable i becomes nonprincipal.
139.366 + *
139.367 + * For variables, Elen (i) >= EMPTY holds until just before the
139.368 + * postordering and permutation vectors are computed. For elements,
139.369 + * Elen [e] < EMPTY holds.
139.370 + *
139.371 + * On output, Elen [i] is the degree of the row/column in the Cholesky
139.372 + * factorization of the permuted matrix, corresponding to the original row
139.373 + * i, if i is a super row/column. It is equal to EMPTY if i is
139.374 + * non-principal. Note that i refers to a row/column in the original
139.375 + * matrix, not the permuted matrix.
139.376 + *
139.377 + * Note that the contents of Elen on output differ from the Fortran
139.378 + * version (Elen holds the inverse permutation in the Fortran version,
139.379 + * which is instead returned in the Next array in this C version,
139.380 + * described below).
139.381 + *
139.382 + * Last: In a degree list, Last [i] is the supervariable preceding i, or EMPTY
139.383 + * if i is the head of the list. In a hash bucket, Last [i] is the hash
139.384 + * key for i.
139.385 + *
139.386 + * Last [Head [hash]] is also used as the head of a hash bucket if
139.387 + * Head [hash] contains a degree list (see the description of Head,
139.388 + * below).
139.389 + *
139.390 + * On output, Last [0..n-1] holds the permutation. That is, if
139.391 + * i = Last [k], then row i is the kth pivot row (where k ranges from 0 to
139.392 + * n-1). Row Last [k] of A is the kth row in the permuted matrix, PAP'.
139.393 + *
139.394 + * Next: Next [i] is the supervariable following i in a link list, or EMPTY if
139.395 + * i is the last in the list. Used for two kinds of lists: degree lists
139.396 + * and hash buckets (a supervariable can be in only one kind of list at a
139.397 + * time).
139.398 + *
139.399 + * On output Next [0..n-1] holds the inverse permutation. That is, if
139.400 + * k = Next [i], then row i is the kth pivot row. Row i of A appears as
139.401 + * the (Next[i])-th row in the permuted matrix, PAP'.
139.402 + *
139.403 + * Note that the contents of Next on output differ from the Fortran
139.404 + * version (Next is undefined on output in the Fortran version).
139.405 +
139.406 + * ----------------------------------------------------------------------------
139.407 + * LOCAL WORKSPACE (not input or output - used only during execution):
139.408 + * ----------------------------------------------------------------------------
139.409 + *
139.410 + * Degree: An integer array of size n. If i is a supervariable, then
139.411 + * Degree [i] holds the current approximation of the external degree of
139.412 + * row i (an upper bound). The external degree is the number of nonzeros
139.413 + * in row i, minus ABS (Nv [i]), the diagonal part. The bound is equal to
139.414 + * the exact external degree if Elen [i] is less than or equal to two.
139.415 + *
139.416 + * We also use the term "external degree" for elements e to refer to
139.417 + * |Le \ Lme|. If e is an element, then Degree [e] is |Le|, which is the
139.418 + * degree of the off-diagonal part of the element e (not including the
139.419 + * diagonal part).
139.420 + *
139.421 + * Head: An integer array of size n. Head is used for degree lists.
139.422 + * Head [deg] is the first supervariable in a degree list. All
139.423 + * supervariables i in a degree list Head [deg] have the same approximate
139.424 + * degree, namely, deg = Degree [i]. If the list Head [deg] is empty then
139.425 + * Head [deg] = EMPTY.
139.426 + *
139.427 + * During supervariable detection Head [hash] also serves as a pointer to
139.428 + * a hash bucket. If Head [hash] >= 0, there is a degree list of degree
139.429 + * hash. The hash bucket head pointer is Last [Head [hash]]. If
139.430 + * Head [hash] = EMPTY, then the degree list and hash bucket are both
139.431 + * empty. If Head [hash] < EMPTY, then the degree list is empty, and
139.432 + * FLIP (Head [hash]) is the head of the hash bucket. After supervariable
139.433 + * detection is complete, all hash buckets are empty, and the
139.434 + * (Last [Head [hash]] = EMPTY) condition is restored for the non-empty
139.435 + * degree lists.
139.436 + *
139.437 + * W: An integer array of size n. The flag array W determines the status of
139.438 + * elements and variables, and the external degree of elements.
139.439 + *
139.440 + * for elements:
139.441 + * if W [e] = 0, then the element e is absorbed.
139.442 + * if W [e] >= wflg, then W [e] - wflg is the size of the set
139.443 + * |Le \ Lme|, in terms of nonzeros (the sum of ABS (Nv [i]) for
139.444 + * each principal variable i that is both in the pattern of
139.445 + * element e and NOT in the pattern of the current pivot element,
139.446 + * me).
139.447 + * if wflg > W [e] > 0, then e is not absorbed and has not yet been
139.448 + * seen in the scan of the element lists in the computation of
139.449 + * |Le\Lme| in Scan 1 below.
139.450 + *
139.451 + * for variables:
139.452 + * during supervariable detection, if W [j] != wflg then j is
139.453 + * not in the pattern of variable i.
139.454 + *
139.455 + * The W array is initialized by setting W [i] = 1 for all i, and by
139.456 + * setting wflg = 2. It is reinitialized if wflg becomes too large (to
139.457 + * ensure that wflg+n does not cause integer overflow).
139.458 +
139.459 + * ----------------------------------------------------------------------------
139.460 + * LOCAL INTEGERS:
139.461 + * ----------------------------------------------------------------------------
139.462 + */
139.463 +
139.464 + Int deg, degme, dext, lemax, e, elenme, eln, i, ilast, inext, j,
139.465 + jlast, jnext, k, knt1, knt2, knt3, lenj, ln, me, mindeg, nel, nleft,
139.466 + nvi, nvj, nvpiv, slenme, wbig, we, wflg, wnvi, ok, ndense, ncmpa,
139.467 + dense, aggressive ;
139.468 +
139.469 + unsigned Int hash ; /* unsigned, so that hash % n is well defined.*/
139.470 +
139.471 +/*
139.472 + * deg: the degree of a variable or element
139.473 + * degme: size, |Lme|, of the current element, me (= Degree [me])
139.474 + * dext: external degree, |Le \ Lme|, of some element e
139.475 + * lemax: largest |Le| seen so far (called dmax in Fortran version)
139.476 + * e: an element
139.477 + * elenme: the length, Elen [me], of element list of pivotal variable
139.478 + * eln: the length, Elen [...], of an element list
139.479 + * hash: the computed value of the hash function
139.480 + * i: a supervariable
139.481 + * ilast: the entry in a link list preceding i
139.482 + * inext: the entry in a link list following i
139.483 + * j: a supervariable
139.484 + * jlast: the entry in a link list preceding j
139.485 + * jnext: the entry in a link list, or path, following j
139.486 + * k: the pivot order of an element or variable
139.487 + * knt1: loop counter used during element construction
139.488 + * knt2: loop counter used during element construction
139.489 + * knt3: loop counter used during compression
139.490 + * lenj: Len [j]
139.491 + * ln: length of a supervariable list
139.492 + * me: current supervariable being eliminated, and the current
139.493 + * element created by eliminating that supervariable
139.494 + * mindeg: current minimum degree
139.495 + * nel: number of pivots selected so far
139.496 + * nleft: n - nel, the number of nonpivotal rows/columns remaining
139.497 + * nvi: the number of variables in a supervariable i (= Nv [i])
139.498 + * nvj: the number of variables in a supervariable j (= Nv [j])
139.499 + * nvpiv: number of pivots in current element
139.500 + * slenme: number of variables in variable list of pivotal variable
139.501 + * wbig: = INT_MAX - n for the int version, UF_long_max - n for the
139.502 + * UF_long version. wflg is not allowed to be >= wbig.
139.503 + * we: W [e]
139.504 + * wflg: used for flagging the W array. See description of Iw.
139.505 + * wnvi: wflg - Nv [i]
139.506 + * x: either a supervariable or an element
139.507 + *
139.508 + * ok: true if supervariable j can be absorbed into i
139.509 + * ndense: number of "dense" rows/columns
139.510 + * dense: rows/columns with initial degree > dense are considered "dense"
139.511 + * aggressive: true if aggressive absorption is being performed
139.512 + * ncmpa: number of garbage collections
139.513 +
139.514 + * ----------------------------------------------------------------------------
139.515 + * LOCAL DOUBLES, used for statistical output only (except for alpha):
139.516 + * ----------------------------------------------------------------------------
139.517 + */
139.518 +
139.519 + double f, r, ndiv, s, nms_lu, nms_ldl, dmax, alpha, lnz, lnzme ;
139.520 +
139.521 +/*
139.522 + * f: nvpiv
139.523 + * r: degme + nvpiv
139.524 + * ndiv: number of divisions for LU or LDL' factorizations
139.525 + * s: number of multiply-subtract pairs for LU factorization, for the
139.526 + * current element me
139.527 + * nms_lu number of multiply-subtract pairs for LU factorization
139.528 + * nms_ldl number of multiply-subtract pairs for LDL' factorization
139.529 + * dmax: the largest number of entries in any column of L, including the
139.530 + * diagonal
139.531 + * alpha: "dense" degree ratio
139.532 + * lnz: the number of nonzeros in L (excluding the diagonal)
139.533 + * lnzme: the number of nonzeros in L (excl. the diagonal) for the
139.534 + * current element me
139.535 +
139.536 + * ----------------------------------------------------------------------------
139.537 + * LOCAL "POINTERS" (indices into the Iw array)
139.538 + * ----------------------------------------------------------------------------
139.539 +*/
139.540 +
139.541 + Int p, p1, p2, p3, p4, pdst, pend, pj, pme, pme1, pme2, pn, psrc ;
139.542 +
139.543 +/*
139.544 + * Any parameter (Pe [...] or pfree) or local variable starting with "p" (for
139.545 + * Pointer) is an index into Iw, and all indices into Iw use variables starting
139.546 + * with "p." The only exception to this rule is the iwlen input argument.
139.547 + *
139.548 + * p: pointer into lots of things
139.549 + * p1: Pe [i] for some variable i (start of element list)
139.550 + * p2: Pe [i] + Elen [i] - 1 for some variable i
139.551 + * p3: index of first supervariable in clean list
139.552 + * p4:
139.553 + * pdst: destination pointer, for compression
139.554 + * pend: end of memory to compress
139.555 + * pj: pointer into an element or variable
139.556 + * pme: pointer into the current element (pme1...pme2)
139.557 + * pme1: the current element, me, is stored in Iw [pme1...pme2]
139.558 + * pme2: the end of the current element
139.559 + * pn: pointer into a "clean" variable, also used to compress
139.560 + * psrc: source pointer, for compression
139.561 +*/
139.562 +
139.563 +/* ========================================================================= */
139.564 +/* INITIALIZATIONS */
139.565 +/* ========================================================================= */
139.566 +
139.567 + /* Note that this restriction on iwlen is slightly more restrictive than
139.568 + * what is actually required in AMD_2. AMD_2 can operate with no elbow
139.569 + * room at all, but it will be slow. For better performance, at least
139.570 + * size-n elbow room is enforced. */
139.571 + ASSERT (iwlen >= pfree + n) ;
139.572 + ASSERT (n > 0) ;
139.573 +
139.574 + /* initialize output statistics */
139.575 + lnz = 0 ;
139.576 + ndiv = 0 ;
139.577 + nms_lu = 0 ;
139.578 + nms_ldl = 0 ;
139.579 + dmax = 1 ;
139.580 + me = EMPTY ;
139.581 +
139.582 + mindeg = 0 ;
139.583 + ncmpa = 0 ;
139.584 + nel = 0 ;
139.585 + lemax = 0 ;
139.586 +
139.587 + /* get control parameters */
139.588 + if (Control != (double *) NULL)
139.589 + {
139.590 + alpha = Control [AMD_DENSE] ;
139.591 + aggressive = (Control [AMD_AGGRESSIVE] != 0) ;
139.592 + }
139.593 + else
139.594 + {
139.595 + alpha = AMD_DEFAULT_DENSE ;
139.596 + aggressive = AMD_DEFAULT_AGGRESSIVE ;
139.597 + }
139.598 + /* Note: if alpha is NaN, this is undefined: */
139.599 + if (alpha < 0)
139.600 + {
139.601 + /* only remove completely dense rows/columns */
139.602 + dense = n-2 ;
139.603 + }
139.604 + else
139.605 + {
139.606 + dense = alpha * sqrt ((double) n) ;
139.607 + }
139.608 + dense = MAX (16, dense) ;
139.609 + dense = MIN (n, dense) ;
139.610 + AMD_DEBUG1 (("\n\nAMD (debug), alpha %g, aggr. "ID"\n",
139.611 + alpha, aggressive)) ;
139.612 +
139.613 + for (i = 0 ; i < n ; i++)
139.614 + {
139.615 + Last [i] = EMPTY ;
139.616 + Head [i] = EMPTY ;
139.617 + Next [i] = EMPTY ;
139.618 + /* if separate Hhead array is used for hash buckets: *
139.619 + Hhead [i] = EMPTY ;
139.620 + */
139.621 + Nv [i] = 1 ;
139.622 + W [i] = 1 ;
139.623 + Elen [i] = 0 ;
139.624 + Degree [i] = Len [i] ;
139.625 + }
139.626 +
139.627 +#ifndef NDEBUG
139.628 + AMD_DEBUG1 (("\n======Nel "ID" initial\n", nel)) ;
139.629 + AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next, Last,
139.630 + Head, Elen, Degree, W, -1) ;
139.631 +#endif
139.632 +
139.633 + /* initialize wflg */
139.634 + wbig = Int_MAX - n ;
139.635 + wflg = clear_flag (0, wbig, W, n) ;
139.636 +
139.637 + /* --------------------------------------------------------------------- */
139.638 + /* initialize degree lists and eliminate dense and empty rows */
139.639 + /* --------------------------------------------------------------------- */
139.640 +
139.641 + ndense = 0 ;
139.642 +
139.643 + for (i = 0 ; i < n ; i++)
139.644 + {
139.645 + deg = Degree [i] ;
139.646 + ASSERT (deg >= 0 && deg < n) ;
139.647 + if (deg == 0)
139.648 + {
139.649 +
139.650 + /* -------------------------------------------------------------
139.651 + * we have a variable that can be eliminated at once because
139.652 + * there is no off-diagonal non-zero in its row. Note that
139.653 + * Nv [i] = 1 for an empty variable i. It is treated just
139.654 + * the same as an eliminated element i.
139.655 + * ------------------------------------------------------------- */
139.656 +
139.657 + Elen [i] = FLIP (1) ;
139.658 + nel++ ;
139.659 + Pe [i] = EMPTY ;
139.660 + W [i] = 0 ;
139.661 +
139.662 + }
139.663 + else if (deg > dense)
139.664 + {
139.665 +
139.666 + /* -------------------------------------------------------------
139.667 + * Dense variables are not treated as elements, but as unordered,
139.668 + * non-principal variables that have no parent. They do not take
139.669 + * part in the postorder, since Nv [i] = 0. Note that the Fortran
139.670 + * version does not have this option.
139.671 + * ------------------------------------------------------------- */
139.672 +
139.673 + AMD_DEBUG1 (("Dense node "ID" degree "ID"\n", i, deg)) ;
139.674 + ndense++ ;
139.675 + Nv [i] = 0 ; /* do not postorder this node */
139.676 + Elen [i] = EMPTY ;
139.677 + nel++ ;
139.678 + Pe [i] = EMPTY ;
139.679 +
139.680 + }
139.681 + else
139.682 + {
139.683 +
139.684 + /* -------------------------------------------------------------
139.685 + * place i in the degree list corresponding to its degree
139.686 + * ------------------------------------------------------------- */
139.687 +
139.688 + inext = Head [deg] ;
139.689 + ASSERT (inext >= EMPTY && inext < n) ;
139.690 + if (inext != EMPTY) Last [inext] = i ;
139.691 + Next [i] = inext ;
139.692 + Head [deg] = i ;
139.693 +
139.694 + }
139.695 + }
139.696 +
139.697 +/* ========================================================================= */
139.698 +/* WHILE (selecting pivots) DO */
139.699 +/* ========================================================================= */
139.700 +
139.701 + while (nel < n)
139.702 + {
139.703 +
139.704 +#ifndef NDEBUG
139.705 + AMD_DEBUG1 (("\n======Nel "ID"\n", nel)) ;
139.706 + if (AMD_debug >= 2)
139.707 + {
139.708 + AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next,
139.709 + Last, Head, Elen, Degree, W, nel) ;
139.710 + }
139.711 +#endif
139.712 +
139.713 +/* ========================================================================= */
139.714 +/* GET PIVOT OF MINIMUM DEGREE */
139.715 +/* ========================================================================= */
139.716 +
139.717 + /* ----------------------------------------------------------------- */
139.718 + /* find next supervariable for elimination */
139.719 + /* ----------------------------------------------------------------- */
139.720 +
139.721 + ASSERT (mindeg >= 0 && mindeg < n) ;
139.722 + for (deg = mindeg ; deg < n ; deg++)
139.723 + {
139.724 + me = Head [deg] ;
139.725 + if (me != EMPTY) break ;
139.726 + }
139.727 + mindeg = deg ;
139.728 + ASSERT (me >= 0 && me < n) ;
139.729 + AMD_DEBUG1 (("=================me: "ID"\n", me)) ;
139.730 +
139.731 + /* ----------------------------------------------------------------- */
139.732 + /* remove chosen variable from link list */
139.733 + /* ----------------------------------------------------------------- */
139.734 +
139.735 + inext = Next [me] ;
139.736 + ASSERT (inext >= EMPTY && inext < n) ;
139.737 + if (inext != EMPTY) Last [inext] = EMPTY ;
139.738 + Head [deg] = inext ;
139.739 +
139.740 + /* ----------------------------------------------------------------- */
139.741 + /* me represents the elimination of pivots nel to nel+Nv[me]-1. */
139.742 + /* place me itself as the first in this set. */
139.743 + /* ----------------------------------------------------------------- */
139.744 +
139.745 + elenme = Elen [me] ;
139.746 + nvpiv = Nv [me] ;
139.747 + ASSERT (nvpiv > 0) ;
139.748 + nel += nvpiv ;
139.749 +
139.750 +/* ========================================================================= */
139.751 +/* CONSTRUCT NEW ELEMENT */
139.752 +/* ========================================================================= */
139.753 +
139.754 + /* -----------------------------------------------------------------
139.755 + * At this point, me is the pivotal supervariable. It will be
139.756 + * converted into the current element. Scan list of the pivotal
139.757 + * supervariable, me, setting tree pointers and constructing new list
139.758 + * of supervariables for the new element, me. p is a pointer to the
139.759 + * current position in the old list.
139.760 + * ----------------------------------------------------------------- */
139.761 +
139.762 + /* flag the variable "me" as being in Lme by negating Nv [me] */
139.763 + Nv [me] = -nvpiv ;
139.764 + degme = 0 ;
139.765 + ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ;
139.766 +
139.767 + if (elenme == 0)
139.768 + {
139.769 +
139.770 + /* ------------------------------------------------------------- */
139.771 + /* construct the new element in place */
139.772 + /* ------------------------------------------------------------- */
139.773 +
139.774 + pme1 = Pe [me] ;
139.775 + pme2 = pme1 - 1 ;
139.776 +
139.777 + for (p = pme1 ; p <= pme1 + Len [me] - 1 ; p++)
139.778 + {
139.779 + i = Iw [p] ;
139.780 + ASSERT (i >= 0 && i < n && Nv [i] >= 0) ;
139.781 + nvi = Nv [i] ;
139.782 + if (nvi > 0)
139.783 + {
139.784 +
139.785 + /* ----------------------------------------------------- */
139.786 + /* i is a principal variable not yet placed in Lme. */
139.787 + /* store i in new list */
139.788 + /* ----------------------------------------------------- */
139.789 +
139.790 + /* flag i as being in Lme by negating Nv [i] */
139.791 + degme += nvi ;
139.792 + Nv [i] = -nvi ;
139.793 + Iw [++pme2] = i ;
139.794 +
139.795 + /* ----------------------------------------------------- */
139.796 + /* remove variable i from degree list. */
139.797 + /* ----------------------------------------------------- */
139.798 +
139.799 + ilast = Last [i] ;
139.800 + inext = Next [i] ;
139.801 + ASSERT (ilast >= EMPTY && ilast < n) ;
139.802 + ASSERT (inext >= EMPTY && inext < n) ;
139.803 + if (inext != EMPTY) Last [inext] = ilast ;
139.804 + if (ilast != EMPTY)
139.805 + {
139.806 + Next [ilast] = inext ;
139.807 + }
139.808 + else
139.809 + {
139.810 + /* i is at the head of the degree list */
139.811 + ASSERT (Degree [i] >= 0 && Degree [i] < n) ;
139.812 + Head [Degree [i]] = inext ;
139.813 + }
139.814 + }
139.815 + }
139.816 + }
139.817 + else
139.818 + {
139.819 +
139.820 + /* ------------------------------------------------------------- */
139.821 + /* construct the new element in empty space, Iw [pfree ...] */
139.822 + /* ------------------------------------------------------------- */
139.823 +
139.824 + p = Pe [me] ;
139.825 + pme1 = pfree ;
139.826 + slenme = Len [me] - elenme ;
139.827 +
139.828 + for (knt1 = 1 ; knt1 <= elenme + 1 ; knt1++)
139.829 + {
139.830 +
139.831 + if (knt1 > elenme)
139.832 + {
139.833 + /* search the supervariables in me. */
139.834 + e = me ;
139.835 + pj = p ;
139.836 + ln = slenme ;
139.837 + AMD_DEBUG2 (("Search sv: "ID" "ID" "ID"\n", me,pj,ln)) ;
139.838 + }
139.839 + else
139.840 + {
139.841 + /* search the elements in me. */
139.842 + e = Iw [p++] ;
139.843 + ASSERT (e >= 0 && e < n) ;
139.844 + pj = Pe [e] ;
139.845 + ln = Len [e] ;
139.846 + AMD_DEBUG2 (("Search element e "ID" in me "ID"\n", e,me)) ;
139.847 + ASSERT (Elen [e] < EMPTY && W [e] > 0 && pj >= 0) ;
139.848 + }
139.849 + ASSERT (ln >= 0 && (ln == 0 || (pj >= 0 && pj < iwlen))) ;
139.850 +
139.851 + /* ---------------------------------------------------------
139.852 + * search for different supervariables and add them to the
139.853 + * new list, compressing when necessary. this loop is
139.854 + * executed once for each element in the list and once for
139.855 + * all the supervariables in the list.
139.856 + * --------------------------------------------------------- */
139.857 +
139.858 + for (knt2 = 1 ; knt2 <= ln ; knt2++)
139.859 + {
139.860 + i = Iw [pj++] ;
139.861 + ASSERT (i >= 0 && i < n && (i == me || Elen [i] >= EMPTY));
139.862 + nvi = Nv [i] ;
139.863 + AMD_DEBUG2 ((": "ID" "ID" "ID" "ID"\n",
139.864 + i, Elen [i], Nv [i], wflg)) ;
139.865 +
139.866 + if (nvi > 0)
139.867 + {
139.868 +
139.869 + /* ------------------------------------------------- */
139.870 + /* compress Iw, if necessary */
139.871 + /* ------------------------------------------------- */
139.872 +
139.873 + if (pfree >= iwlen)
139.874 + {
139.875 +
139.876 + AMD_DEBUG1 (("GARBAGE COLLECTION\n")) ;
139.877 +
139.878 + /* prepare for compressing Iw by adjusting pointers
139.879 + * and lengths so that the lists being searched in
139.880 + * the inner and outer loops contain only the
139.881 + * remaining entries. */
139.882 +
139.883 + Pe [me] = p ;
139.884 + Len [me] -= knt1 ;
139.885 + /* check if nothing left of supervariable me */
139.886 + if (Len [me] == 0) Pe [me] = EMPTY ;
139.887 + Pe [e] = pj ;
139.888 + Len [e] = ln - knt2 ;
139.889 + /* nothing left of element e */
139.890 + if (Len [e] == 0) Pe [e] = EMPTY ;
139.891 +
139.892 + ncmpa++ ; /* one more garbage collection */
139.893 +
139.894 + /* store first entry of each object in Pe */
139.895 + /* FLIP the first entry in each object */
139.896 + for (j = 0 ; j < n ; j++)
139.897 + {
139.898 + pn = Pe [j] ;
139.899 + if (pn >= 0)
139.900 + {
139.901 + ASSERT (pn >= 0 && pn < iwlen) ;
139.902 + Pe [j] = Iw [pn] ;
139.903 + Iw [pn] = FLIP (j) ;
139.904 + }
139.905 + }
139.906 +
139.907 + /* psrc/pdst point to source/destination */
139.908 + psrc = 0 ;
139.909 + pdst = 0 ;
139.910 + pend = pme1 - 1 ;
139.911 +
139.912 + while (psrc <= pend)
139.913 + {
139.914 + /* search for next FLIP'd entry */
139.915 + j = FLIP (Iw [psrc++]) ;
139.916 + if (j >= 0)
139.917 + {
139.918 + AMD_DEBUG2 (("Got object j: "ID"\n", j)) ;
139.919 + Iw [pdst] = Pe [j] ;
139.920 + Pe [j] = pdst++ ;
139.921 + lenj = Len [j] ;
139.922 + /* copy from source to destination */
139.923 + for (knt3 = 0 ; knt3 <= lenj - 2 ; knt3++)
139.924 + {
139.925 + Iw [pdst++] = Iw [psrc++] ;
139.926 + }
139.927 + }
139.928 + }
139.929 +
139.930 + /* move the new partially-constructed element */
139.931 + p1 = pdst ;
139.932 + for (psrc = pme1 ; psrc <= pfree-1 ; psrc++)
139.933 + {
139.934 + Iw [pdst++] = Iw [psrc] ;
139.935 + }
139.936 + pme1 = p1 ;
139.937 + pfree = pdst ;
139.938 + pj = Pe [e] ;
139.939 + p = Pe [me] ;
139.940 +
139.941 + }
139.942 +
139.943 + /* ------------------------------------------------- */
139.944 + /* i is a principal variable not yet placed in Lme */
139.945 + /* store i in new list */
139.946 + /* ------------------------------------------------- */
139.947 +
139.948 + /* flag i as being in Lme by negating Nv [i] */
139.949 + degme += nvi ;
139.950 + Nv [i] = -nvi ;
139.951 + Iw [pfree++] = i ;
139.952 + AMD_DEBUG2 ((" s: "ID" nv "ID"\n", i, Nv [i]));
139.953 +
139.954 + /* ------------------------------------------------- */
139.955 + /* remove variable i from degree link list */
139.956 + /* ------------------------------------------------- */
139.957 +
139.958 + ilast = Last [i] ;
139.959 + inext = Next [i] ;
139.960 + ASSERT (ilast >= EMPTY && ilast < n) ;
139.961 + ASSERT (inext >= EMPTY && inext < n) ;
139.962 + if (inext != EMPTY) Last [inext] = ilast ;
139.963 + if (ilast != EMPTY)
139.964 + {
139.965 + Next [ilast] = inext ;
139.966 + }
139.967 + else
139.968 + {
139.969 + /* i is at the head of the degree list */
139.970 + ASSERT (Degree [i] >= 0 && Degree [i] < n) ;
139.971 + Head [Degree [i]] = inext ;
139.972 + }
139.973 + }
139.974 + }
139.975 +
139.976 + if (e != me)
139.977 + {
139.978 + /* set tree pointer and flag to indicate element e is
139.979 + * absorbed into new element me (the parent of e is me) */
139.980 + AMD_DEBUG1 ((" Element "ID" => "ID"\n", e, me)) ;
139.981 + Pe [e] = FLIP (me) ;
139.982 + W [e] = 0 ;
139.983 + }
139.984 + }
139.985 +
139.986 + pme2 = pfree - 1 ;
139.987 + }
139.988 +
139.989 + /* ----------------------------------------------------------------- */
139.990 + /* me has now been converted into an element in Iw [pme1..pme2] */
139.991 + /* ----------------------------------------------------------------- */
139.992 +
139.993 + /* degme holds the external degree of new element */
139.994 + Degree [me] = degme ;
139.995 + Pe [me] = pme1 ;
139.996 + Len [me] = pme2 - pme1 + 1 ;
139.997 + ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ;
139.998 +
139.999 + Elen [me] = FLIP (nvpiv + degme) ;
139.1000 + /* FLIP (Elen (me)) is now the degree of pivot (including
139.1001 + * diagonal part). */
139.1002 +
139.1003 +#ifndef NDEBUG
139.1004 + AMD_DEBUG2 (("New element structure: length= "ID"\n", pme2-pme1+1)) ;
139.1005 + for (pme = pme1 ; pme <= pme2 ; pme++) AMD_DEBUG3 ((" "ID"", Iw[pme]));
139.1006 + AMD_DEBUG3 (("\n")) ;
139.1007 +#endif
139.1008 +
139.1009 + /* ----------------------------------------------------------------- */
139.1010 + /* make sure that wflg is not too large. */
139.1011 + /* ----------------------------------------------------------------- */
139.1012 +
139.1013 + /* With the current value of wflg, wflg+n must not cause integer
139.1014 + * overflow */
139.1015 +
139.1016 + wflg = clear_flag (wflg, wbig, W, n) ;
139.1017 +
139.1018 +/* ========================================================================= */
139.1019 +/* COMPUTE (W [e] - wflg) = |Le\Lme| FOR ALL ELEMENTS */
139.1020 +/* ========================================================================= */
139.1021 +
139.1022 + /* -----------------------------------------------------------------
139.1023 + * Scan 1: compute the external degrees of previous elements with
139.1024 + * respect to the current element. That is:
139.1025 + * (W [e] - wflg) = |Le \ Lme|
139.1026 + * for each element e that appears in any supervariable in Lme. The
139.1027 + * notation Le refers to the pattern (list of supervariables) of a
139.1028 + * previous element e, where e is not yet absorbed, stored in
139.1029 + * Iw [Pe [e] + 1 ... Pe [e] + Len [e]]. The notation Lme
139.1030 + * refers to the pattern of the current element (stored in
139.1031 + * Iw [pme1..pme2]). If aggressive absorption is enabled, and
139.1032 + * (W [e] - wflg) becomes zero, then the element e will be absorbed
139.1033 + * in Scan 2.
139.1034 + * ----------------------------------------------------------------- */
139.1035 +
139.1036 + AMD_DEBUG2 (("me: ")) ;
139.1037 + for (pme = pme1 ; pme <= pme2 ; pme++)
139.1038 + {
139.1039 + i = Iw [pme] ;
139.1040 + ASSERT (i >= 0 && i < n) ;
139.1041 + eln = Elen [i] ;
139.1042 + AMD_DEBUG3 ((""ID" Elen "ID": \n", i, eln)) ;
139.1043 + if (eln > 0)
139.1044 + {
139.1045 + /* note that Nv [i] has been negated to denote i in Lme: */
139.1046 + nvi = -Nv [i] ;
139.1047 + ASSERT (nvi > 0 && Pe [i] >= 0 && Pe [i] < iwlen) ;
139.1048 + wnvi = wflg - nvi ;
139.1049 + for (p = Pe [i] ; p <= Pe [i] + eln - 1 ; p++)
139.1050 + {
139.1051 + e = Iw [p] ;
139.1052 + ASSERT (e >= 0 && e < n) ;
139.1053 + we = W [e] ;
139.1054 + AMD_DEBUG4 ((" e "ID" we "ID" ", e, we)) ;
139.1055 + if (we >= wflg)
139.1056 + {
139.1057 + /* unabsorbed element e has been seen in this loop */
139.1058 + AMD_DEBUG4 ((" unabsorbed, first time seen")) ;
139.1059 + we -= nvi ;
139.1060 + }
139.1061 + else if (we != 0)
139.1062 + {
139.1063 + /* e is an unabsorbed element */
139.1064 + /* this is the first we have seen e in all of Scan 1 */
139.1065 + AMD_DEBUG4 ((" unabsorbed")) ;
139.1066 + we = Degree [e] + wnvi ;
139.1067 + }
139.1068 + AMD_DEBUG4 (("\n")) ;
139.1069 + W [e] = we ;
139.1070 + }
139.1071 + }
139.1072 + }
139.1073 + AMD_DEBUG2 (("\n")) ;
139.1074 +
139.1075 +/* ========================================================================= */
139.1076 +/* DEGREE UPDATE AND ELEMENT ABSORPTION */
139.1077 +/* ========================================================================= */
139.1078 +
139.1079 + /* -----------------------------------------------------------------
139.1080 + * Scan 2: for each i in Lme, sum up the degree of Lme (which is
139.1081 + * degme), plus the sum of the external degrees of each Le for the
139.1082 + * elements e appearing within i, plus the supervariables in i.
139.1083 + * Place i in hash list.
139.1084 + * ----------------------------------------------------------------- */
139.1085 +
139.1086 + for (pme = pme1 ; pme <= pme2 ; pme++)
139.1087 + {
139.1088 + i = Iw [pme] ;
139.1089 + ASSERT (i >= 0 && i < n && Nv [i] < 0 && Elen [i] >= 0) ;
139.1090 + AMD_DEBUG2 (("Updating: i "ID" "ID" "ID"\n", i, Elen[i], Len [i]));
139.1091 + p1 = Pe [i] ;
139.1092 + p2 = p1 + Elen [i] - 1 ;
139.1093 + pn = p1 ;
139.1094 + hash = 0 ;
139.1095 + deg = 0 ;
139.1096 + ASSERT (p1 >= 0 && p1 < iwlen && p2 >= -1 && p2 < iwlen) ;
139.1097 +
139.1098 + /* ------------------------------------------------------------- */
139.1099 + /* scan the element list associated with supervariable i */
139.1100 + /* ------------------------------------------------------------- */
139.1101 +
139.1102 + /* UMFPACK/MA38-style approximate degree: */
139.1103 + if (aggressive)
139.1104 + {
139.1105 + for (p = p1 ; p <= p2 ; p++)
139.1106 + {
139.1107 + e = Iw [p] ;
139.1108 + ASSERT (e >= 0 && e < n) ;
139.1109 + we = W [e] ;
139.1110 + if (we != 0)
139.1111 + {
139.1112 + /* e is an unabsorbed element */
139.1113 + /* dext = | Le \ Lme | */
139.1114 + dext = we - wflg ;
139.1115 + if (dext > 0)
139.1116 + {
139.1117 + deg += dext ;
139.1118 + Iw [pn++] = e ;
139.1119 + hash += e ;
139.1120 + AMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ;
139.1121 + }
139.1122 + else
139.1123 + {
139.1124 + /* external degree of e is zero, absorb e into me*/
139.1125 + AMD_DEBUG1 ((" Element "ID" =>"ID" (aggressive)\n",
139.1126 + e, me)) ;
139.1127 + ASSERT (dext == 0) ;
139.1128 + Pe [e] = FLIP (me) ;
139.1129 + W [e] = 0 ;
139.1130 + }
139.1131 + }
139.1132 + }
139.1133 + }
139.1134 + else
139.1135 + {
139.1136 + for (p = p1 ; p <= p2 ; p++)
139.1137 + {
139.1138 + e = Iw [p] ;
139.1139 + ASSERT (e >= 0 && e < n) ;
139.1140 + we = W [e] ;
139.1141 + if (we != 0)
139.1142 + {
139.1143 + /* e is an unabsorbed element */
139.1144 + dext = we - wflg ;
139.1145 + ASSERT (dext >= 0) ;
139.1146 + deg += dext ;
139.1147 + Iw [pn++] = e ;
139.1148 + hash += e ;
139.1149 + AMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ;
139.1150 + }
139.1151 + }
139.1152 + }
139.1153 +
139.1154 + /* count the number of elements in i (including me): */
139.1155 + Elen [i] = pn - p1 + 1 ;
139.1156 +
139.1157 + /* ------------------------------------------------------------- */
139.1158 + /* scan the supervariables in the list associated with i */
139.1159 + /* ------------------------------------------------------------- */
139.1160 +
139.1161 + /* The bulk of the AMD run time is typically spent in this loop,
139.1162 + * particularly if the matrix has many dense rows that are not
139.1163 + * removed prior to ordering. */
139.1164 + p3 = pn ;
139.1165 + p4 = p1 + Len [i] ;
139.1166 + for (p = p2 + 1 ; p < p4 ; p++)
139.1167 + {
139.1168 + j = Iw [p] ;
139.1169 + ASSERT (j >= 0 && j < n) ;
139.1170 + nvj = Nv [j] ;
139.1171 + if (nvj > 0)
139.1172 + {
139.1173 + /* j is unabsorbed, and not in Lme. */
139.1174 + /* add to degree and add to new list */
139.1175 + deg += nvj ;
139.1176 + Iw [pn++] = j ;
139.1177 + hash += j ;
139.1178 + AMD_DEBUG4 ((" s: "ID" hash "ID" Nv[j]= "ID"\n",
139.1179 + j, hash, nvj)) ;
139.1180 + }
139.1181 + }
139.1182 +
139.1183 + /* ------------------------------------------------------------- */
139.1184 + /* update the degree and check for mass elimination */
139.1185 + /* ------------------------------------------------------------- */
139.1186 +
139.1187 + /* with aggressive absorption, deg==0 is identical to the
139.1188 + * Elen [i] == 1 && p3 == pn test, below. */
139.1189 + ASSERT (IMPLIES (aggressive, (deg==0) == (Elen[i]==1 && p3==pn))) ;
139.1190 +
139.1191 + if (Elen [i] == 1 && p3 == pn)
139.1192 + {
139.1193 +
139.1194 + /* --------------------------------------------------------- */
139.1195 + /* mass elimination */
139.1196 + /* --------------------------------------------------------- */
139.1197 +
139.1198 + /* There is nothing left of this node except for an edge to
139.1199 + * the current pivot element. Elen [i] is 1, and there are
139.1200 + * no variables adjacent to node i. Absorb i into the
139.1201 + * current pivot element, me. Note that if there are two or
139.1202 + * more mass eliminations, fillin due to mass elimination is
139.1203 + * possible within the nvpiv-by-nvpiv pivot block. It is this
139.1204 + * step that causes AMD's analysis to be an upper bound.
139.1205 + *
139.1206 + * The reason is that the selected pivot has a lower
139.1207 + * approximate degree than the true degree of the two mass
139.1208 + * eliminated nodes. There is no edge between the two mass
139.1209 + * eliminated nodes. They are merged with the current pivot
139.1210 + * anyway.
139.1211 + *
139.1212 + * No fillin occurs in the Schur complement, in any case,
139.1213 + * and this effect does not decrease the quality of the
139.1214 + * ordering itself, just the quality of the nonzero and
139.1215 + * flop count analysis. It also means that the post-ordering
139.1216 + * is not an exact elimination tree post-ordering. */
139.1217 +
139.1218 + AMD_DEBUG1 ((" MASS i "ID" => parent e "ID"\n", i, me)) ;
139.1219 + Pe [i] = FLIP (me) ;
139.1220 + nvi = -Nv [i] ;
139.1221 + degme -= nvi ;
139.1222 + nvpiv += nvi ;
139.1223 + nel += nvi ;
139.1224 + Nv [i] = 0 ;
139.1225 + Elen [i] = EMPTY ;
139.1226 +
139.1227 + }
139.1228 + else
139.1229 + {
139.1230 +
139.1231 + /* --------------------------------------------------------- */
139.1232 + /* update the upper-bound degree of i */
139.1233 + /* --------------------------------------------------------- */
139.1234 +
139.1235 + /* the following degree does not yet include the size
139.1236 + * of the current element, which is added later: */
139.1237 +
139.1238 + Degree [i] = MIN (Degree [i], deg) ;
139.1239 +
139.1240 + /* --------------------------------------------------------- */
139.1241 + /* add me to the list for i */
139.1242 + /* --------------------------------------------------------- */
139.1243 +
139.1244 + /* move first supervariable to end of list */
139.1245 + Iw [pn] = Iw [p3] ;
139.1246 + /* move first element to end of element part of list */
139.1247 + Iw [p3] = Iw [p1] ;
139.1248 + /* add new element, me, to front of list. */
139.1249 + Iw [p1] = me ;
139.1250 + /* store the new length of the list in Len [i] */
139.1251 + Len [i] = pn - p1 + 1 ;
139.1252 +
139.1253 + /* --------------------------------------------------------- */
139.1254 + /* place in hash bucket. Save hash key of i in Last [i]. */
139.1255 + /* --------------------------------------------------------- */
139.1256 +
139.1257 + /* NOTE: this can fail if hash is negative, because the ANSI C
139.1258 + * standard does not define a % b when a and/or b are negative.
139.1259 + * That's why hash is defined as an unsigned Int, to avoid this
139.1260 + * problem. */
139.1261 + hash = hash % n ;
139.1262 + ASSERT (((Int) hash) >= 0 && ((Int) hash) < n) ;
139.1263 +
139.1264 + /* if the Hhead array is not used: */
139.1265 + j = Head [hash] ;
139.1266 + if (j <= EMPTY)
139.1267 + {
139.1268 + /* degree list is empty, hash head is FLIP (j) */
139.1269 + Next [i] = FLIP (j) ;
139.1270 + Head [hash] = FLIP (i) ;
139.1271 + }
139.1272 + else
139.1273 + {
139.1274 + /* degree list is not empty, use Last [Head [hash]] as
139.1275 + * hash head. */
139.1276 + Next [i] = Last [j] ;
139.1277 + Last [j] = i ;
139.1278 + }
139.1279 +
139.1280 + /* if a separate Hhead array is used: *
139.1281 + Next [i] = Hhead [hash] ;
139.1282 + Hhead [hash] = i ;
139.1283 + */
139.1284 +
139.1285 + Last [i] = hash ;
139.1286 + }
139.1287 + }
139.1288 +
139.1289 + Degree [me] = degme ;
139.1290 +
139.1291 + /* ----------------------------------------------------------------- */
139.1292 + /* Clear the counter array, W [...], by incrementing wflg. */
139.1293 + /* ----------------------------------------------------------------- */
139.1294 +
139.1295 + /* make sure that wflg+n does not cause integer overflow */
139.1296 + lemax = MAX (lemax, degme) ;
139.1297 + wflg += lemax ;
139.1298 + wflg = clear_flag (wflg, wbig, W, n) ;
139.1299 + /* at this point, W [0..n-1] < wflg holds */
139.1300 +
139.1301 +/* ========================================================================= */
139.1302 +/* SUPERVARIABLE DETECTION */
139.1303 +/* ========================================================================= */
139.1304 +
139.1305 + AMD_DEBUG1 (("Detecting supervariables:\n")) ;
139.1306 + for (pme = pme1 ; pme <= pme2 ; pme++)
139.1307 + {
139.1308 + i = Iw [pme] ;
139.1309 + ASSERT (i >= 0 && i < n) ;
139.1310 + AMD_DEBUG2 (("Consider i "ID" nv "ID"\n", i, Nv [i])) ;
139.1311 + if (Nv [i] < 0)
139.1312 + {
139.1313 + /* i is a principal variable in Lme */
139.1314 +
139.1315 + /* ---------------------------------------------------------
139.1316 + * examine all hash buckets with 2 or more variables. We do
139.1317 + * this by examing all unique hash keys for supervariables in
139.1318 + * the pattern Lme of the current element, me
139.1319 + * --------------------------------------------------------- */
139.1320 +
139.1321 + /* let i = head of hash bucket, and empty the hash bucket */
139.1322 + ASSERT (Last [i] >= 0 && Last [i] < n) ;
139.1323 + hash = Last [i] ;
139.1324 +
139.1325 + /* if Hhead array is not used: */
139.1326 + j = Head [hash] ;
139.1327 + if (j == EMPTY)
139.1328 + {
139.1329 + /* hash bucket and degree list are both empty */
139.1330 + i = EMPTY ;
139.1331 + }
139.1332 + else if (j < EMPTY)
139.1333 + {
139.1334 + /* degree list is empty */
139.1335 + i = FLIP (j) ;
139.1336 + Head [hash] = EMPTY ;
139.1337 + }
139.1338 + else
139.1339 + {
139.1340 + /* degree list is not empty, restore Last [j] of head j */
139.1341 + i = Last [j] ;
139.1342 + Last [j] = EMPTY ;
139.1343 + }
139.1344 +
139.1345 + /* if separate Hhead array is used: *
139.1346 + i = Hhead [hash] ;
139.1347 + Hhead [hash] = EMPTY ;
139.1348 + */
139.1349 +
139.1350 + ASSERT (i >= EMPTY && i < n) ;
139.1351 + AMD_DEBUG2 (("----i "ID" hash "ID"\n", i, hash)) ;
139.1352 +
139.1353 + while (i != EMPTY && Next [i] != EMPTY)
139.1354 + {
139.1355 +
139.1356 + /* -----------------------------------------------------
139.1357 + * this bucket has one or more variables following i.
139.1358 + * scan all of them to see if i can absorb any entries
139.1359 + * that follow i in hash bucket. Scatter i into w.
139.1360 + * ----------------------------------------------------- */
139.1361 +
139.1362 + ln = Len [i] ;
139.1363 + eln = Elen [i] ;
139.1364 + ASSERT (ln >= 0 && eln >= 0) ;
139.1365 + ASSERT (Pe [i] >= 0 && Pe [i] < iwlen) ;
139.1366 + /* do not flag the first element in the list (me) */
139.1367 + for (p = Pe [i] + 1 ; p <= Pe [i] + ln - 1 ; p++)
139.1368 + {
139.1369 + ASSERT (Iw [p] >= 0 && Iw [p] < n) ;
139.1370 + W [Iw [p]] = wflg ;
139.1371 + }
139.1372 +
139.1373 + /* ----------------------------------------------------- */
139.1374 + /* scan every other entry j following i in bucket */
139.1375 + /* ----------------------------------------------------- */
139.1376 +
139.1377 + jlast = i ;
139.1378 + j = Next [i] ;
139.1379 + ASSERT (j >= EMPTY && j < n) ;
139.1380 +
139.1381 + while (j != EMPTY)
139.1382 + {
139.1383 + /* ------------------------------------------------- */
139.1384 + /* check if j and i have identical nonzero pattern */
139.1385 + /* ------------------------------------------------- */
139.1386 +
139.1387 + AMD_DEBUG3 (("compare i "ID" and j "ID"\n", i,j)) ;
139.1388 +
139.1389 + /* check if i and j have the same Len and Elen */
139.1390 + ASSERT (Len [j] >= 0 && Elen [j] >= 0) ;
139.1391 + ASSERT (Pe [j] >= 0 && Pe [j] < iwlen) ;
139.1392 + ok = (Len [j] == ln) && (Elen [j] == eln) ;
139.1393 + /* skip the first element in the list (me) */
139.1394 + for (p = Pe [j] + 1 ; ok && p <= Pe [j] + ln - 1 ; p++)
139.1395 + {
139.1396 + ASSERT (Iw [p] >= 0 && Iw [p] < n) ;
139.1397 + if (W [Iw [p]] != wflg) ok = 0 ;
139.1398 + }
139.1399 + if (ok)
139.1400 + {
139.1401 + /* --------------------------------------------- */
139.1402 + /* found it! j can be absorbed into i */
139.1403 + /* --------------------------------------------- */
139.1404 +
139.1405 + AMD_DEBUG1 (("found it! j "ID" => i "ID"\n", j,i));
139.1406 + Pe [j] = FLIP (i) ;
139.1407 + /* both Nv [i] and Nv [j] are negated since they */
139.1408 + /* are in Lme, and the absolute values of each */
139.1409 + /* are the number of variables in i and j: */
139.1410 + Nv [i] += Nv [j] ;
139.1411 + Nv [j] = 0 ;
139.1412 + Elen [j] = EMPTY ;
139.1413 + /* delete j from hash bucket */
139.1414 + ASSERT (j != Next [j]) ;
139.1415 + j = Next [j] ;
139.1416 + Next [jlast] = j ;
139.1417 +
139.1418 + }
139.1419 + else
139.1420 + {
139.1421 + /* j cannot be absorbed into i */
139.1422 + jlast = j ;
139.1423 + ASSERT (j != Next [j]) ;
139.1424 + j = Next [j] ;
139.1425 + }
139.1426 + ASSERT (j >= EMPTY && j < n) ;
139.1427 + }
139.1428 +
139.1429 + /* -----------------------------------------------------
139.1430 + * no more variables can be absorbed into i
139.1431 + * go to next i in bucket and clear flag array
139.1432 + * ----------------------------------------------------- */
139.1433 +
139.1434 + wflg++ ;
139.1435 + i = Next [i] ;
139.1436 + ASSERT (i >= EMPTY && i < n) ;
139.1437 +
139.1438 + }
139.1439 + }
139.1440 + }
139.1441 + AMD_DEBUG2 (("detect done\n")) ;
139.1442 +
139.1443 +/* ========================================================================= */
139.1444 +/* RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVARIABLES FROM ELEMENT */
139.1445 +/* ========================================================================= */
139.1446 +
139.1447 + p = pme1 ;
139.1448 + nleft = n - nel ;
139.1449 + for (pme = pme1 ; pme <= pme2 ; pme++)
139.1450 + {
139.1451 + i = Iw [pme] ;
139.1452 + ASSERT (i >= 0 && i < n) ;
139.1453 + nvi = -Nv [i] ;
139.1454 + AMD_DEBUG3 (("Restore i "ID" "ID"\n", i, nvi)) ;
139.1455 + if (nvi > 0)
139.1456 + {
139.1457 + /* i is a principal variable in Lme */
139.1458 + /* restore Nv [i] to signify that i is principal */
139.1459 + Nv [i] = nvi ;
139.1460 +
139.1461 + /* --------------------------------------------------------- */
139.1462 + /* compute the external degree (add size of current element) */
139.1463 + /* --------------------------------------------------------- */
139.1464 +
139.1465 + deg = Degree [i] + degme - nvi ;
139.1466 + deg = MIN (deg, nleft - nvi) ;
139.1467 + ASSERT (IMPLIES (aggressive, deg > 0) && deg >= 0 && deg < n) ;
139.1468 +
139.1469 + /* --------------------------------------------------------- */
139.1470 + /* place the supervariable at the head of the degree list */
139.1471 + /* --------------------------------------------------------- */
139.1472 +
139.1473 + inext = Head [deg] ;
139.1474 + ASSERT (inext >= EMPTY && inext < n) ;
139.1475 + if (inext != EMPTY) Last [inext] = i ;
139.1476 + Next [i] = inext ;
139.1477 + Last [i] = EMPTY ;
139.1478 + Head [deg] = i ;
139.1479 +
139.1480 + /* --------------------------------------------------------- */
139.1481 + /* save the new degree, and find the minimum degree */
139.1482 + /* --------------------------------------------------------- */
139.1483 +
139.1484 + mindeg = MIN (mindeg, deg) ;
139.1485 + Degree [i] = deg ;
139.1486 +
139.1487 + /* --------------------------------------------------------- */
139.1488 + /* place the supervariable in the element pattern */
139.1489 + /* --------------------------------------------------------- */
139.1490 +
139.1491 + Iw [p++] = i ;
139.1492 +
139.1493 + }
139.1494 + }
139.1495 + AMD_DEBUG2 (("restore done\n")) ;
139.1496 +
139.1497 +/* ========================================================================= */
139.1498 +/* FINALIZE THE NEW ELEMENT */
139.1499 +/* ========================================================================= */
139.1500 +
139.1501 + AMD_DEBUG2 (("ME = "ID" DONE\n", me)) ;
139.1502 + Nv [me] = nvpiv ;
139.1503 + /* save the length of the list for the new element me */
139.1504 + Len [me] = p - pme1 ;
139.1505 + if (Len [me] == 0)
139.1506 + {
139.1507 + /* there is nothing left of the current pivot element */
139.1508 + /* it is a root of the assembly tree */
139.1509 + Pe [me] = EMPTY ;
139.1510 + W [me] = 0 ;
139.1511 + }
139.1512 + if (elenme != 0)
139.1513 + {
139.1514 + /* element was not constructed in place: deallocate part of */
139.1515 + /* it since newly nonprincipal variables may have been removed */
139.1516 + pfree = p ;
139.1517 + }
139.1518 +
139.1519 + /* The new element has nvpiv pivots and the size of the contribution
139.1520 + * block for a multifrontal method is degme-by-degme, not including
139.1521 + * the "dense" rows/columns. If the "dense" rows/columns are included,
139.1522 + * the frontal matrix is no larger than
139.1523 + * (degme+ndense)-by-(degme+ndense).
139.1524 + */
139.1525 +
139.1526 + if (Info != (double *) NULL)
139.1527 + {
139.1528 + f = nvpiv ;
139.1529 + r = degme + ndense ;
139.1530 + dmax = MAX (dmax, f + r) ;
139.1531 +
139.1532 + /* number of nonzeros in L (excluding the diagonal) */
139.1533 + lnzme = f*r + (f-1)*f/2 ;
139.1534 + lnz += lnzme ;
139.1535 +
139.1536 + /* number of divide operations for LDL' and for LU */
139.1537 + ndiv += lnzme ;
139.1538 +
139.1539 + /* number of multiply-subtract pairs for LU */
139.1540 + s = f*r*r + r*(f-1)*f + (f-1)*f*(2*f-1)/6 ;
139.1541 + nms_lu += s ;
139.1542 +
139.1543 + /* number of multiply-subtract pairs for LDL' */
139.1544 + nms_ldl += (s + lnzme)/2 ;
139.1545 + }
139.1546 +
139.1547 +#ifndef NDEBUG
139.1548 + AMD_DEBUG2 (("finalize done nel "ID" n "ID"\n ::::\n", nel, n)) ;
139.1549 + for (pme = Pe [me] ; pme <= Pe [me] + Len [me] - 1 ; pme++)
139.1550 + {
139.1551 + AMD_DEBUG3 ((" "ID"", Iw [pme])) ;
139.1552 + }
139.1553 + AMD_DEBUG3 (("\n")) ;
139.1554 +#endif
139.1555 +
139.1556 + }
139.1557 +
139.1558 +/* ========================================================================= */
139.1559 +/* DONE SELECTING PIVOTS */
139.1560 +/* ========================================================================= */
139.1561 +
139.1562 + if (Info != (double *) NULL)
139.1563 + {
139.1564 +
139.1565 + /* count the work to factorize the ndense-by-ndense submatrix */
139.1566 + f = ndense ;
139.1567 + dmax = MAX (dmax, (double) ndense) ;
139.1568 +
139.1569 + /* number of nonzeros in L (excluding the diagonal) */
139.1570 + lnzme = (f-1)*f/2 ;
139.1571 + lnz += lnzme ;
139.1572 +
139.1573 + /* number of divide operations for LDL' and for LU */
139.1574 + ndiv += lnzme ;
139.1575 +
139.1576 + /* number of multiply-subtract pairs for LU */
139.1577 + s = (f-1)*f*(2*f-1)/6 ;
139.1578 + nms_lu += s ;
139.1579 +
139.1580 + /* number of multiply-subtract pairs for LDL' */
139.1581 + nms_ldl += (s + lnzme)/2 ;
139.1582 +
139.1583 + /* number of nz's in L (excl. diagonal) */
139.1584 + Info [AMD_LNZ] = lnz ;
139.1585 +
139.1586 + /* number of divide ops for LU and LDL' */
139.1587 + Info [AMD_NDIV] = ndiv ;
139.1588 +
139.1589 + /* number of multiply-subtract pairs for LDL' */
139.1590 + Info [AMD_NMULTSUBS_LDL] = nms_ldl ;
139.1591 +
139.1592 + /* number of multiply-subtract pairs for LU */
139.1593 + Info [AMD_NMULTSUBS_LU] = nms_lu ;
139.1594 +
139.1595 + /* number of "dense" rows/columns */
139.1596 + Info [AMD_NDENSE] = ndense ;
139.1597 +
139.1598 + /* largest front is dmax-by-dmax */
139.1599 + Info [AMD_DMAX] = dmax ;
139.1600 +
139.1601 + /* number of garbage collections in AMD */
139.1602 + Info [AMD_NCMPA] = ncmpa ;
139.1603 +
139.1604 + /* successful ordering */
139.1605 + Info [AMD_STATUS] = AMD_OK ;
139.1606 + }
139.1607 +
139.1608 +/* ========================================================================= */
139.1609 +/* POST-ORDERING */
139.1610 +/* ========================================================================= */
139.1611 +
139.1612 +/* -------------------------------------------------------------------------
139.1613 + * Variables at this point:
139.1614 + *
139.1615 + * Pe: holds the elimination tree. The parent of j is FLIP (Pe [j]),
139.1616 + * or EMPTY if j is a root. The tree holds both elements and
139.1617 + * non-principal (unordered) variables absorbed into them.
139.1618 + * Dense variables are non-principal and unordered.
139.1619 + *
139.1620 + * Elen: holds the size of each element, including the diagonal part.
139.1621 + * FLIP (Elen [e]) > 0 if e is an element. For unordered
139.1622 + * variables i, Elen [i] is EMPTY.
139.1623 + *
139.1624 + * Nv: Nv [e] > 0 is the number of pivots represented by the element e.
139.1625 + * For unordered variables i, Nv [i] is zero.
139.1626 + *
139.1627 + * Contents no longer needed:
139.1628 + * W, Iw, Len, Degree, Head, Next, Last.
139.1629 + *
139.1630 + * The matrix itself has been destroyed.
139.1631 + *
139.1632 + * n: the size of the matrix.
139.1633 + * No other scalars needed (pfree, iwlen, etc.)
139.1634 + * ------------------------------------------------------------------------- */
139.1635 +
139.1636 + /* restore Pe */
139.1637 + for (i = 0 ; i < n ; i++)
139.1638 + {
139.1639 + Pe [i] = FLIP (Pe [i]) ;
139.1640 + }
139.1641 +
139.1642 + /* restore Elen, for output information, and for postordering */
139.1643 + for (i = 0 ; i < n ; i++)
139.1644 + {
139.1645 + Elen [i] = FLIP (Elen [i]) ;
139.1646 + }
139.1647 +
139.1648 +/* Now the parent of j is Pe [j], or EMPTY if j is a root. Elen [e] > 0
139.1649 + * is the size of element e. Elen [i] is EMPTY for unordered variable i. */
139.1650 +
139.1651 +#ifndef NDEBUG
139.1652 + AMD_DEBUG2 (("\nTree:\n")) ;
139.1653 + for (i = 0 ; i < n ; i++)
139.1654 + {
139.1655 + AMD_DEBUG2 ((" "ID" parent: "ID" ", i, Pe [i])) ;
139.1656 + ASSERT (Pe [i] >= EMPTY && Pe [i] < n) ;
139.1657 + if (Nv [i] > 0)
139.1658 + {
139.1659 + /* this is an element */
139.1660 + e = i ;
139.1661 + AMD_DEBUG2 ((" element, size is "ID"\n", Elen [i])) ;
139.1662 + ASSERT (Elen [e] > 0) ;
139.1663 + }
139.1664 + AMD_DEBUG2 (("\n")) ;
139.1665 + }
139.1666 + AMD_DEBUG2 (("\nelements:\n")) ;
139.1667 + for (e = 0 ; e < n ; e++)
139.1668 + {
139.1669 + if (Nv [e] > 0)
139.1670 + {
139.1671 + AMD_DEBUG3 (("Element e= "ID" size "ID" nv "ID" \n", e,
139.1672 + Elen [e], Nv [e])) ;
139.1673 + }
139.1674 + }
139.1675 + AMD_DEBUG2 (("\nvariables:\n")) ;
139.1676 + for (i = 0 ; i < n ; i++)
139.1677 + {
139.1678 + Int cnt ;
139.1679 + if (Nv [i] == 0)
139.1680 + {
139.1681 + AMD_DEBUG3 (("i unordered: "ID"\n", i)) ;
139.1682 + j = Pe [i] ;
139.1683 + cnt = 0 ;
139.1684 + AMD_DEBUG3 ((" j: "ID"\n", j)) ;
139.1685 + if (j == EMPTY)
139.1686 + {
139.1687 + AMD_DEBUG3 ((" i is a dense variable\n")) ;
139.1688 + }
139.1689 + else
139.1690 + {
139.1691 + ASSERT (j >= 0 && j < n) ;
139.1692 + while (Nv [j] == 0)
139.1693 + {
139.1694 + AMD_DEBUG3 ((" j : "ID"\n", j)) ;
139.1695 + j = Pe [j] ;
139.1696 + AMD_DEBUG3 ((" j:: "ID"\n", j)) ;
139.1697 + cnt++ ;
139.1698 + if (cnt > n) break ;
139.1699 + }
139.1700 + e = j ;
139.1701 + AMD_DEBUG3 ((" got to e: "ID"\n", e)) ;
139.1702 + }
139.1703 + }
139.1704 + }
139.1705 +#endif
139.1706 +
139.1707 +/* ========================================================================= */
139.1708 +/* compress the paths of the variables */
139.1709 +/* ========================================================================= */
139.1710 +
139.1711 + for (i = 0 ; i < n ; i++)
139.1712 + {
139.1713 + if (Nv [i] == 0)
139.1714 + {
139.1715 +
139.1716 + /* -------------------------------------------------------------
139.1717 + * i is an un-ordered row. Traverse the tree from i until
139.1718 + * reaching an element, e. The element, e, was the principal
139.1719 + * supervariable of i and all nodes in the path from i to when e
139.1720 + * was selected as pivot.
139.1721 + * ------------------------------------------------------------- */
139.1722 +
139.1723 + AMD_DEBUG1 (("Path compression, i unordered: "ID"\n", i)) ;
139.1724 + j = Pe [i] ;
139.1725 + ASSERT (j >= EMPTY && j < n) ;
139.1726 + AMD_DEBUG3 ((" j: "ID"\n", j)) ;
139.1727 + if (j == EMPTY)
139.1728 + {
139.1729 + /* Skip a dense variable. It has no parent. */
139.1730 + AMD_DEBUG3 ((" i is a dense variable\n")) ;
139.1731 + continue ;
139.1732 + }
139.1733 +
139.1734 + /* while (j is a variable) */
139.1735 + while (Nv [j] == 0)
139.1736 + {
139.1737 + AMD_DEBUG3 ((" j : "ID"\n", j)) ;
139.1738 + j = Pe [j] ;
139.1739 + AMD_DEBUG3 ((" j:: "ID"\n", j)) ;
139.1740 + ASSERT (j >= 0 && j < n) ;
139.1741 + }
139.1742 + /* got to an element e */
139.1743 + e = j ;
139.1744 + AMD_DEBUG3 (("got to e: "ID"\n", e)) ;
139.1745 +
139.1746 + /* -------------------------------------------------------------
139.1747 + * traverse the path again from i to e, and compress the path
139.1748 + * (all nodes point to e). Path compression allows this code to
139.1749 + * compute in O(n) time.
139.1750 + * ------------------------------------------------------------- */
139.1751 +
139.1752 + j = i ;
139.1753 + /* while (j is a variable) */
139.1754 + while (Nv [j] == 0)
139.1755 + {
139.1756 + jnext = Pe [j] ;
139.1757 + AMD_DEBUG3 (("j "ID" jnext "ID"\n", j, jnext)) ;
139.1758 + Pe [j] = e ;
139.1759 + j = jnext ;
139.1760 + ASSERT (j >= 0 && j < n) ;
139.1761 + }
139.1762 + }
139.1763 + }
139.1764 +
139.1765 +/* ========================================================================= */
139.1766 +/* postorder the assembly tree */
139.1767 +/* ========================================================================= */
139.1768 +
139.1769 + AMD_postorder (n, Pe, Nv, Elen,
139.1770 + W, /* output order */
139.1771 + Head, Next, Last) ; /* workspace */
139.1772 +
139.1773 +/* ========================================================================= */
139.1774 +/* compute output permutation and inverse permutation */
139.1775 +/* ========================================================================= */
139.1776 +
139.1777 + /* W [e] = k means that element e is the kth element in the new
139.1778 + * order. e is in the range 0 to n-1, and k is in the range 0 to
139.1779 + * the number of elements. Use Head for inverse order. */
139.1780 +
139.1781 + for (k = 0 ; k < n ; k++)
139.1782 + {
139.1783 + Head [k] = EMPTY ;
139.1784 + Next [k] = EMPTY ;
139.1785 + }
139.1786 + for (e = 0 ; e < n ; e++)
139.1787 + {
139.1788 + k = W [e] ;
139.1789 + ASSERT ((k == EMPTY) == (Nv [e] == 0)) ;
139.1790 + if (k != EMPTY)
139.1791 + {
139.1792 + ASSERT (k >= 0 && k < n) ;
139.1793 + Head [k] = e ;
139.1794 + }
139.1795 + }
139.1796 +
139.1797 + /* construct output inverse permutation in Next,
139.1798 + * and permutation in Last */
139.1799 + nel = 0 ;
139.1800 + for (k = 0 ; k < n ; k++)
139.1801 + {
139.1802 + e = Head [k] ;
139.1803 + if (e == EMPTY) break ;
139.1804 + ASSERT (e >= 0 && e < n && Nv [e] > 0) ;
139.1805 + Next [e] = nel ;
139.1806 + nel += Nv [e] ;
139.1807 + }
139.1808 + ASSERT (nel == n - ndense) ;
139.1809 +
139.1810 + /* order non-principal variables (dense, & those merged into supervar's) */
139.1811 + for (i = 0 ; i < n ; i++)
139.1812 + {
139.1813 + if (Nv [i] == 0)
139.1814 + {
139.1815 + e = Pe [i] ;
139.1816 + ASSERT (e >= EMPTY && e < n) ;
139.1817 + if (e != EMPTY)
139.1818 + {
139.1819 + /* This is an unordered variable that was merged
139.1820 + * into element e via supernode detection or mass
139.1821 + * elimination of i when e became the pivot element.
139.1822 + * Place i in order just before e. */
139.1823 + ASSERT (Next [i] == EMPTY && Nv [e] > 0) ;
139.1824 + Next [i] = Next [e] ;
139.1825 + Next [e]++ ;
139.1826 + }
139.1827 + else
139.1828 + {
139.1829 + /* This is a dense unordered variable, with no parent.
139.1830 + * Place it last in the output order. */
139.1831 + Next [i] = nel++ ;
139.1832 + }
139.1833 + }
139.1834 + }
139.1835 + ASSERT (nel == n) ;
139.1836 +
139.1837 + AMD_DEBUG2 (("\n\nPerm:\n")) ;
139.1838 + for (i = 0 ; i < n ; i++)
139.1839 + {
139.1840 + k = Next [i] ;
139.1841 + ASSERT (k >= 0 && k < n) ;
139.1842 + Last [k] = i ;
139.1843 + AMD_DEBUG2 ((" perm ["ID"] = "ID"\n", k, i)) ;
139.1844 + }
139.1845 +}
140.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
140.2 +++ b/src/amd/amd_aat.c Mon Dec 06 13:09:21 2010 +0100
140.3 @@ -0,0 +1,185 @@
140.4 +/* ========================================================================= */
140.5 +/* === AMD_aat ============================================================= */
140.6 +/* ========================================================================= */
140.7 +
140.8 +/* ------------------------------------------------------------------------- */
140.9 +/* AMD, Copyright (c) Timothy A. Davis, */
140.10 +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
140.11 +/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
140.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd */
140.13 +/* ------------------------------------------------------------------------- */
140.14 +
140.15 +/* AMD_aat: compute the symmetry of the pattern of A, and count the number of
140.16 + * nonzeros each column of A+A' (excluding the diagonal). Assumes the input
140.17 + * matrix has no errors, with sorted columns and no duplicates
140.18 + * (AMD_valid (n, n, Ap, Ai) must be AMD_OK, but this condition is not
140.19 + * checked).
140.20 + */
140.21 +
140.22 +#include "amd_internal.h"
140.23 +
140.24 +GLOBAL size_t AMD_aat /* returns nz in A+A' */
140.25 +(
140.26 + Int n,
140.27 + const Int Ap [ ],
140.28 + const Int Ai [ ],
140.29 + Int Len [ ], /* Len [j]: length of column j of A+A', excl diagonal*/
140.30 + Int Tp [ ], /* workspace of size n */
140.31 + double Info [ ]
140.32 +)
140.33 +{
140.34 + Int p1, p2, p, i, j, pj, pj2, k, nzdiag, nzboth, nz ;
140.35 + double sym ;
140.36 + size_t nzaat ;
140.37 +
140.38 +#ifndef NDEBUG
140.39 + AMD_debug_init ("AMD AAT") ;
140.40 + for (k = 0 ; k < n ; k++) Tp [k] = EMPTY ;
140.41 + ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ;
140.42 +#endif
140.43 +
140.44 + if (Info != (double *) NULL)
140.45 + {
140.46 + /* clear the Info array, if it exists */
140.47 + for (i = 0 ; i < AMD_INFO ; i++)
140.48 + {
140.49 + Info [i] = EMPTY ;
140.50 + }
140.51 + Info [AMD_STATUS] = AMD_OK ;
140.52 + }
140.53 +
140.54 + for (k = 0 ; k < n ; k++)
140.55 + {
140.56 + Len [k] = 0 ;
140.57 + }
140.58 +
140.59 + nzdiag = 0 ;
140.60 + nzboth = 0 ;
140.61 + nz = Ap [n] ;
140.62 +
140.63 + for (k = 0 ; k < n ; k++)
140.64 + {
140.65 + p1 = Ap [k] ;
140.66 + p2 = Ap [k+1] ;
140.67 + AMD_DEBUG2 (("\nAAT Column: "ID" p1: "ID" p2: "ID"\n", k, p1, p2)) ;
140.68 +
140.69 + /* construct A+A' */
140.70 + for (p = p1 ; p < p2 ; )
140.71 + {
140.72 + /* scan the upper triangular part of A */
140.73 + j = Ai [p] ;
140.74 + if (j < k)
140.75 + {
140.76 + /* entry A (j,k) is in the strictly upper triangular part,
140.77 + * add both A (j,k) and A (k,j) to the matrix A+A' */
140.78 + Len [j]++ ;
140.79 + Len [k]++ ;
140.80 + AMD_DEBUG3 ((" upper ("ID","ID") ("ID","ID")\n", j,k, k,j));
140.81 + p++ ;
140.82 + }
140.83 + else if (j == k)
140.84 + {
140.85 + /* skip the diagonal */
140.86 + p++ ;
140.87 + nzdiag++ ;
140.88 + break ;
140.89 + }
140.90 + else /* j > k */
140.91 + {
140.92 + /* first entry below the diagonal */
140.93 + break ;
140.94 + }
140.95 + /* scan lower triangular part of A, in column j until reaching
140.96 + * row k. Start where last scan left off. */
140.97 + ASSERT (Tp [j] != EMPTY) ;
140.98 + ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
140.99 + pj2 = Ap [j+1] ;
140.100 + for (pj = Tp [j] ; pj < pj2 ; )
140.101 + {
140.102 + i = Ai [pj] ;
140.103 + if (i < k)
140.104 + {
140.105 + /* A (i,j) is only in the lower part, not in upper.
140.106 + * add both A (i,j) and A (j,i) to the matrix A+A' */
140.107 + Len [i]++ ;
140.108 + Len [j]++ ;
140.109 + AMD_DEBUG3 ((" lower ("ID","ID") ("ID","ID")\n",
140.110 + i,j, j,i)) ;
140.111 + pj++ ;
140.112 + }
140.113 + else if (i == k)
140.114 + {
140.115 + /* entry A (k,j) in lower part and A (j,k) in upper */
140.116 + pj++ ;
140.117 + nzboth++ ;
140.118 + break ;
140.119 + }
140.120 + else /* i > k */
140.121 + {
140.122 + /* consider this entry later, when k advances to i */
140.123 + break ;
140.124 + }
140.125 + }
140.126 + Tp [j] = pj ;
140.127 + }
140.128 + /* Tp [k] points to the entry just below the diagonal in column k */
140.129 + Tp [k] = p ;
140.130 + }
140.131 +
140.132 + /* clean up, for remaining mismatched entries */
140.133 + for (j = 0 ; j < n ; j++)
140.134 + {
140.135 + for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
140.136 + {
140.137 + i = Ai [pj] ;
140.138 + /* A (i,j) is only in the lower part, not in upper.
140.139 + * add both A (i,j) and A (j,i) to the matrix A+A' */
140.140 + Len [i]++ ;
140.141 + Len [j]++ ;
140.142 + AMD_DEBUG3 ((" lower cleanup ("ID","ID") ("ID","ID")\n",
140.143 + i,j, j,i)) ;
140.144 + }
140.145 + }
140.146 +
140.147 + /* --------------------------------------------------------------------- */
140.148 + /* compute the symmetry of the nonzero pattern of A */
140.149 + /* --------------------------------------------------------------------- */
140.150 +
140.151 + /* Given a matrix A, the symmetry of A is:
140.152 + * B = tril (spones (A), -1) + triu (spones (A), 1) ;
140.153 + * sym = nnz (B & B') / nnz (B) ;
140.154 + * or 1 if nnz (B) is zero.
140.155 + */
140.156 +
140.157 + if (nz == nzdiag)
140.158 + {
140.159 + sym = 1 ;
140.160 + }
140.161 + else
140.162 + {
140.163 + sym = (2 * (double) nzboth) / ((double) (nz - nzdiag)) ;
140.164 + }
140.165 +
140.166 + nzaat = 0 ;
140.167 + for (k = 0 ; k < n ; k++)
140.168 + {
140.169 + nzaat += Len [k] ;
140.170 + }
140.171 +
140.172 + AMD_DEBUG1 (("AMD nz in A+A', excluding diagonal (nzaat) = %g\n",
140.173 + (double) nzaat)) ;
140.174 + AMD_DEBUG1 ((" nzboth: "ID" nz: "ID" nzdiag: "ID" symmetry: %g\n",
140.175 + nzboth, nz, nzdiag, sym)) ;
140.176 +
140.177 + if (Info != (double *) NULL)
140.178 + {
140.179 + Info [AMD_STATUS] = AMD_OK ;
140.180 + Info [AMD_N] = n ;
140.181 + Info [AMD_NZ] = nz ;
140.182 + Info [AMD_SYMMETRY] = sym ; /* symmetry of pattern of A */
140.183 + Info [AMD_NZDIAG] = nzdiag ; /* nonzeros on diagonal of A */
140.184 + Info [AMD_NZ_A_PLUS_AT] = nzaat ; /* nonzeros in A+A' */
140.185 + }
140.186 +
140.187 + return (nzaat) ;
140.188 +}
141.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
141.2 +++ b/src/amd/amd_control.c Mon Dec 06 13:09:21 2010 +0100
141.3 @@ -0,0 +1,64 @@
141.4 +/* ========================================================================= */
141.5 +/* === AMD_control ========================================================= */
141.6 +/* ========================================================================= */
141.7 +
141.8 +/* ------------------------------------------------------------------------- */
141.9 +/* AMD, Copyright (c) Timothy A. Davis, */
141.10 +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
141.11 +/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
141.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd */
141.13 +/* ------------------------------------------------------------------------- */
141.14 +
141.15 +/* User-callable. Prints the control parameters for AMD. See amd.h
141.16 + * for details. If the Control array is not present, the defaults are
141.17 + * printed instead.
141.18 + */
141.19 +
141.20 +#include "amd_internal.h"
141.21 +
141.22 +GLOBAL void AMD_control
141.23 +(
141.24 + double Control [ ]
141.25 +)
141.26 +{
141.27 + double alpha ;
141.28 + Int aggressive ;
141.29 +
141.30 + if (Control != (double *) NULL)
141.31 + {
141.32 + alpha = Control [AMD_DENSE] ;
141.33 + aggressive = Control [AMD_AGGRESSIVE] != 0 ;
141.34 + }
141.35 + else
141.36 + {
141.37 + alpha = AMD_DEFAULT_DENSE ;
141.38 + aggressive = AMD_DEFAULT_AGGRESSIVE ;
141.39 + }
141.40 +
141.41 + PRINTF (("\nAMD version %d.%d.%d, %s: approximate minimum degree ordering\n"
141.42 + " dense row parameter: %g\n", AMD_MAIN_VERSION, AMD_SUB_VERSION,
141.43 + AMD_SUBSUB_VERSION, AMD_DATE, alpha)) ;
141.44 +
141.45 + if (alpha < 0)
141.46 + {
141.47 + PRINTF ((" no rows treated as dense\n")) ;
141.48 + }
141.49 + else
141.50 + {
141.51 + PRINTF ((
141.52 + " (rows with more than max (%g * sqrt (n), 16) entries are\n"
141.53 + " considered \"dense\", and placed last in output permutation)\n",
141.54 + alpha)) ;
141.55 + }
141.56 +
141.57 + if (aggressive)
141.58 + {
141.59 + PRINTF ((" aggressive absorption: yes\n")) ;
141.60 + }
141.61 + else
141.62 + {
141.63 + PRINTF ((" aggressive absorption: no\n")) ;
141.64 + }
141.65 +
141.66 + PRINTF ((" size of AMD integer: %d\n\n", sizeof (Int))) ;
141.67 +}
142.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
142.2 +++ b/src/amd/amd_defaults.c Mon Dec 06 13:09:21 2010 +0100
142.3 @@ -0,0 +1,38 @@
142.4 +/* ========================================================================= */
142.5 +/* === AMD_defaults ======================================================== */
142.6 +/* ========================================================================= */
142.7 +
142.8 +/* ------------------------------------------------------------------------- */
142.9 +/* AMD, Copyright (c) Timothy A. Davis, */
142.10 +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
142.11 +/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
142.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd */
142.13 +/* ------------------------------------------------------------------------- */
142.14 +
142.15 +/* User-callable. Sets default control parameters for AMD. See amd.h
142.16 + * for details.
142.17 + */
142.18 +
142.19 +#include "amd_internal.h"
142.20 +
142.21 +/* ========================================================================= */
142.22 +/* === AMD defaults ======================================================== */
142.23 +/* ========================================================================= */
142.24 +
142.25 +GLOBAL void AMD_defaults
142.26 +(
142.27 + double Control [ ]
142.28 +)
142.29 +{
142.30 + Int i ;
142.31 +
142.32 + if (Control != (double *) NULL)
142.33 + {
142.34 + for (i = 0 ; i < AMD_CONTROL ; i++)
142.35 + {
142.36 + Control [i] = 0 ;
142.37 + }
142.38 + Control [AMD_DENSE] = AMD_DEFAULT_DENSE ;
142.39 + Control [AMD_AGGRESSIVE] = AMD_DEFAULT_AGGRESSIVE ;
142.40 + }
142.41 +}
143.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
143.2 +++ b/src/amd/amd_dump.c Mon Dec 06 13:09:21 2010 +0100
143.3 @@ -0,0 +1,180 @@
143.4 +/* ========================================================================= */
143.5 +/* === AMD_dump ============================================================ */
143.6 +/* ========================================================================= */
143.7 +
143.8 +/* ------------------------------------------------------------------------- */
143.9 +/* AMD, Copyright (c) Timothy A. Davis, */
143.10 +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
143.11 +/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
143.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd */
143.13 +/* ------------------------------------------------------------------------- */
143.14 +
143.15 +/* Debugging routines for AMD. Not used if NDEBUG is not defined at compile-
143.16 + * time (the default). See comments in amd_internal.h on how to enable
143.17 + * debugging. Not user-callable.
143.18 + */
143.19 +
143.20 +#include "amd_internal.h"
143.21 +
143.22 +#ifndef NDEBUG
143.23 +
143.24 +/* This global variable is present only when debugging */
143.25 +GLOBAL Int AMD_debug = -999 ; /* default is no debug printing */
143.26 +
143.27 +/* ========================================================================= */
143.28 +/* === AMD_debug_init ====================================================== */
143.29 +/* ========================================================================= */
143.30 +
143.31 +/* Sets the debug print level, by reading the file debug.amd (if it exists) */
143.32 +
143.33 +GLOBAL void AMD_debug_init ( char *s )
143.34 +{
143.35 + FILE *f ;
143.36 + f = fopen ("debug.amd", "r") ;
143.37 + if (f == (FILE *) NULL)
143.38 + {
143.39 + AMD_debug = -999 ;
143.40 + }
143.41 + else
143.42 + {
143.43 + fscanf (f, ID, &AMD_debug) ;
143.44 + fclose (f) ;
143.45 + }
143.46 + if (AMD_debug >= 0)
143.47 + {
143.48 + printf ("%s: AMD_debug_init, D= "ID"\n", s, AMD_debug) ;
143.49 + }
143.50 +}
143.51 +
143.52 +/* ========================================================================= */
143.53 +/* === AMD_dump ============================================================ */
143.54 +/* ========================================================================= */
143.55 +
143.56 +/* Dump AMD's data structure, except for the hash buckets. This routine
143.57 + * cannot be called when the hash buckets are non-empty.
143.58 + */
143.59 +
143.60 +GLOBAL void AMD_dump (
143.61 + Int n, /* A is n-by-n */
143.62 + Int Pe [ ], /* pe [0..n-1]: index in iw of start of row i */
143.63 + Int Iw [ ], /* workspace of size iwlen, iwlen [0..pfree-1]
143.64 + * holds the matrix on input */
143.65 + Int Len [ ], /* len [0..n-1]: length for row i */
143.66 + Int iwlen, /* length of iw */
143.67 + Int pfree, /* iw [pfree ... iwlen-1] is empty on input */
143.68 + Int Nv [ ], /* nv [0..n-1] */
143.69 + Int Next [ ], /* next [0..n-1] */
143.70 + Int Last [ ], /* last [0..n-1] */
143.71 + Int Head [ ], /* head [0..n-1] */
143.72 + Int Elen [ ], /* size n */
143.73 + Int Degree [ ], /* size n */
143.74 + Int W [ ], /* size n */
143.75 + Int nel
143.76 +)
143.77 +{
143.78 + Int i, pe, elen, nv, len, e, p, k, j, deg, w, cnt, ilast ;
143.79 +
143.80 + if (AMD_debug < 0) return ;
143.81 + ASSERT (pfree <= iwlen) ;
143.82 + AMD_DEBUG3 (("\nAMD dump, pfree: "ID"\n", pfree)) ;
143.83 + for (i = 0 ; i < n ; i++)
143.84 + {
143.85 + pe = Pe [i] ;
143.86 + elen = Elen [i] ;
143.87 + nv = Nv [i] ;
143.88 + len = Len [i] ;
143.89 + w = W [i] ;
143.90 +
143.91 + if (elen >= EMPTY)
143.92 + {
143.93 + if (nv == 0)
143.94 + {
143.95 + AMD_DEBUG3 (("\nI "ID": nonprincipal: ", i)) ;
143.96 + ASSERT (elen == EMPTY) ;
143.97 + if (pe == EMPTY)
143.98 + {
143.99 + AMD_DEBUG3 ((" dense node\n")) ;
143.100 + ASSERT (w == 1) ;
143.101 + }
143.102 + else
143.103 + {
143.104 + ASSERT (pe < EMPTY) ;
143.105 + AMD_DEBUG3 ((" i "ID" -> parent "ID"\n", i, FLIP (Pe[i])));
143.106 + }
143.107 + }
143.108 + else
143.109 + {
143.110 + AMD_DEBUG3 (("\nI "ID": active principal supervariable:\n",i));
143.111 + AMD_DEBUG3 ((" nv(i): "ID" Flag: %d\n", nv, (nv < 0))) ;
143.112 + ASSERT (elen >= 0) ;
143.113 + ASSERT (nv > 0 && pe >= 0) ;
143.114 + p = pe ;
143.115 + AMD_DEBUG3 ((" e/s: ")) ;
143.116 + if (elen == 0) AMD_DEBUG3 ((" : ")) ;
143.117 + ASSERT (pe + len <= pfree) ;
143.118 + for (k = 0 ; k < len ; k++)
143.119 + {
143.120 + j = Iw [p] ;
143.121 + AMD_DEBUG3 ((" "ID"", j)) ;
143.122 + ASSERT (j >= 0 && j < n) ;
143.123 + if (k == elen-1) AMD_DEBUG3 ((" : ")) ;
143.124 + p++ ;
143.125 + }
143.126 + AMD_DEBUG3 (("\n")) ;
143.127 + }
143.128 + }
143.129 + else
143.130 + {
143.131 + e = i ;
143.132 + if (w == 0)
143.133 + {
143.134 + AMD_DEBUG3 (("\nE "ID": absorbed element: w "ID"\n", e, w)) ;
143.135 + ASSERT (nv > 0 && pe < 0) ;
143.136 + AMD_DEBUG3 ((" e "ID" -> parent "ID"\n", e, FLIP (Pe [e]))) ;
143.137 + }
143.138 + else
143.139 + {
143.140 + AMD_DEBUG3 (("\nE "ID": unabsorbed element: w "ID"\n", e, w)) ;
143.141 + ASSERT (nv > 0 && pe >= 0) ;
143.142 + p = pe ;
143.143 + AMD_DEBUG3 ((" : ")) ;
143.144 + ASSERT (pe + len <= pfree) ;
143.145 + for (k = 0 ; k < len ; k++)
143.146 + {
143.147 + j = Iw [p] ;
143.148 + AMD_DEBUG3 ((" "ID"", j)) ;
143.149 + ASSERT (j >= 0 && j < n) ;
143.150 + p++ ;
143.151 + }
143.152 + AMD_DEBUG3 (("\n")) ;
143.153 + }
143.154 + }
143.155 + }
143.156 +
143.157 + /* this routine cannot be called when the hash buckets are non-empty */
143.158 + AMD_DEBUG3 (("\nDegree lists:\n")) ;
143.159 + if (nel >= 0)
143.160 + {
143.161 + cnt = 0 ;
143.162 + for (deg = 0 ; deg < n ; deg++)
143.163 + {
143.164 + if (Head [deg] == EMPTY) continue ;
143.165 + ilast = EMPTY ;
143.166 + AMD_DEBUG3 ((ID": \n", deg)) ;
143.167 + for (i = Head [deg] ; i != EMPTY ; i = Next [i])
143.168 + {
143.169 + AMD_DEBUG3 ((" "ID" : next "ID" last "ID" deg "ID"\n",
143.170 + i, Next [i], Last [i], Degree [i])) ;
143.171 + ASSERT (i >= 0 && i < n && ilast == Last [i] &&
143.172 + deg == Degree [i]) ;
143.173 + cnt += Nv [i] ;
143.174 + ilast = i ;
143.175 + }
143.176 + AMD_DEBUG3 (("\n")) ;
143.177 + }
143.178 + ASSERT (cnt == n - nel) ;
143.179 + }
143.180 +
143.181 +}
143.182 +
143.183 +#endif
144.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
144.2 +++ b/src/amd/amd_info.c Mon Dec 06 13:09:21 2010 +0100
144.3 @@ -0,0 +1,120 @@
144.4 +/* ========================================================================= */
144.5 +/* === AMD_info ============================================================ */
144.6 +/* ========================================================================= */
144.7 +
144.8 +/* ------------------------------------------------------------------------- */
144.9 +/* AMD, Copyright (c) Timothy A. Davis, */
144.10 +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
144.11 +/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
144.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd */
144.13 +/* ------------------------------------------------------------------------- */
144.14 +
144.15 +/* User-callable. Prints the output statistics for AMD. See amd.h
144.16 + * for details. If the Info array is not present, nothing is printed.
144.17 + */
144.18 +
144.19 +#include "amd_internal.h"
144.20 +
144.21 +#define PRI(format,x) { if (x >= 0) { PRINTF ((format, x)) ; }}
144.22 +
144.23 +GLOBAL void AMD_info
144.24 +(
144.25 + double Info [ ]
144.26 +)
144.27 +{
144.28 + double n, ndiv, nmultsubs_ldl, nmultsubs_lu, lnz, lnzd ;
144.29 +
144.30 + PRINTF (("\nAMD version %d.%d.%d, %s, results:\n",
144.31 + AMD_MAIN_VERSION, AMD_SUB_VERSION, AMD_SUBSUB_VERSION, AMD_DATE)) ;
144.32 +
144.33 + if (!Info)
144.34 + {
144.35 + return ;
144.36 + }
144.37 +
144.38 + n = Info [AMD_N] ;
144.39 + ndiv = Info [AMD_NDIV] ;
144.40 + nmultsubs_ldl = Info [AMD_NMULTSUBS_LDL] ;
144.41 + nmultsubs_lu = Info [AMD_NMULTSUBS_LU] ;
144.42 + lnz = Info [AMD_LNZ] ;
144.43 + lnzd = (n >= 0 && lnz >= 0) ? (n + lnz) : (-1) ;
144.44 +
144.45 + /* AMD return status */
144.46 + PRINTF ((" status: ")) ;
144.47 + if (Info [AMD_STATUS] == AMD_OK)
144.48 + {
144.49 + PRINTF (("OK\n")) ;
144.50 + }
144.51 + else if (Info [AMD_STATUS] == AMD_OUT_OF_MEMORY)
144.52 + {
144.53 + PRINTF (("out of memory\n")) ;
144.54 + }
144.55 + else if (Info [AMD_STATUS] == AMD_INVALID)
144.56 + {
144.57 + PRINTF (("invalid matrix\n")) ;
144.58 + }
144.59 + else if (Info [AMD_STATUS] == AMD_OK_BUT_JUMBLED)
144.60 + {
144.61 + PRINTF (("OK, but jumbled\n")) ;
144.62 + }
144.63 + else
144.64 + {
144.65 + PRINTF (("unknown\n")) ;
144.66 + }
144.67 +
144.68 + /* statistics about the input matrix */
144.69 + PRI (" n, dimension of A: %.20g\n", n);
144.70 + PRI (" nz, number of nonzeros in A: %.20g\n",
144.71 + Info [AMD_NZ]) ;
144.72 + PRI (" symmetry of A: %.4f\n",
144.73 + Info [AMD_SYMMETRY]) ;
144.74 + PRI (" number of nonzeros on diagonal: %.20g\n",
144.75 + Info [AMD_NZDIAG]) ;
144.76 + PRI (" nonzeros in pattern of A+A' (excl. diagonal): %.20g\n",
144.77 + Info [AMD_NZ_A_PLUS_AT]) ;
144.78 + PRI (" # dense rows/columns of A+A': %.20g\n",
144.79 + Info [AMD_NDENSE]) ;
144.80 +
144.81 + /* statistics about AMD's behavior */
144.82 + PRI (" memory used, in bytes: %.20g\n",
144.83 + Info [AMD_MEMORY]) ;
144.84 + PRI (" # of memory compactions: %.20g\n",
144.85 + Info [AMD_NCMPA]) ;
144.86 +
144.87 + /* statistics about the ordering quality */
144.88 + PRINTF (("\n"
144.89 + " The following approximate statistics are for a subsequent\n"
144.90 + " factorization of A(P,P) + A(P,P)'. They are slight upper\n"
144.91 + " bounds if there are no dense rows/columns in A+A', and become\n"
144.92 + " looser if dense rows/columns exist.\n\n")) ;
144.93 +
144.94 + PRI (" nonzeros in L (excluding diagonal): %.20g\n",
144.95 + lnz) ;
144.96 + PRI (" nonzeros in L (including diagonal): %.20g\n",
144.97 + lnzd) ;
144.98 + PRI (" # divide operations for LDL' or LU: %.20g\n",
144.99 + ndiv) ;
144.100 + PRI (" # multiply-subtract operations for LDL': %.20g\n",
144.101 + nmultsubs_ldl) ;
144.102 + PRI (" # multiply-subtract operations for LU: %.20g\n",
144.103 + nmultsubs_lu) ;
144.104 + PRI (" max nz. in any column of L (incl. diagonal): %.20g\n",
144.105 + Info [AMD_DMAX]) ;
144.106 +
144.107 + /* total flop counts for various factorizations */
144.108 +
144.109 + if (n >= 0 && ndiv >= 0 && nmultsubs_ldl >= 0 && nmultsubs_lu >= 0)
144.110 + {
144.111 + PRINTF (("\n"
144.112 + " chol flop count for real A, sqrt counted as 1 flop: %.20g\n"
144.113 + " LDL' flop count for real A: %.20g\n"
144.114 + " LDL' flop count for complex A: %.20g\n"
144.115 + " LU flop count for real A (with no pivoting): %.20g\n"
144.116 + " LU flop count for complex A (with no pivoting): %.20g\n\n",
144.117 + n + ndiv + 2*nmultsubs_ldl,
144.118 + ndiv + 2*nmultsubs_ldl,
144.119 + 9*ndiv + 8*nmultsubs_ldl,
144.120 + ndiv + 2*nmultsubs_lu,
144.121 + 9*ndiv + 8*nmultsubs_lu)) ;
144.122 + }
144.123 +}
145.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
145.2 +++ b/src/amd/amd_internal.h Mon Dec 06 13:09:21 2010 +0100
145.3 @@ -0,0 +1,113 @@
145.4 +/* amd_internal.h */
145.5 +
145.6 +/* Written by Andrew Makhorin <mao@gnu.org>. */
145.7 +
145.8 +#ifndef AMD_INTERNAL_H
145.9 +#define AMD_INTERNAL_H
145.10 +
145.11 +/* AMD will be exceedingly slow when running in debug mode. */
145.12 +#if 1
145.13 +#define NDEBUG
145.14 +#endif
145.15 +
145.16 +#include "amd.h"
145.17 +#define _GLPSTD_STDIO
145.18 +#include "glpenv.h"
145.19 +
145.20 +#define Int int
145.21 +#define ID "%d"
145.22 +#define Int_MAX INT_MAX
145.23 +
145.24 +#define SIZE_T_MAX ((size_t)(-1))
145.25 +
145.26 +#define EMPTY (-1)
145.27 +#define FLIP(i) (-(i)-2)
145.28 +#define UNFLIP(i) ((i < EMPTY) ? FLIP (i) : (i))
145.29 +
145.30 +#define MAX(a,b) (((a) > (b)) ? (a) : (b))
145.31 +#define MIN(a,b) (((a) < (b)) ? (a) : (b))
145.32 +
145.33 +#define IMPLIES(p, q) (!(p) || (q))
145.34 +
145.35 +#define GLOBAL
145.36 +
145.37 +#define AMD_order amd_order
145.38 +#define AMD_defaults amd_defaults
145.39 +#define AMD_control amd_control
145.40 +#define AMD_info amd_info
145.41 +#define AMD_1 amd_1
145.42 +#define AMD_2 amd_2
145.43 +#define AMD_valid amd_valid
145.44 +#define AMD_aat amd_aat
145.45 +#define AMD_postorder amd_postorder
145.46 +#define AMD_post_tree amd_post_tree
145.47 +#define AMD_dump amd_dump
145.48 +#define AMD_debug amd_debug
145.49 +#define AMD_debug_init amd_debug_init
145.50 +#define AMD_preprocess amd_preprocess
145.51 +
145.52 +#define amd_malloc xmalloc
145.53 +#if 0 /* 24/V-2009 */
145.54 +#define amd_free xfree
145.55 +#else
145.56 +#define amd_free(ptr) { if ((ptr) != NULL) xfree(ptr); }
145.57 +#endif
145.58 +#define amd_printf xprintf
145.59 +
145.60 +#define PRINTF(params) { amd_printf params; }
145.61 +
145.62 +#ifndef NDEBUG
145.63 +#define ASSERT(expr) xassert(expr)
145.64 +#define AMD_DEBUG0(params) { PRINTF(params); }
145.65 +#define AMD_DEBUG1(params) { if (AMD_debug >= 1) PRINTF(params); }
145.66 +#define AMD_DEBUG2(params) { if (AMD_debug >= 2) PRINTF(params); }
145.67 +#define AMD_DEBUG3(params) { if (AMD_debug >= 3) PRINTF(params); }
145.68 +#define AMD_DEBUG4(params) { if (AMD_debug >= 4) PRINTF(params); }
145.69 +#else
145.70 +#define ASSERT(expression)
145.71 +#define AMD_DEBUG0(params)
145.72 +#define AMD_DEBUG1(params)
145.73 +#define AMD_DEBUG2(params)
145.74 +#define AMD_DEBUG3(params)
145.75 +#define AMD_DEBUG4(params)
145.76 +#endif
145.77 +
145.78 +#define amd_aat _glp_amd_aat
145.79 +size_t AMD_aat(Int n, const Int Ap[], const Int Ai[], Int Len[],
145.80 + Int Tp[], double Info[]);
145.81 +
145.82 +#define amd_1 _glp_amd_1
145.83 +void AMD_1(Int n, const Int Ap[], const Int Ai[], Int P[], Int Pinv[],
145.84 + Int Len[], Int slen, Int S[], double Control[], double Info[]);
145.85 +
145.86 +#define amd_postorder _glp_amd_postorder
145.87 +void AMD_postorder(Int nn, Int Parent[], Int Npiv[], Int Fsize[],
145.88 + Int Order[], Int Child[], Int Sibling[], Int Stack[]);
145.89 +
145.90 +#define amd_post_tree _glp_amd_post_tree
145.91 +#ifndef NDEBUG
145.92 +Int AMD_post_tree(Int root, Int k, Int Child[], const Int Sibling[],
145.93 + Int Order[], Int Stack[], Int nn);
145.94 +#else
145.95 +Int AMD_post_tree(Int root, Int k, Int Child[], const Int Sibling[],
145.96 + Int Order[], Int Stack[]);
145.97 +#endif
145.98 +
145.99 +#define amd_preprocess _glp_amd_preprocess
145.100 +void AMD_preprocess(Int n, const Int Ap[], const Int Ai[], Int Rp[],
145.101 + Int Ri[], Int W[], Int Flag[]);
145.102 +
145.103 +#define amd_debug _glp_amd_debug
145.104 +extern Int AMD_debug;
145.105 +
145.106 +#define amd_debug_init _glp_amd_debug_init
145.107 +void AMD_debug_init(char *s);
145.108 +
145.109 +#define amd_dump _glp_amd_dump
145.110 +void AMD_dump(Int n, Int Pe[], Int Iw[], Int Len[], Int iwlen,
145.111 + Int pfree, Int Nv[], Int Next[], Int Last[], Int Head[],
145.112 + Int Elen[], Int Degree[], Int W[], Int nel);
145.113 +
145.114 +#endif
145.115 +
145.116 +/* eof */
146.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
146.2 +++ b/src/amd/amd_order.c Mon Dec 06 13:09:21 2010 +0100
146.3 @@ -0,0 +1,200 @@
146.4 +/* ========================================================================= */
146.5 +/* === AMD_order =========================================================== */
146.6 +/* ========================================================================= */
146.7 +
146.8 +/* ------------------------------------------------------------------------- */
146.9 +/* AMD, Copyright (c) Timothy A. Davis, */
146.10 +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
146.11 +/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
146.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd */
146.13 +/* ------------------------------------------------------------------------- */
146.14 +
146.15 +/* User-callable AMD minimum degree ordering routine. See amd.h for
146.16 + * documentation.
146.17 + */
146.18 +
146.19 +#include "amd_internal.h"
146.20 +
146.21 +/* ========================================================================= */
146.22 +/* === AMD_order =========================================================== */
146.23 +/* ========================================================================= */
146.24 +
146.25 +GLOBAL Int AMD_order
146.26 +(
146.27 + Int n,
146.28 + const Int Ap [ ],
146.29 + const Int Ai [ ],
146.30 + Int P [ ],
146.31 + double Control [ ],
146.32 + double Info [ ]
146.33 +)
146.34 +{
146.35 + Int *Len, *S, nz, i, *Pinv, info, status, *Rp, *Ri, *Cp, *Ci, ok ;
146.36 + size_t nzaat, slen ;
146.37 + double mem = 0 ;
146.38 +
146.39 +#ifndef NDEBUG
146.40 + AMD_debug_init ("amd") ;
146.41 +#endif
146.42 +
146.43 + /* clear the Info array, if it exists */
146.44 + info = Info != (double *) NULL ;
146.45 + if (info)
146.46 + {
146.47 + for (i = 0 ; i < AMD_INFO ; i++)
146.48 + {
146.49 + Info [i] = EMPTY ;
146.50 + }
146.51 + Info [AMD_N] = n ;
146.52 + Info [AMD_STATUS] = AMD_OK ;
146.53 + }
146.54 +
146.55 + /* make sure inputs exist and n is >= 0 */
146.56 + if (Ai == (Int *) NULL || Ap == (Int *) NULL || P == (Int *) NULL || n < 0)
146.57 + {
146.58 + if (info) Info [AMD_STATUS] = AMD_INVALID ;
146.59 + return (AMD_INVALID) ; /* arguments are invalid */
146.60 + }
146.61 +
146.62 + if (n == 0)
146.63 + {
146.64 + return (AMD_OK) ; /* n is 0 so there's nothing to do */
146.65 + }
146.66 +
146.67 + nz = Ap [n] ;
146.68 + if (info)
146.69 + {
146.70 + Info [AMD_NZ] = nz ;
146.71 + }
146.72 + if (nz < 0)
146.73 + {
146.74 + if (info) Info [AMD_STATUS] = AMD_INVALID ;
146.75 + return (AMD_INVALID) ;
146.76 + }
146.77 +
146.78 + /* check if n or nz will cause size_t overflow */
146.79 + if (((size_t) n) >= SIZE_T_MAX / sizeof (Int)
146.80 + || ((size_t) nz) >= SIZE_T_MAX / sizeof (Int))
146.81 + {
146.82 + if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
146.83 + return (AMD_OUT_OF_MEMORY) ; /* problem too large */
146.84 + }
146.85 +
146.86 + /* check the input matrix: AMD_OK, AMD_INVALID, or AMD_OK_BUT_JUMBLED */
146.87 + status = AMD_valid (n, n, Ap, Ai) ;
146.88 +
146.89 + if (status == AMD_INVALID)
146.90 + {
146.91 + if (info) Info [AMD_STATUS] = AMD_INVALID ;
146.92 + return (AMD_INVALID) ; /* matrix is invalid */
146.93 + }
146.94 +
146.95 + /* allocate two size-n integer workspaces */
146.96 + Len = amd_malloc (n * sizeof (Int)) ;
146.97 + Pinv = amd_malloc (n * sizeof (Int)) ;
146.98 + mem += n ;
146.99 + mem += n ;
146.100 + if (!Len || !Pinv)
146.101 + {
146.102 + /* :: out of memory :: */
146.103 + amd_free (Len) ;
146.104 + amd_free (Pinv) ;
146.105 + if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
146.106 + return (AMD_OUT_OF_MEMORY) ;
146.107 + }
146.108 +
146.109 + if (status == AMD_OK_BUT_JUMBLED)
146.110 + {
146.111 + /* sort the input matrix and remove duplicate entries */
146.112 + AMD_DEBUG1 (("Matrix is jumbled\n")) ;
146.113 + Rp = amd_malloc ((n+1) * sizeof (Int)) ;
146.114 + Ri = amd_malloc (MAX (nz,1) * sizeof (Int)) ;
146.115 + mem += (n+1) ;
146.116 + mem += MAX (nz,1) ;
146.117 + if (!Rp || !Ri)
146.118 + {
146.119 + /* :: out of memory :: */
146.120 + amd_free (Rp) ;
146.121 + amd_free (Ri) ;
146.122 + amd_free (Len) ;
146.123 + amd_free (Pinv) ;
146.124 + if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
146.125 + return (AMD_OUT_OF_MEMORY) ;
146.126 + }
146.127 + /* use Len and Pinv as workspace to create R = A' */
146.128 + AMD_preprocess (n, Ap, Ai, Rp, Ri, Len, Pinv) ;
146.129 + Cp = Rp ;
146.130 + Ci = Ri ;
146.131 + }
146.132 + else
146.133 + {
146.134 + /* order the input matrix as-is. No need to compute R = A' first */
146.135 + Rp = NULL ;
146.136 + Ri = NULL ;
146.137 + Cp = (Int *) Ap ;
146.138 + Ci = (Int *) Ai ;
146.139 + }
146.140 +
146.141 + /* --------------------------------------------------------------------- */
146.142 + /* determine the symmetry and count off-diagonal nonzeros in A+A' */
146.143 + /* --------------------------------------------------------------------- */
146.144 +
146.145 + nzaat = AMD_aat (n, Cp, Ci, Len, P, Info) ;
146.146 + AMD_DEBUG1 (("nzaat: %g\n", (double) nzaat)) ;
146.147 + ASSERT ((MAX (nz-n, 0) <= nzaat) && (nzaat <= 2 * (size_t) nz)) ;
146.148 +
146.149 + /* --------------------------------------------------------------------- */
146.150 + /* allocate workspace for matrix, elbow room, and 6 size-n vectors */
146.151 + /* --------------------------------------------------------------------- */
146.152 +
146.153 + S = NULL ;
146.154 + slen = nzaat ; /* space for matrix */
146.155 + ok = ((slen + nzaat/5) >= slen) ; /* check for size_t overflow */
146.156 + slen += nzaat/5 ; /* add elbow room */
146.157 + for (i = 0 ; ok && i < 7 ; i++)
146.158 + {
146.159 + ok = ((slen + n) > slen) ; /* check for size_t overflow */
146.160 + slen += n ; /* size-n elbow room, 6 size-n work */
146.161 + }
146.162 + mem += slen ;
146.163 + ok = ok && (slen < SIZE_T_MAX / sizeof (Int)) ; /* check for overflow */
146.164 + ok = ok && (slen < Int_MAX) ; /* S[i] for Int i must be OK */
146.165 + if (ok)
146.166 + {
146.167 + S = amd_malloc (slen * sizeof (Int)) ;
146.168 + }
146.169 + AMD_DEBUG1 (("slen %g\n", (double) slen)) ;
146.170 + if (!S)
146.171 + {
146.172 + /* :: out of memory :: (or problem too large) */
146.173 + amd_free (Rp) ;
146.174 + amd_free (Ri) ;
146.175 + amd_free (Len) ;
146.176 + amd_free (Pinv) ;
146.177 + if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
146.178 + return (AMD_OUT_OF_MEMORY) ;
146.179 + }
146.180 + if (info)
146.181 + {
146.182 + /* memory usage, in bytes. */
146.183 + Info [AMD_MEMORY] = mem * sizeof (Int) ;
146.184 + }
146.185 +
146.186 + /* --------------------------------------------------------------------- */
146.187 + /* order the matrix */
146.188 + /* --------------------------------------------------------------------- */
146.189 +
146.190 + AMD_1 (n, Cp, Ci, P, Pinv, Len, slen, S, Control, Info) ;
146.191 +
146.192 + /* --------------------------------------------------------------------- */
146.193 + /* free the workspace */
146.194 + /* --------------------------------------------------------------------- */
146.195 +
146.196 + amd_free (Rp) ;
146.197 + amd_free (Ri) ;
146.198 + amd_free (Len) ;
146.199 + amd_free (Pinv) ;
146.200 + amd_free (S) ;
146.201 + if (info) Info [AMD_STATUS] = status ;
146.202 + return (status) ; /* successful ordering */
146.203 +}
147.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
147.2 +++ b/src/amd/amd_post_tree.c Mon Dec 06 13:09:21 2010 +0100
147.3 @@ -0,0 +1,121 @@
147.4 +/* ========================================================================= */
147.5 +/* === AMD_post_tree ======================================================= */
147.6 +/* ========================================================================= */
147.7 +
147.8 +/* ------------------------------------------------------------------------- */
147.9 +/* AMD, Copyright (c) Timothy A. Davis, */
147.10 +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
147.11 +/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
147.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd */
147.13 +/* ------------------------------------------------------------------------- */
147.14 +
147.15 +/* Post-ordering of a supernodal elimination tree. */
147.16 +
147.17 +#include "amd_internal.h"
147.18 +
147.19 +GLOBAL Int AMD_post_tree
147.20 +(
147.21 + Int root, /* root of the tree */
147.22 + Int k, /* start numbering at k */
147.23 + Int Child [ ], /* input argument of size nn, undefined on
147.24 + * output. Child [i] is the head of a link
147.25 + * list of all nodes that are children of node
147.26 + * i in the tree. */
147.27 + const Int Sibling [ ], /* input argument of size nn, not modified.
147.28 + * If f is a node in the link list of the
147.29 + * children of node i, then Sibling [f] is the
147.30 + * next child of node i.
147.31 + */
147.32 + Int Order [ ], /* output order, of size nn. Order [i] = k
147.33 + * if node i is the kth node of the reordered
147.34 + * tree. */
147.35 + Int Stack [ ] /* workspace of size nn */
147.36 +#ifndef NDEBUG
147.37 + , Int nn /* nodes are in the range 0..nn-1. */
147.38 +#endif
147.39 +)
147.40 +{
147.41 + Int f, head, h, i ;
147.42 +
147.43 +#if 0
147.44 + /* --------------------------------------------------------------------- */
147.45 + /* recursive version (Stack [ ] is not used): */
147.46 + /* --------------------------------------------------------------------- */
147.47 +
147.48 + /* this is simple, but can caouse stack overflow if nn is large */
147.49 + i = root ;
147.50 + for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
147.51 + {
147.52 + k = AMD_post_tree (f, k, Child, Sibling, Order, Stack, nn) ;
147.53 + }
147.54 + Order [i] = k++ ;
147.55 + return (k) ;
147.56 +#endif
147.57 +
147.58 + /* --------------------------------------------------------------------- */
147.59 + /* non-recursive version, using an explicit stack */
147.60 + /* --------------------------------------------------------------------- */
147.61 +
147.62 + /* push root on the stack */
147.63 + head = 0 ;
147.64 + Stack [0] = root ;
147.65 +
147.66 + while (head >= 0)
147.67 + {
147.68 + /* get head of stack */
147.69 + ASSERT (head < nn) ;
147.70 + i = Stack [head] ;
147.71 + AMD_DEBUG1 (("head of stack "ID" \n", i)) ;
147.72 + ASSERT (i >= 0 && i < nn) ;
147.73 +
147.74 + if (Child [i] != EMPTY)
147.75 + {
147.76 + /* the children of i are not yet ordered */
147.77 + /* push each child onto the stack in reverse order */
147.78 + /* so that small ones at the head of the list get popped first */
147.79 + /* and the biggest one at the end of the list gets popped last */
147.80 + for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
147.81 + {
147.82 + head++ ;
147.83 + ASSERT (head < nn) ;
147.84 + ASSERT (f >= 0 && f < nn) ;
147.85 + }
147.86 + h = head ;
147.87 + ASSERT (head < nn) ;
147.88 + for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
147.89 + {
147.90 + ASSERT (h > 0) ;
147.91 + Stack [h--] = f ;
147.92 + AMD_DEBUG1 (("push "ID" on stack\n", f)) ;
147.93 + ASSERT (f >= 0 && f < nn) ;
147.94 + }
147.95 + ASSERT (Stack [h] == i) ;
147.96 +
147.97 + /* delete child list so that i gets ordered next time we see it */
147.98 + Child [i] = EMPTY ;
147.99 + }
147.100 + else
147.101 + {
147.102 + /* the children of i (if there were any) are already ordered */
147.103 + /* remove i from the stack and order it. Front i is kth front */
147.104 + head-- ;
147.105 + AMD_DEBUG1 (("pop "ID" order "ID"\n", i, k)) ;
147.106 + Order [i] = k++ ;
147.107 + ASSERT (k <= nn) ;
147.108 + }
147.109 +
147.110 +#ifndef NDEBUG
147.111 + AMD_DEBUG1 (("\nStack:")) ;
147.112 + for (h = head ; h >= 0 ; h--)
147.113 + {
147.114 + Int j = Stack [h] ;
147.115 + AMD_DEBUG1 ((" "ID, j)) ;
147.116 + ASSERT (j >= 0 && j < nn) ;
147.117 + }
147.118 + AMD_DEBUG1 (("\n\n")) ;
147.119 + ASSERT (head < nn) ;
147.120 +#endif
147.121 +
147.122 + }
147.123 + return (k) ;
147.124 +}
148.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
148.2 +++ b/src/amd/amd_postorder.c Mon Dec 06 13:09:21 2010 +0100
148.3 @@ -0,0 +1,207 @@
148.4 +/* ========================================================================= */
148.5 +/* === AMD_postorder ======================================================= */
148.6 +/* ========================================================================= */
148.7 +
148.8 +/* ------------------------------------------------------------------------- */
148.9 +/* AMD, Copyright (c) Timothy A. Davis, */
148.10 +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
148.11 +/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
148.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd */
148.13 +/* ------------------------------------------------------------------------- */
148.14 +
148.15 +/* Perform a postordering (via depth-first search) of an assembly tree. */
148.16 +
148.17 +#include "amd_internal.h"
148.18 +
148.19 +GLOBAL void AMD_postorder
148.20 +(
148.21 + /* inputs, not modified on output: */
148.22 + Int nn, /* nodes are in the range 0..nn-1 */
148.23 + Int Parent [ ], /* Parent [j] is the parent of j, or EMPTY if root */
148.24 + Int Nv [ ], /* Nv [j] > 0 number of pivots represented by node j,
148.25 + * or zero if j is not a node. */
148.26 + Int Fsize [ ], /* Fsize [j]: size of node j */
148.27 +
148.28 + /* output, not defined on input: */
148.29 + Int Order [ ], /* output post-order */
148.30 +
148.31 + /* workspaces of size nn: */
148.32 + Int Child [ ],
148.33 + Int Sibling [ ],
148.34 + Int Stack [ ]
148.35 +)
148.36 +{
148.37 + Int i, j, k, parent, frsize, f, fprev, maxfrsize, bigfprev, bigf, fnext ;
148.38 +
148.39 + for (j = 0 ; j < nn ; j++)
148.40 + {
148.41 + Child [j] = EMPTY ;
148.42 + Sibling [j] = EMPTY ;
148.43 + }
148.44 +
148.45 + /* --------------------------------------------------------------------- */
148.46 + /* place the children in link lists - bigger elements tend to be last */
148.47 + /* --------------------------------------------------------------------- */
148.48 +
148.49 + for (j = nn-1 ; j >= 0 ; j--)
148.50 + {
148.51 + if (Nv [j] > 0)
148.52 + {
148.53 + /* this is an element */
148.54 + parent = Parent [j] ;
148.55 + if (parent != EMPTY)
148.56 + {
148.57 + /* place the element in link list of the children its parent */
148.58 + /* bigger elements will tend to be at the end of the list */
148.59 + Sibling [j] = Child [parent] ;
148.60 + Child [parent] = j ;
148.61 + }
148.62 + }
148.63 + }
148.64 +
148.65 +#ifndef NDEBUG
148.66 + {
148.67 + Int nels, ff, nchild ;
148.68 + AMD_DEBUG1 (("\n\n================================ AMD_postorder:\n"));
148.69 + nels = 0 ;
148.70 + for (j = 0 ; j < nn ; j++)
148.71 + {
148.72 + if (Nv [j] > 0)
148.73 + {
148.74 + AMD_DEBUG1 (( ""ID" : nels "ID" npiv "ID" size "ID
148.75 + " parent "ID" maxfr "ID"\n", j, nels,
148.76 + Nv [j], Fsize [j], Parent [j], Fsize [j])) ;
148.77 + /* this is an element */
148.78 + /* dump the link list of children */
148.79 + nchild = 0 ;
148.80 + AMD_DEBUG1 ((" Children: ")) ;
148.81 + for (ff = Child [j] ; ff != EMPTY ; ff = Sibling [ff])
148.82 + {
148.83 + AMD_DEBUG1 ((ID" ", ff)) ;
148.84 + ASSERT (Parent [ff] == j) ;
148.85 + nchild++ ;
148.86 + ASSERT (nchild < nn) ;
148.87 + }
148.88 + AMD_DEBUG1 (("\n")) ;
148.89 + parent = Parent [j] ;
148.90 + if (parent != EMPTY)
148.91 + {
148.92 + ASSERT (Nv [parent] > 0) ;
148.93 + }
148.94 + nels++ ;
148.95 + }
148.96 + }
148.97 + }
148.98 + AMD_DEBUG1 (("\n\nGo through the children of each node, and put\n"
148.99 + "the biggest child last in each list:\n")) ;
148.100 +#endif
148.101 +
148.102 + /* --------------------------------------------------------------------- */
148.103 + /* place the largest child last in the list of children for each node */
148.104 + /* --------------------------------------------------------------------- */
148.105 +
148.106 + for (i = 0 ; i < nn ; i++)
148.107 + {
148.108 + if (Nv [i] > 0 && Child [i] != EMPTY)
148.109 + {
148.110 +
148.111 +#ifndef NDEBUG
148.112 + Int nchild ;
148.113 + AMD_DEBUG1 (("Before partial sort, element "ID"\n", i)) ;
148.114 + nchild = 0 ;
148.115 + for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
148.116 + {
148.117 + ASSERT (f >= 0 && f < nn) ;
148.118 + AMD_DEBUG1 ((" f: "ID" size: "ID"\n", f, Fsize [f])) ;
148.119 + nchild++ ;
148.120 + ASSERT (nchild <= nn) ;
148.121 + }
148.122 +#endif
148.123 +
148.124 + /* find the biggest element in the child list */
148.125 + fprev = EMPTY ;
148.126 + maxfrsize = EMPTY ;
148.127 + bigfprev = EMPTY ;
148.128 + bigf = EMPTY ;
148.129 + for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
148.130 + {
148.131 + ASSERT (f >= 0 && f < nn) ;
148.132 + frsize = Fsize [f] ;
148.133 + if (frsize >= maxfrsize)
148.134 + {
148.135 + /* this is the biggest seen so far */
148.136 + maxfrsize = frsize ;
148.137 + bigfprev = fprev ;
148.138 + bigf = f ;
148.139 + }
148.140 + fprev = f ;
148.141 + }
148.142 + ASSERT (bigf != EMPTY) ;
148.143 +
148.144 + fnext = Sibling [bigf] ;
148.145 +
148.146 + AMD_DEBUG1 (("bigf "ID" maxfrsize "ID" bigfprev "ID" fnext "ID
148.147 + " fprev " ID"\n", bigf, maxfrsize, bigfprev, fnext, fprev)) ;
148.148 +
148.149 + if (fnext != EMPTY)
148.150 + {
148.151 + /* if fnext is EMPTY then bigf is already at the end of list */
148.152 +
148.153 + if (bigfprev == EMPTY)
148.154 + {
148.155 + /* delete bigf from the element of the list */
148.156 + Child [i] = fnext ;
148.157 + }
148.158 + else
148.159 + {
148.160 + /* delete bigf from the middle of the list */
148.161 + Sibling [bigfprev] = fnext ;
148.162 + }
148.163 +
148.164 + /* put bigf at the end of the list */
148.165 + Sibling [bigf] = EMPTY ;
148.166 + ASSERT (Child [i] != EMPTY) ;
148.167 + ASSERT (fprev != bigf) ;
148.168 + ASSERT (fprev != EMPTY) ;
148.169 + Sibling [fprev] = bigf ;
148.170 + }
148.171 +
148.172 +#ifndef NDEBUG
148.173 + AMD_DEBUG1 (("After partial sort, element "ID"\n", i)) ;
148.174 + for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
148.175 + {
148.176 + ASSERT (f >= 0 && f < nn) ;
148.177 + AMD_DEBUG1 ((" "ID" "ID"\n", f, Fsize [f])) ;
148.178 + ASSERT (Nv [f] > 0) ;
148.179 + nchild-- ;
148.180 + }
148.181 + ASSERT (nchild == 0) ;
148.182 +#endif
148.183 +
148.184 + }
148.185 + }
148.186 +
148.187 + /* --------------------------------------------------------------------- */
148.188 + /* postorder the assembly tree */
148.189 + /* --------------------------------------------------------------------- */
148.190 +
148.191 + for (i = 0 ; i < nn ; i++)
148.192 + {
148.193 + Order [i] = EMPTY ;
148.194 + }
148.195 +
148.196 + k = 0 ;
148.197 +
148.198 + for (i = 0 ; i < nn ; i++)
148.199 + {
148.200 + if (Parent [i] == EMPTY && Nv [i] > 0)
148.201 + {
148.202 + AMD_DEBUG1 (("Root of assembly tree "ID"\n", i)) ;
148.203 + k = AMD_post_tree (i, k, Child, Sibling, Order, Stack
148.204 +#ifndef NDEBUG
148.205 + , nn
148.206 +#endif
148.207 + ) ;
148.208 + }
148.209 + }
148.210 +}
149.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
149.2 +++ b/src/amd/amd_preprocess.c Mon Dec 06 13:09:21 2010 +0100
149.3 @@ -0,0 +1,119 @@
149.4 +/* ========================================================================= */
149.5 +/* === AMD_preprocess ====================================================== */
149.6 +/* ========================================================================= */
149.7 +
149.8 +/* ------------------------------------------------------------------------- */
149.9 +/* AMD, Copyright (c) Timothy A. Davis, */
149.10 +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
149.11 +/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
149.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd */
149.13 +/* ------------------------------------------------------------------------- */
149.14 +
149.15 +/* Sorts, removes duplicate entries, and transposes from the nonzero pattern of
149.16 + * a column-form matrix A, to obtain the matrix R. The input matrix can have
149.17 + * duplicate entries and/or unsorted columns (AMD_valid (n,Ap,Ai) must not be
149.18 + * AMD_INVALID).
149.19 + *
149.20 + * This input condition is NOT checked. This routine is not user-callable.
149.21 + */
149.22 +
149.23 +#include "amd_internal.h"
149.24 +
149.25 +/* ========================================================================= */
149.26 +/* === AMD_preprocess ====================================================== */
149.27 +/* ========================================================================= */
149.28 +
149.29 +/* AMD_preprocess does not check its input for errors or allocate workspace.
149.30 + * On input, the condition (AMD_valid (n,n,Ap,Ai) != AMD_INVALID) must hold.
149.31 + */
149.32 +
149.33 +GLOBAL void AMD_preprocess
149.34 +(
149.35 + Int n, /* input matrix: A is n-by-n */
149.36 + const Int Ap [ ], /* size n+1 */
149.37 + const Int Ai [ ], /* size nz = Ap [n] */
149.38 +
149.39 + /* output matrix R: */
149.40 + Int Rp [ ], /* size n+1 */
149.41 + Int Ri [ ], /* size nz (or less, if duplicates present) */
149.42 +
149.43 + Int W [ ], /* workspace of size n */
149.44 + Int Flag [ ] /* workspace of size n */
149.45 +)
149.46 +{
149.47 +
149.48 + /* --------------------------------------------------------------------- */
149.49 + /* local variables */
149.50 + /* --------------------------------------------------------------------- */
149.51 +
149.52 + Int i, j, p, p2 ;
149.53 +
149.54 + ASSERT (AMD_valid (n, n, Ap, Ai) != AMD_INVALID) ;
149.55 +
149.56 + /* --------------------------------------------------------------------- */
149.57 + /* count the entries in each row of A (excluding duplicates) */
149.58 + /* --------------------------------------------------------------------- */
149.59 +
149.60 + for (i = 0 ; i < n ; i++)
149.61 + {
149.62 + W [i] = 0 ; /* # of nonzeros in row i (excl duplicates) */
149.63 + Flag [i] = EMPTY ; /* Flag [i] = j if i appears in column j */
149.64 + }
149.65 + for (j = 0 ; j < n ; j++)
149.66 + {
149.67 + p2 = Ap [j+1] ;
149.68 + for (p = Ap [j] ; p < p2 ; p++)
149.69 + {
149.70 + i = Ai [p] ;
149.71 + if (Flag [i] != j)
149.72 + {
149.73 + /* row index i has not yet appeared in column j */
149.74 + W [i]++ ; /* one more entry in row i */
149.75 + Flag [i] = j ; /* flag row index i as appearing in col j*/
149.76 + }
149.77 + }
149.78 + }
149.79 +
149.80 + /* --------------------------------------------------------------------- */
149.81 + /* compute the row pointers for R */
149.82 + /* --------------------------------------------------------------------- */
149.83 +
149.84 + Rp [0] = 0 ;
149.85 + for (i = 0 ; i < n ; i++)
149.86 + {
149.87 + Rp [i+1] = Rp [i] + W [i] ;
149.88 + }
149.89 + for (i = 0 ; i < n ; i++)
149.90 + {
149.91 + W [i] = Rp [i] ;
149.92 + Flag [i] = EMPTY ;
149.93 + }
149.94 +
149.95 + /* --------------------------------------------------------------------- */
149.96 + /* construct the row form matrix R */
149.97 + /* --------------------------------------------------------------------- */
149.98 +
149.99 + /* R = row form of pattern of A */
149.100 + for (j = 0 ; j < n ; j++)
149.101 + {
149.102 + p2 = Ap [j+1] ;
149.103 + for (p = Ap [j] ; p < p2 ; p++)
149.104 + {
149.105 + i = Ai [p] ;
149.106 + if (Flag [i] != j)
149.107 + {
149.108 + /* row index i has not yet appeared in column j */
149.109 + Ri [W [i]++] = j ; /* put col j in row i */
149.110 + Flag [i] = j ; /* flag row index i as appearing in col j*/
149.111 + }
149.112 + }
149.113 + }
149.114 +
149.115 +#ifndef NDEBUG
149.116 + ASSERT (AMD_valid (n, n, Rp, Ri) == AMD_OK) ;
149.117 + for (j = 0 ; j < n ; j++)
149.118 + {
149.119 + ASSERT (W [j] == Rp [j+1]) ;
149.120 + }
149.121 +#endif
149.122 +}
150.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
150.2 +++ b/src/amd/amd_valid.c Mon Dec 06 13:09:21 2010 +0100
150.3 @@ -0,0 +1,93 @@
150.4 +/* ========================================================================= */
150.5 +/* === AMD_valid =========================================================== */
150.6 +/* ========================================================================= */
150.7 +
150.8 +/* ------------------------------------------------------------------------- */
150.9 +/* AMD, Copyright (c) Timothy A. Davis, */
150.10 +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
150.11 +/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
150.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd */
150.13 +/* ------------------------------------------------------------------------- */
150.14 +
150.15 +/* Check if a column-form matrix is valid or not. The matrix A is
150.16 + * n_row-by-n_col. The row indices of entries in column j are in
150.17 + * Ai [Ap [j] ... Ap [j+1]-1]. Required conditions are:
150.18 + *
150.19 + * n_row >= 0
150.20 + * n_col >= 0
150.21 + * nz = Ap [n_col] >= 0 number of entries in the matrix
150.22 + * Ap [0] == 0
150.23 + * Ap [j] <= Ap [j+1] for all j in the range 0 to n_col.
150.24 + * Ai [0 ... nz-1] must be in the range 0 to n_row-1.
150.25 + *
150.26 + * If any of the above conditions hold, AMD_INVALID is returned. If the
150.27 + * following condition holds, AMD_OK_BUT_JUMBLED is returned (a warning,
150.28 + * not an error):
150.29 + *
150.30 + * row indices in Ai [Ap [j] ... Ap [j+1]-1] are not sorted in ascending
150.31 + * order, and/or duplicate entries exist.
150.32 + *
150.33 + * Otherwise, AMD_OK is returned.
150.34 + *
150.35 + * In v1.2 and earlier, this function returned TRUE if the matrix was valid
150.36 + * (now returns AMD_OK), or FALSE otherwise (now returns AMD_INVALID or
150.37 + * AMD_OK_BUT_JUMBLED).
150.38 + */
150.39 +
150.40 +#include "amd_internal.h"
150.41 +
150.42 +GLOBAL Int AMD_valid
150.43 +(
150.44 + /* inputs, not modified on output: */
150.45 + Int n_row, /* A is n_row-by-n_col */
150.46 + Int n_col,
150.47 + const Int Ap [ ], /* column pointers of A, of size n_col+1 */
150.48 + const Int Ai [ ] /* row indices of A, of size nz = Ap [n_col] */
150.49 +)
150.50 +{
150.51 + Int nz, j, p1, p2, ilast, i, p, result = AMD_OK ;
150.52 +
150.53 + if (n_row < 0 || n_col < 0 || Ap == NULL || Ai == NULL)
150.54 + {
150.55 + return (AMD_INVALID) ;
150.56 + }
150.57 + nz = Ap [n_col] ;
150.58 + if (Ap [0] != 0 || nz < 0)
150.59 + {
150.60 + /* column pointers must start at Ap [0] = 0, and Ap [n] must be >= 0 */
150.61 + AMD_DEBUG0 (("column 0 pointer bad or nz < 0\n")) ;
150.62 + return (AMD_INVALID) ;
150.63 + }
150.64 + for (j = 0 ; j < n_col ; j++)
150.65 + {
150.66 + p1 = Ap [j] ;
150.67 + p2 = Ap [j+1] ;
150.68 + AMD_DEBUG2 (("\nColumn: "ID" p1: "ID" p2: "ID"\n", j, p1, p2)) ;
150.69 + if (p1 > p2)
150.70 + {
150.71 + /* column pointers must be ascending */
150.72 + AMD_DEBUG0 (("column "ID" pointer bad\n", j)) ;
150.73 + return (AMD_INVALID) ;
150.74 + }
150.75 + ilast = EMPTY ;
150.76 + for (p = p1 ; p < p2 ; p++)
150.77 + {
150.78 + i = Ai [p] ;
150.79 + AMD_DEBUG3 (("row: "ID"\n", i)) ;
150.80 + if (i < 0 || i >= n_row)
150.81 + {
150.82 + /* row index out of range */
150.83 + AMD_DEBUG0 (("index out of range, col "ID" row "ID"\n", j, i));
150.84 + return (AMD_INVALID) ;
150.85 + }
150.86 + if (i <= ilast)
150.87 + {
150.88 + /* row index unsorted, or duplicate entry present */
150.89 + AMD_DEBUG1 (("index unsorted/dupl col "ID" row "ID"\n", j, i));
150.90 + result = AMD_OK_BUT_JUMBLED ;
150.91 + }
150.92 + ilast = i ;
150.93 + }
150.94 + }
150.95 + return (result) ;
150.96 +}
151.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
151.2 +++ b/src/colamd/COPYING Mon Dec 06 13:09:21 2010 +0100
151.3 @@ -0,0 +1,502 @@
151.4 + GNU LESSER GENERAL PUBLIC LICENSE
151.5 + Version 2.1, February 1999
151.6 +
151.7 + Copyright (C) 1991, 1999 Free Software Foundation, Inc.
151.8 + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
151.9 + Everyone is permitted to copy and distribute verbatim copies
151.10 + of this license document, but changing it is not allowed.
151.11 +
151.12 +[This is the first released version of the Lesser GPL. It also counts
151.13 + as the successor of the GNU Library Public License, version 2, hence
151.14 + the version number 2.1.]
151.15 +
151.16 + Preamble
151.17 +
151.18 + The licenses for most software are designed to take away your
151.19 +freedom to share and change it. By contrast, the GNU General Public
151.20 +Licenses are intended to guarantee your freedom to share and change
151.21 +free software--to make sure the software is free for all its users.
151.22 +
151.23 + This license, the Lesser General Public License, applies to some
151.24 +specially designated software packages--typically libraries--of the
151.25 +Free Software Foundation and other authors who decide to use it. You
151.26 +can use it too, but we suggest you first think carefully about whether
151.27 +this license or the ordinary General Public License is the better
151.28 +strategy to use in any particular case, based on the explanations below.
151.29 +
151.30 + When we speak of free software, we are referring to freedom of use,
151.31 +not price. Our General Public Licenses are designed to make sure that
151.32 +you have the freedom to distribute copies of free software (and charge
151.33 +for this service if you wish); that you receive source code or can get
151.34 +it if you want it; that you can change the software and use pieces of
151.35 +it in new free programs; and that you are informed that you can do
151.36 +these things.
151.37 +
151.38 + To protect your rights, we need to make restrictions that forbid
151.39 +distributors to deny you these rights or to ask you to surrender these
151.40 +rights. These restrictions translate to certain responsibilities for
151.41 +you if you distribute copies of the library or if you modify it.
151.42 +
151.43 + For example, if you distribute copies of the library, whether gratis
151.44 +or for a fee, you must give the recipients all the rights that we gave
151.45 +you. You must make sure that they, too, receive or can get the source
151.46 +code. If you link other code with the library, you must provide
151.47 +complete object files to the recipients, so that they can relink them
151.48 +with the library after making changes to the library and recompiling
151.49 +it. And you must show them these terms so they know their rights.
151.50 +
151.51 + We protect your rights with a two-step method: (1) we copyright the
151.52 +library, and (2) we offer you this license, which gives you legal
151.53 +permission to copy, distribute and/or modify the library.
151.54 +
151.55 + To protect each distributor, we want to make it very clear that
151.56 +there is no warranty for the free library. Also, if the library is
151.57 +modified by someone else and passed on, the recipients should know
151.58 +that what they have is not the original version, so that the original
151.59 +author's reputation will not be affected by problems that might be
151.60 +introduced by others.
151.61 +
151.62 + Finally, software patents pose a constant threat to the existence of
151.63 +any free program. We wish to make sure that a company cannot
151.64 +effectively restrict the users of a free program by obtaining a
151.65 +restrictive license from a patent holder. Therefore, we insist that
151.66 +any patent license obtained for a version of the library must be
151.67 +consistent with the full freedom of use specified in this license.
151.68 +
151.69 + Most GNU software, including some libraries, is covered by the
151.70 +ordinary GNU General Public License. This license, the GNU Lesser
151.71 +General Public License, applies to certain designated libraries, and
151.72 +is quite different from the ordinary General Public License. We use
151.73 +this license for certain libraries in order to permit linking those
151.74 +libraries into non-free programs.
151.75 +
151.76 + When a program is linked with a library, whether statically or using
151.77 +a shared library, the combination of the two is legally speaking a
151.78 +combined work, a derivative of the original library. The ordinary
151.79 +General Public License therefore permits such linking only if the
151.80 +entire combination fits its criteria of freedom. The Lesser General
151.81 +Public License permits more lax criteria for linking other code with
151.82 +the library.
151.83 +
151.84 + We call this license the "Lesser" General Public License because it
151.85 +does Less to protect the user's freedom than the ordinary General
151.86 +Public License. It also provides other free software developers Less
151.87 +of an advantage over competing non-free programs. These disadvantages
151.88 +are the reason we use the ordinary General Public License for many
151.89 +libraries. However, the Lesser license provides advantages in certain
151.90 +special circumstances.
151.91 +
151.92 + For example, on rare occasions, there may be a special need to
151.93 +encourage the widest possible use of a certain library, so that it becomes
151.94 +a de-facto standard. To achieve this, non-free programs must be
151.95 +allowed to use the library. A more frequent case is that a free
151.96 +library does the same job as widely used non-free libraries. In this
151.97 +case, there is little to gain by limiting the free library to free
151.98 +software only, so we use the Lesser General Public License.
151.99 +
151.100 + In other cases, permission to use a particular library in non-free
151.101 +programs enables a greater number of people to use a large body of
151.102 +free software. For example, permission to use the GNU C Library in
151.103 +non-free programs enables many more people to use the whole GNU
151.104 +operating system, as well as its variant, the GNU/Linux operating
151.105 +system.
151.106 +
151.107 + Although the Lesser General Public License is Less protective of the
151.108 +users' freedom, it does ensure that the user of a program that is
151.109 +linked with the Library has the freedom and the wherewithal to run
151.110 +that program using a modified version of the Library.
151.111 +
151.112 + The precise terms and conditions for copying, distribution and
151.113 +modification follow. Pay close attention to the difference between a
151.114 +"work based on the library" and a "work that uses the library". The
151.115 +former contains code derived from the library, whereas the latter must
151.116 +be combined with the library in order to run.
151.117 +
151.118 + GNU LESSER GENERAL PUBLIC LICENSE
151.119 + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
151.120 +
151.121 + 0. This License Agreement applies to any software library or other
151.122 +program which contains a notice placed by the copyright holder or
151.123 +other authorized party saying it may be distributed under the terms of
151.124 +this Lesser General Public License (also called "this License").
151.125 +Each licensee is addressed as "you".
151.126 +
151.127 + A "library" means a collection of software functions and/or data
151.128 +prepared so as to be conveniently linked with application programs
151.129 +(which use some of those functions and data) to form executables.
151.130 +
151.131 + The "Library", below, refers to any such software library or work
151.132 +which has been distributed under these terms. A "work based on the
151.133 +Library" means either the Library or any derivative work under
151.134 +copyright law: that is to say, a work containing the Library or a
151.135 +portion of it, either verbatim or with modifications and/or translated
151.136 +straightforwardly into another language. (Hereinafter, translation is
151.137 +included without limitation in the term "modification".)
151.138 +
151.139 + "Source code" for a work means the preferred form of the work for
151.140 +making modifications to it. For a library, complete source code means
151.141 +all the source code for all modules it contains, plus any associated
151.142 +interface definition files, plus the scripts used to control compilation
151.143 +and installation of the library.
151.144 +
151.145 + Activities other than copying, distribution and modification are not
151.146 +covered by this License; they are outside its scope. The act of
151.147 +running a program using the Library is not restricted, and output from
151.148 +such a program is covered only if its contents constitute a work based
151.149 +on the Library (independent of the use of the Library in a tool for
151.150 +writing it). Whether that is true depends on what the Library does
151.151 +and what the program that uses the Library does.
151.152 +
151.153 + 1. You may copy and distribute verbatim copies of the Library's
151.154 +complete source code as you receive it, in any medium, provided that
151.155 +you conspicuously and appropriately publish on each copy an
151.156 +appropriate copyright notice and disclaimer of warranty; keep intact
151.157 +all the notices that refer to this License and to the absence of any
151.158 +warranty; and distribute a copy of this License along with the
151.159 +Library.
151.160 +
151.161 + You may charge a fee for the physical act of transferring a copy,
151.162 +and you may at your option offer warranty protection in exchange for a
151.163 +fee.
151.164 +
151.165 + 2. You may modify your copy or copies of the Library or any portion
151.166 +of it, thus forming a work based on the Library, and copy and
151.167 +distribute such modifications or work under the terms of Section 1
151.168 +above, provided that you also meet all of these conditions:
151.169 +
151.170 + a) The modified work must itself be a software library.
151.171 +
151.172 + b) You must cause the files modified to carry prominent notices
151.173 + stating that you changed the files and the date of any change.
151.174 +
151.175 + c) You must cause the whole of the work to be licensed at no
151.176 + charge to all third parties under the terms of this License.
151.177 +
151.178 + d) If a facility in the modified Library refers to a function or a
151.179 + table of data to be supplied by an application program that uses
151.180 + the facility, other than as an argument passed when the facility
151.181 + is invoked, then you must make a good faith effort to ensure that,
151.182 + in the event an application does not supply such function or
151.183 + table, the facility still operates, and performs whatever part of
151.184 + its purpose remains meaningful.
151.185 +
151.186 + (For example, a function in a library to compute square roots has
151.187 + a purpose that is entirely well-defined independent of the
151.188 + application. Therefore, Subsection 2d requires that any
151.189 + application-supplied function or table used by this function must
151.190 + be optional: if the application does not supply it, the square
151.191 + root function must still compute square roots.)
151.192 +
151.193 +These requirements apply to the modified work as a whole. If
151.194 +identifiable sections of that work are not derived from the Library,
151.195 +and can be reasonably considered independent and separate works in
151.196 +themselves, then this License, and its terms, do not apply to those
151.197 +sections when you distribute them as separate works. But when you
151.198 +distribute the same sections as part of a whole which is a work based
151.199 +on the Library, the distribution of the whole must be on the terms of
151.200 +this License, whose permissions for other licensees extend to the
151.201 +entire whole, and thus to each and every part regardless of who wrote
151.202 +it.
151.203 +
151.204 +Thus, it is not the intent of this section to claim rights or contest
151.205 +your rights to work written entirely by you; rather, the intent is to
151.206 +exercise the right to control the distribution of derivative or
151.207 +collective works based on the Library.
151.208 +
151.209 +In addition, mere aggregation of another work not based on the Library
151.210 +with the Library (or with a work based on the Library) on a volume of
151.211 +a storage or distribution medium does not bring the other work under
151.212 +the scope of this License.
151.213 +
151.214 + 3. You may opt to apply the terms of the ordinary GNU General Public
151.215 +License instead of this License to a given copy of the Library. To do
151.216 +this, you must alter all the notices that refer to this License, so
151.217 +that they refer to the ordinary GNU General Public License, version 2,
151.218 +instead of to this License. (If a newer version than version 2 of the
151.219 +ordinary GNU General Public License has appeared, then you can specify
151.220 +that version instead if you wish.) Do not make any other change in
151.221 +these notices.
151.222 +
151.223 + Once this change is made in a given copy, it is irreversible for
151.224 +that copy, so the ordinary GNU General Public License applies to all
151.225 +subsequent copies and derivative works made from that copy.
151.226 +
151.227 + This option is useful when you wish to copy part of the code of
151.228 +the Library into a program that is not a library.
151.229 +
151.230 + 4. You may copy and distribute the Library (or a portion or
151.231 +derivative of it, under Section 2) in object code or executable form
151.232 +under the terms of Sections 1 and 2 above provided that you accompany
151.233 +it with the complete corresponding machine-readable source code, which
151.234 +must be distributed under the terms of Sections 1 and 2 above on a
151.235 +medium customarily used for software interchange.
151.236 +
151.237 + If distribution of object code is made by offering access to copy
151.238 +from a designated place, then offering equivalent access to copy the
151.239 +source code from the same place satisfies the requirement to
151.240 +distribute the source code, even though third parties are not
151.241 +compelled to copy the source along with the object code.
151.242 +
151.243 + 5. A program that contains no derivative of any portion of the
151.244 +Library, but is designed to work with the Library by being compiled or
151.245 +linked with it, is called a "work that uses the Library". Such a
151.246 +work, in isolation, is not a derivative work of the Library, and
151.247 +therefore falls outside the scope of this License.
151.248 +
151.249 + However, linking a "work that uses the Library" with the Library
151.250 +creates an executable that is a derivative of the Library (because it
151.251 +contains portions of the Library), rather than a "work that uses the
151.252 +library". The executable is therefore covered by this License.
151.253 +Section 6 states terms for distribution of such executables.
151.254 +
151.255 + When a "work that uses the Library" uses material from a header file
151.256 +that is part of the Library, the object code for the work may be a
151.257 +derivative work of the Library even though the source code is not.
151.258 +Whether this is true is especially significant if the work can be
151.259 +linked without the Library, or if the work is itself a library. The
151.260 +threshold for this to be true is not precisely defined by law.
151.261 +
151.262 + If such an object file uses only numerical parameters, data
151.263 +structure layouts and accessors, and small macros and small inline
151.264 +functions (ten lines or less in length), then the use of the object
151.265 +file is unrestricted, regardless of whether it is legally a derivative
151.266 +work. (Executables containing this object code plus portions of the
151.267 +Library will still fall under Section 6.)
151.268 +
151.269 + Otherwise, if the work is a derivative of the Library, you may
151.270 +distribute the object code for the work under the terms of Section 6.
151.271 +Any executables containing that work also fall under Section 6,
151.272 +whether or not they are linked directly with the Library itself.
151.273 +
151.274 + 6. As an exception to the Sections above, you may also combine or
151.275 +link a "work that uses the Library" with the Library to produce a
151.276 +work containing portions of the Library, and distribute that work
151.277 +under terms of your choice, provided that the terms permit
151.278 +modification of the work for the customer's own use and reverse
151.279 +engineering for debugging such modifications.
151.280 +
151.281 + You must give prominent notice with each copy of the work that the
151.282 +Library is used in it and that the Library and its use are covered by
151.283 +this License. You must supply a copy of this License. If the work
151.284 +during execution displays copyright notices, you must include the
151.285 +copyright notice for the Library among them, as well as a reference
151.286 +directing the user to the copy of this License. Also, you must do one
151.287 +of these things:
151.288 +
151.289 + a) Accompany the work with the complete corresponding
151.290 + machine-readable source code for the Library including whatever
151.291 + changes were used in the work (which must be distributed under
151.292 + Sections 1 and 2 above); and, if the work is an executable linked
151.293 + with the Library, with the complete machine-readable "work that
151.294 + uses the Library", as object code and/or source code, so that the
151.295 + user can modify the Library and then relink to produce a modified
151.296 + executable containing the modified Library. (It is understood
151.297 + that the user who changes the contents of definitions files in the
151.298 + Library will not necessarily be able to recompile the application
151.299 + to use the modified definitions.)
151.300 +
151.301 + b) Use a suitable shared library mechanism for linking with the
151.302 + Library. A suitable mechanism is one that (1) uses at run time a
151.303 + copy of the library already present on the user's computer system,
151.304 + rather than copying library functions into the executable, and (2)
151.305 + will operate properly with a modified version of the library, if
151.306 + the user installs one, as long as the modified version is
151.307 + interface-compatible with the version that the work was made with.
151.308 +
151.309 + c) Accompany the work with a written offer, valid for at
151.310 + least three years, to give the same user the materials
151.311 + specified in Subsection 6a, above, for a charge no more
151.312 + than the cost of performing this distribution.
151.313 +
151.314 + d) If distribution of the work is made by offering access to copy
151.315 + from a designated place, offer equivalent access to copy the above
151.316 + specified materials from the same place.
151.317 +
151.318 + e) Verify that the user has already received a copy of these
151.319 + materials or that you have already sent this user a copy.
151.320 +
151.321 + For an executable, the required form of the "work that uses the
151.322 +Library" must include any data and utility programs needed for
151.323 +reproducing the executable from it. However, as a special exception,
151.324 +the materials to be distributed need not include anything that is
151.325 +normally distributed (in either source or binary form) with the major
151.326 +components (compiler, kernel, and so on) of the operating system on
151.327 +which the executable runs, unless that component itself accompanies
151.328 +the executable.
151.329 +
151.330 + It may happen that this requirement contradicts the license
151.331 +restrictions of other proprietary libraries that do not normally
151.332 +accompany the operating system. Such a contradiction means you cannot
151.333 +use both them and the Library together in an executable that you
151.334 +distribute.
151.335 +
151.336 + 7. You may place library facilities that are a work based on the
151.337 +Library side-by-side in a single library together with other library
151.338 +facilities not covered by this License, and distribute such a combined
151.339 +library, provided that the separate distribution of the work based on
151.340 +the Library and of the other library facilities is otherwise
151.341 +permitted, and provided that you do these two things:
151.342 +
151.343 + a) Accompany the combined library with a copy of the same work
151.344 + based on the Library, uncombined with any other library
151.345 + facilities. This must be distributed under the terms of the
151.346 + Sections above.
151.347 +
151.348 + b) Give prominent notice with the combined library of the fact
151.349 + that part of it is a work based on the Library, and explaining
151.350 + where to find the accompanying uncombined form of the same work.
151.351 +
151.352 + 8. You may not copy, modify, sublicense, link with, or distribute
151.353 +the Library except as expressly provided under this License. Any
151.354 +attempt otherwise to copy, modify, sublicense, link with, or
151.355 +distribute the Library is void, and will automatically terminate your
151.356 +rights under this License. However, parties who have received copies,
151.357 +or rights, from you under this License will not have their licenses
151.358 +terminated so long as such parties remain in full compliance.
151.359 +
151.360 + 9. You are not required to accept this License, since you have not
151.361 +signed it. However, nothing else grants you permission to modify or
151.362 +distribute the Library or its derivative works. These actions are
151.363 +prohibited by law if you do not accept this License. Therefore, by
151.364 +modifying or distributing the Library (or any work based on the
151.365 +Library), you indicate your acceptance of this License to do so, and
151.366 +all its terms and conditions for copying, distributing or modifying
151.367 +the Library or works based on it.
151.368 +
151.369 + 10. Each time you redistribute the Library (or any work based on the
151.370 +Library), the recipient automatically receives a license from the
151.371 +original licensor to copy, distribute, link with or modify the Library
151.372 +subject to these terms and conditions. You may not impose any further
151.373 +restrictions on the recipients' exercise of the rights granted herein.
151.374 +You are not responsible for enforcing compliance by third parties with
151.375 +this License.
151.376 +
151.377 + 11. If, as a consequence of a court judgment or allegation of patent
151.378 +infringement or for any other reason (not limited to patent issues),
151.379 +conditions are imposed on you (whether by court order, agreement or
151.380 +otherwise) that contradict the conditions of this License, they do not
151.381 +excuse you from the conditions of this License. If you cannot
151.382 +distribute so as to satisfy simultaneously your obligations under this
151.383 +License and any other pertinent obligations, then as a consequence you
151.384 +may not distribute the Library at all. For example, if a patent
151.385 +license would not permit royalty-free redistribution of the Library by
151.386 +all those who receive copies directly or indirectly through you, then
151.387 +the only way you could satisfy both it and this License would be to
151.388 +refrain entirely from distribution of the Library.
151.389 +
151.390 +If any portion of this section is held invalid or unenforceable under any
151.391 +particular circumstance, the balance of the section is intended to apply,
151.392 +and the section as a whole is intended to apply in other circumstances.
151.393 +
151.394 +It is not the purpose of this section to induce you to infringe any
151.395 +patents or other property right claims or to contest validity of any
151.396 +such claims; this section has the sole purpose of protecting the
151.397 +integrity of the free software distribution system which is
151.398 +implemented by public license practices. Many people have made
151.399 +generous contributions to the wide range of software distributed
151.400 +through that system in reliance on consistent application of that
151.401 +system; it is up to the author/donor to decide if he or she is willing
151.402 +to distribute software through any other system and a licensee cannot
151.403 +impose that choice.
151.404 +
151.405 +This section is intended to make thoroughly clear what is believed to
151.406 +be a consequence of the rest of this License.
151.407 +
151.408 + 12. If the distribution and/or use of the Library is restricted in
151.409 +certain countries either by patents or by copyrighted interfaces, the
151.410 +original copyright holder who places the Library under this License may add
151.411 +an explicit geographical distribution limitation excluding those countries,
151.412 +so that distribution is permitted only in or among countries not thus
151.413 +excluded. In such case, this License incorporates the limitation as if
151.414 +written in the body of this License.
151.415 +
151.416 + 13. The Free Software Foundation may publish revised and/or new
151.417 +versions of the Lesser General Public License from time to time.
151.418 +Such new versions will be similar in spirit to the present version,
151.419 +but may differ in detail to address new problems or concerns.
151.420 +
151.421 +Each version is given a distinguishing version number. If the Library
151.422 +specifies a version number of this License which applies to it and
151.423 +"any later version", you have the option of following the terms and
151.424 +conditions either of that version or of any later version published by
151.425 +the Free Software Foundation. If the Library does not specify a
151.426 +license version number, you may choose any version ever published by
151.427 +the Free Software Foundation.
151.428 +
151.429 + 14. If you wish to incorporate parts of the Library into other free
151.430 +programs whose distribution conditions are incompatible with these,
151.431 +write to the author to ask for permission. For software which is
151.432 +copyrighted by the Free Software Foundation, write to the Free
151.433 +Software Foundation; we sometimes make exceptions for this. Our
151.434 +decision will be guided by the two goals of preserving the free status
151.435 +of all derivatives of our free software and of promoting the sharing
151.436 +and reuse of software generally.
151.437 +
151.438 + NO WARRANTY
151.439 +
151.440 + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
151.441 +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
151.442 +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
151.443 +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
151.444 +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
151.445 +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
151.446 +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
151.447 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
151.448 +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
151.449 +
151.450 + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
151.451 +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
151.452 +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
151.453 +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
151.454 +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
151.455 +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
151.456 +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
151.457 +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
151.458 +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
151.459 +DAMAGES.
151.460 +
151.461 + END OF TERMS AND CONDITIONS
151.462 +
151.463 + How to Apply These Terms to Your New Libraries
151.464 +
151.465 + If you develop a new library, and you want it to be of the greatest
151.466 +possible use to the public, we recommend making it free software that
151.467 +everyone can redistribute and change. You can do so by permitting
151.468 +redistribution under these terms (or, alternatively, under the terms of the
151.469 +ordinary General Public License).
151.470 +
151.471 + To apply these terms, attach the following notices to the library. It is
151.472 +safest to attach them to the start of each source file to most effectively
151.473 +convey the exclusion of warranty; and each file should have at least the
151.474 +"copyright" line and a pointer to where the full notice is found.
151.475 +
151.476 + <one line to give the library's name and a brief idea of what it does.>
151.477 + Copyright (C) <year> <name of author>
151.478 +
151.479 + This library is free software; you can redistribute it and/or
151.480 + modify it under the terms of the GNU Lesser General Public
151.481 + License as published by the Free Software Foundation; either
151.482 + version 2.1 of the License, or (at your option) any later version.
151.483 +
151.484 + This library is distributed in the hope that it will be useful,
151.485 + but WITHOUT ANY WARRANTY; without even the implied warranty of
151.486 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
151.487 + Lesser General Public License for more details.
151.488 +
151.489 + You should have received a copy of the GNU Lesser General Public
151.490 + License along with this library; if not, write to the Free Software
151.491 + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
151.492 +
151.493 +Also add information on how to contact you by electronic and paper mail.
151.494 +
151.495 +You should also get your employer (if you work as a programmer) or your
151.496 +school, if any, to sign a "copyright disclaimer" for the library, if
151.497 +necessary. Here is a sample; alter the names:
151.498 +
151.499 + Yoyodyne, Inc., hereby disclaims all copyright interest in the
151.500 + library `Frob' (a library for tweaking knobs) written by James Random Hacker.
151.501 +
151.502 + <signature of Ty Coon>, 1 April 1990
151.503 + Ty Coon, President of Vice
151.504 +
151.505 +That's all there is to it!
152.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
152.2 +++ b/src/colamd/README Mon Dec 06 13:09:21 2010 +0100
152.3 @@ -0,0 +1,98 @@
152.4 +NOTE: Files in this subdirectory are NOT part of the GLPK package, but
152.5 + are used with GLPK.
152.6 +
152.7 + The original code was modified according to GLPK requirements by
152.8 + Andrew Makhorin <mao@gnu.org>.
152.9 +************************************************************************
152.10 +COLAMD/SYMAMD Version 2.7, Copyright (C) 1998-2007, Timothy A. Davis,
152.11 +All Rights Reserved.
152.12 +
152.13 +Description:
152.14 +
152.15 + colamd: an approximate minimum degree column ordering algorithm,
152.16 + for LU factorization of symmetric or unsymmetric matrices,
152.17 + QR factorization, least squares, interior point methods for
152.18 + linear programming problems, and other related problems.
152.19 +
152.20 + symamd: an approximate minimum degree ordering algorithm for
152.21 + Cholesky factorization of symmetric matrices.
152.22 +
152.23 +Purpose:
152.24 +
152.25 + Colamd computes a permutation Q such that the Cholesky factorization
152.26 + of (AQ)'(AQ) has less fill-in and requires fewer floating point
152.27 + operations than A'A. This also provides a good ordering for sparse
152.28 + partial pivoting methods, P(AQ) = LU, where Q is computed prior to
152.29 + numerical factorization, and P is computed during numerical
152.30 + factorization via conventional partial pivoting with row
152.31 + interchanges. Colamd is the column ordering method used in SuperLU,
152.32 + part of the ScaLAPACK library. It is also available as built-in
152.33 + function in MATLAB Version 6, available from MathWorks, Inc.
152.34 + (http://www.mathworks.com). This routine can be used in place of
152.35 + colmmd in MATLAB.
152.36 +
152.37 + Symamd computes a permutation P of a symmetric matrix A such that
152.38 + the Cholesky factorization of PAP' has less fill-in and requires
152.39 + fewer floating point operations than A. Symamd constructs a matrix
152.40 + M such that M'M has the same nonzero pattern of A, and then orders
152.41 + the columns of M using colmmd. The column ordering of M is then
152.42 + returned as the row and column ordering P of A.
152.43 +
152.44 +Authors:
152.45 +
152.46 + The authors of the code itself are Stefan I. Larimore and Timothy A.
152.47 + Davis (davis at cise.ufl.edu), University of Florida. The algorithm
152.48 + was developed in collaboration with John Gilbert, Xerox PARC, and
152.49 + Esmond Ng, Oak Ridge National Laboratory.
152.50 +
152.51 +Acknowledgements:
152.52 +
152.53 + This work was supported by the National Science Foundation, under
152.54 + grants DMS-9504974 and DMS-9803599.
152.55 +
152.56 +License:
152.57 +
152.58 + This library is free software; you can redistribute it and/or
152.59 + modify it under the terms of the GNU Lesser General Public License
152.60 + as published by the Free Software Foundation; either version 2.1 of
152.61 + the License, or (at your option) any later version.
152.62 +
152.63 + This library is distributed in the hope that it will be useful,
152.64 + but WITHOUT ANY WARRANTY; without even the implied warranty of
152.65 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
152.66 + Lesser General Public License for more details.
152.67 +
152.68 + You should have received a copy of the GNU Lesser General Public
152.69 + License along with this library; if not, write to the Free Software
152.70 + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
152.71 + USA.
152.72 +
152.73 + Permission is hereby granted to use or copy this program under the
152.74 + terms of the GNU LGPL, provided that the Copyright, this License,
152.75 + and the Availability of the original version is retained on all
152.76 + copies. User documentation of any code that uses this code or any
152.77 + modified version of this code must cite the Copyright, this License,
152.78 + the Availability note, and "Used by permission." Permission to
152.79 + modify the code and to distribute modified code is granted, provided
152.80 + the Copyright, this License, and the Availability note are retained,
152.81 + and a notice that the code was modified is included.
152.82 +
152.83 + COLAMD is also available under alternate licenses, contact T. Davis
152.84 + for details.
152.85 +
152.86 +Availability:
152.87 +
152.88 + The colamd/symamd library is available at:
152.89 +
152.90 + http://www.cise.ufl.edu/research/sparse/colamd/
152.91 +
152.92 +References:
152.93 +
152.94 + T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate
152.95 + column minimum degree ordering algorithm, ACM Transactions on
152.96 + Mathematical Software, vol. 30, no. 3., pp. 353-376, 2004.
152.97 +
152.98 + T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836:
152.99 + COLAMD, an approximate column minimum degree ordering algorithm, ACM
152.100 + Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380,
152.101 + 2004.
153.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
153.2 +++ b/src/colamd/colamd.c Mon Dec 06 13:09:21 2010 +0100
153.3 @@ -0,0 +1,3622 @@
153.4 +/* ========================================================================== */
153.5 +/* === colamd/symamd - a sparse matrix column ordering algorithm ============ */
153.6 +/* ========================================================================== */
153.7 +
153.8 +/* COLAMD / SYMAMD
153.9 +
153.10 + colamd: an approximate minimum degree column ordering algorithm,
153.11 + for LU factorization of symmetric or unsymmetric matrices,
153.12 + QR factorization, least squares, interior point methods for
153.13 + linear programming problems, and other related problems.
153.14 +
153.15 + symamd: an approximate minimum degree ordering algorithm for Cholesky
153.16 + factorization of symmetric matrices.
153.17 +
153.18 + Purpose:
153.19 +
153.20 + Colamd computes a permutation Q such that the Cholesky factorization of
153.21 + (AQ)'(AQ) has less fill-in and requires fewer floating point operations
153.22 + than A'A. This also provides a good ordering for sparse partial
153.23 + pivoting methods, P(AQ) = LU, where Q is computed prior to numerical
153.24 + factorization, and P is computed during numerical factorization via
153.25 + conventional partial pivoting with row interchanges. Colamd is the
153.26 + column ordering method used in SuperLU, part of the ScaLAPACK library.
153.27 + It is also available as built-in function in MATLAB Version 6,
153.28 + available from MathWorks, Inc. (http://www.mathworks.com). This
153.29 + routine can be used in place of colmmd in MATLAB.
153.30 +
153.31 + Symamd computes a permutation P of a symmetric matrix A such that the
153.32 + Cholesky factorization of PAP' has less fill-in and requires fewer
153.33 + floating point operations than A. Symamd constructs a matrix M such
153.34 + that M'M has the same nonzero pattern of A, and then orders the columns
153.35 + of M using colmmd. The column ordering of M is then returned as the
153.36 + row and column ordering P of A.
153.37 +
153.38 + Authors:
153.39 +
153.40 + The authors of the code itself are Stefan I. Larimore and Timothy A.
153.41 + Davis (davis at cise.ufl.edu), University of Florida. The algorithm was
153.42 + developed in collaboration with John Gilbert, Xerox PARC, and Esmond
153.43 + Ng, Oak Ridge National Laboratory.
153.44 +
153.45 + Acknowledgements:
153.46 +
153.47 + This work was supported by the National Science Foundation, under
153.48 + grants DMS-9504974 and DMS-9803599.
153.49 +
153.50 + Copyright and License:
153.51 +
153.52 + Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved.
153.53 + COLAMD is also available under alternate licenses, contact T. Davis
153.54 + for details.
153.55 +
153.56 + This library is free software; you can redistribute it and/or
153.57 + modify it under the terms of the GNU Lesser General Public
153.58 + License as published by the Free Software Foundation; either
153.59 + version 2.1 of the License, or (at your option) any later version.
153.60 +
153.61 + This library is distributed in the hope that it will be useful,
153.62 + but WITHOUT ANY WARRANTY; without even the implied warranty of
153.63 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
153.64 + Lesser General Public License for more details.
153.65 +
153.66 + You should have received a copy of the GNU Lesser General Public
153.67 + License along with this library; if not, write to the Free Software
153.68 + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
153.69 + USA
153.70 +
153.71 + Permission is hereby granted to use or copy this program under the
153.72 + terms of the GNU LGPL, provided that the Copyright, this License,
153.73 + and the Availability of the original version is retained on all copies.
153.74 + User documentation of any code that uses this code or any modified
153.75 + version of this code must cite the Copyright, this License, the
153.76 + Availability note, and "Used by permission." Permission to modify
153.77 + the code and to distribute modified code is granted, provided the
153.78 + Copyright, this License, and the Availability note are retained,
153.79 + and a notice that the code was modified is included.
153.80 +
153.81 + Availability:
153.82 +
153.83 + The colamd/symamd library is available at
153.84 +
153.85 + http://www.cise.ufl.edu/research/sparse/colamd/
153.86 +
153.87 + This is the http://www.cise.ufl.edu/research/sparse/colamd/colamd.c
153.88 + file. It requires the colamd.h file. It is required by the colamdmex.c
153.89 + and symamdmex.c files, for the MATLAB interface to colamd and symamd.
153.90 + Appears as ACM Algorithm 836.
153.91 +
153.92 + See the ChangeLog file for changes since Version 1.0.
153.93 +
153.94 + References:
153.95 +
153.96 + T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate column
153.97 + minimum degree ordering algorithm, ACM Transactions on Mathematical
153.98 + Software, vol. 30, no. 3., pp. 353-376, 2004.
153.99 +
153.100 + T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD,
153.101 + an approximate column minimum degree ordering algorithm, ACM
153.102 + Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380,
153.103 + 2004.
153.104 +
153.105 +*/
153.106 +
153.107 +/* ========================================================================== */
153.108 +/* === Description of user-callable routines ================================ */
153.109 +/* ========================================================================== */
153.110 +
153.111 +/* COLAMD includes both int and UF_long versions of all its routines. The
153.112 + * description below is for the int version. For UF_long, all int arguments
153.113 + * become UF_long. UF_long is normally defined as long, except for WIN64.
153.114 +
153.115 + ----------------------------------------------------------------------------
153.116 + colamd_recommended:
153.117 + ----------------------------------------------------------------------------
153.118 +
153.119 + C syntax:
153.120 +
153.121 + #include "colamd.h"
153.122 + size_t colamd_recommended (int nnz, int n_row, int n_col) ;
153.123 + size_t colamd_l_recommended (UF_long nnz, UF_long n_row,
153.124 + UF_long n_col) ;
153.125 +
153.126 + Purpose:
153.127 +
153.128 + Returns recommended value of Alen for use by colamd. Returns 0
153.129 + if any input argument is negative. The use of this routine
153.130 + is optional. Not needed for symamd, which dynamically allocates
153.131 + its own memory.
153.132 +
153.133 + Note that in v2.4 and earlier, these routines returned int or long.
153.134 + They now return a value of type size_t.
153.135 +
153.136 + Arguments (all input arguments):
153.137 +
153.138 + int nnz ; Number of nonzeros in the matrix A. This must
153.139 + be the same value as p [n_col] in the call to
153.140 + colamd - otherwise you will get a wrong value
153.141 + of the recommended memory to use.
153.142 +
153.143 + int n_row ; Number of rows in the matrix A.
153.144 +
153.145 + int n_col ; Number of columns in the matrix A.
153.146 +
153.147 + ----------------------------------------------------------------------------
153.148 + colamd_set_defaults:
153.149 + ----------------------------------------------------------------------------
153.150 +
153.151 + C syntax:
153.152 +
153.153 + #include "colamd.h"
153.154 + colamd_set_defaults (double knobs [COLAMD_KNOBS]) ;
153.155 + colamd_l_set_defaults (double knobs [COLAMD_KNOBS]) ;
153.156 +
153.157 + Purpose:
153.158 +
153.159 + Sets the default parameters. The use of this routine is optional.
153.160 +
153.161 + Arguments:
153.162 +
153.163 + double knobs [COLAMD_KNOBS] ; Output only.
153.164 +
153.165 + NOTE: the meaning of the dense row/col knobs has changed in v2.4
153.166 +
153.167 + knobs [0] and knobs [1] control dense row and col detection:
153.168 +
153.169 + Colamd: rows with more than
153.170 + max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n_col))
153.171 + entries are removed prior to ordering. Columns with more than
153.172 + max (16, knobs [COLAMD_DENSE_COL] * sqrt (MIN (n_row,n_col)))
153.173 + entries are removed prior to
153.174 + ordering, and placed last in the output column ordering.
153.175 +
153.176 + Symamd: uses only knobs [COLAMD_DENSE_ROW], which is knobs [0].
153.177 + Rows and columns with more than
153.178 + max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n))
153.179 + entries are removed prior to ordering, and placed last in the
153.180 + output ordering.
153.181 +
153.182 + COLAMD_DENSE_ROW and COLAMD_DENSE_COL are defined as 0 and 1,
153.183 + respectively, in colamd.h. Default values of these two knobs
153.184 + are both 10. Currently, only knobs [0] and knobs [1] are
153.185 + used, but future versions may use more knobs. If so, they will
153.186 + be properly set to their defaults by the future version of
153.187 + colamd_set_defaults, so that the code that calls colamd will
153.188 + not need to change, assuming that you either use
153.189 + colamd_set_defaults, or pass a (double *) NULL pointer as the
153.190 + knobs array to colamd or symamd.
153.191 +
153.192 + knobs [2]: aggressive absorption
153.193 +
153.194 + knobs [COLAMD_AGGRESSIVE] controls whether or not to do
153.195 + aggressive absorption during the ordering. Default is TRUE.
153.196 +
153.197 +
153.198 + ----------------------------------------------------------------------------
153.199 + colamd:
153.200 + ----------------------------------------------------------------------------
153.201 +
153.202 + C syntax:
153.203 +
153.204 + #include "colamd.h"
153.205 + int colamd (int n_row, int n_col, int Alen, int *A, int *p,
153.206 + double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS]) ;
153.207 + UF_long colamd_l (UF_long n_row, UF_long n_col, UF_long Alen,
153.208 + UF_long *A, UF_long *p, double knobs [COLAMD_KNOBS],
153.209 + UF_long stats [COLAMD_STATS]) ;
153.210 +
153.211 + Purpose:
153.212 +
153.213 + Computes a column ordering (Q) of A such that P(AQ)=LU or
153.214 + (AQ)'AQ=LL' have less fill-in and require fewer floating point
153.215 + operations than factorizing the unpermuted matrix A or A'A,
153.216 + respectively.
153.217 +
153.218 + Returns:
153.219 +
153.220 + TRUE (1) if successful, FALSE (0) otherwise.
153.221 +
153.222 + Arguments:
153.223 +
153.224 + int n_row ; Input argument.
153.225 +
153.226 + Number of rows in the matrix A.
153.227 + Restriction: n_row >= 0.
153.228 + Colamd returns FALSE if n_row is negative.
153.229 +
153.230 + int n_col ; Input argument.
153.231 +
153.232 + Number of columns in the matrix A.
153.233 + Restriction: n_col >= 0.
153.234 + Colamd returns FALSE if n_col is negative.
153.235 +
153.236 + int Alen ; Input argument.
153.237 +
153.238 + Restriction (see note):
153.239 + Alen >= 2*nnz + 6*(n_col+1) + 4*(n_row+1) + n_col
153.240 + Colamd returns FALSE if these conditions are not met.
153.241 +
153.242 + Note: this restriction makes an modest assumption regarding
153.243 + the size of the two typedef's structures in colamd.h.
153.244 + We do, however, guarantee that
153.245 +
153.246 + Alen >= colamd_recommended (nnz, n_row, n_col)
153.247 +
153.248 + will be sufficient. Note: the macro version does not check
153.249 + for integer overflow, and thus is not recommended. Use
153.250 + the colamd_recommended routine instead.
153.251 +
153.252 + int A [Alen] ; Input argument, undefined on output.
153.253 +
153.254 + A is an integer array of size Alen. Alen must be at least as
153.255 + large as the bare minimum value given above, but this is very
153.256 + low, and can result in excessive run time. For best
153.257 + performance, we recommend that Alen be greater than or equal to
153.258 + colamd_recommended (nnz, n_row, n_col), which adds
153.259 + nnz/5 to the bare minimum value given above.
153.260 +
153.261 + On input, the row indices of the entries in column c of the
153.262 + matrix are held in A [(p [c]) ... (p [c+1]-1)]. The row indices
153.263 + in a given column c need not be in ascending order, and
153.264 + duplicate row indices may be be present. However, colamd will
153.265 + work a little faster if both of these conditions are met
153.266 + (Colamd puts the matrix into this format, if it finds that the
153.267 + the conditions are not met).
153.268 +
153.269 + The matrix is 0-based. That is, rows are in the range 0 to
153.270 + n_row-1, and columns are in the range 0 to n_col-1. Colamd
153.271 + returns FALSE if any row index is out of range.
153.272 +
153.273 + The contents of A are modified during ordering, and are
153.274 + undefined on output.
153.275 +
153.276 + int p [n_col+1] ; Both input and output argument.
153.277 +
153.278 + p is an integer array of size n_col+1. On input, it holds the
153.279 + "pointers" for the column form of the matrix A. Column c of
153.280 + the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first
153.281 + entry, p [0], must be zero, and p [c] <= p [c+1] must hold
153.282 + for all c in the range 0 to n_col-1. The value p [n_col] is
153.283 + thus the total number of entries in the pattern of the matrix A.
153.284 + Colamd returns FALSE if these conditions are not met.
153.285 +
153.286 + On output, if colamd returns TRUE, the array p holds the column
153.287 + permutation (Q, for P(AQ)=LU or (AQ)'(AQ)=LL'), where p [0] is
153.288 + the first column index in the new ordering, and p [n_col-1] is
153.289 + the last. That is, p [k] = j means that column j of A is the
153.290 + kth pivot column, in AQ, where k is in the range 0 to n_col-1
153.291 + (p [0] = j means that column j of A is the first column in AQ).
153.292 +
153.293 + If colamd returns FALSE, then no permutation is returned, and
153.294 + p is undefined on output.
153.295 +
153.296 + double knobs [COLAMD_KNOBS] ; Input argument.
153.297 +
153.298 + See colamd_set_defaults for a description.
153.299 +
153.300 + int stats [COLAMD_STATS] ; Output argument.
153.301 +
153.302 + Statistics on the ordering, and error status.
153.303 + See colamd.h for related definitions.
153.304 + Colamd returns FALSE if stats is not present.
153.305 +
153.306 + stats [0]: number of dense or empty rows ignored.
153.307 +
153.308 + stats [1]: number of dense or empty columns ignored (and
153.309 + ordered last in the output permutation p)
153.310 + Note that a row can become "empty" if it
153.311 + contains only "dense" and/or "empty" columns,
153.312 + and similarly a column can become "empty" if it
153.313 + only contains "dense" and/or "empty" rows.
153.314 +
153.315 + stats [2]: number of garbage collections performed.
153.316 + This can be excessively high if Alen is close
153.317 + to the minimum required value.
153.318 +
153.319 + stats [3]: status code. < 0 is an error code.
153.320 + > 1 is a warning or notice.
153.321 +
153.322 + 0 OK. Each column of the input matrix contained
153.323 + row indices in increasing order, with no
153.324 + duplicates.
153.325 +
153.326 + 1 OK, but columns of input matrix were jumbled
153.327 + (unsorted columns or duplicate entries). Colamd
153.328 + had to do some extra work to sort the matrix
153.329 + first and remove duplicate entries, but it
153.330 + still was able to return a valid permutation
153.331 + (return value of colamd was TRUE).
153.332 +
153.333 + stats [4]: highest numbered column that
153.334 + is unsorted or has duplicate
153.335 + entries.
153.336 + stats [5]: last seen duplicate or
153.337 + unsorted row index.
153.338 + stats [6]: number of duplicate or
153.339 + unsorted row indices.
153.340 +
153.341 + -1 A is a null pointer
153.342 +
153.343 + -2 p is a null pointer
153.344 +
153.345 + -3 n_row is negative
153.346 +
153.347 + stats [4]: n_row
153.348 +
153.349 + -4 n_col is negative
153.350 +
153.351 + stats [4]: n_col
153.352 +
153.353 + -5 number of nonzeros in matrix is negative
153.354 +
153.355 + stats [4]: number of nonzeros, p [n_col]
153.356 +
153.357 + -6 p [0] is nonzero
153.358 +
153.359 + stats [4]: p [0]
153.360 +
153.361 + -7 A is too small
153.362 +
153.363 + stats [4]: required size
153.364 + stats [5]: actual size (Alen)
153.365 +
153.366 + -8 a column has a negative number of entries
153.367 +
153.368 + stats [4]: column with < 0 entries
153.369 + stats [5]: number of entries in col
153.370 +
153.371 + -9 a row index is out of bounds
153.372 +
153.373 + stats [4]: column with bad row index
153.374 + stats [5]: bad row index
153.375 + stats [6]: n_row, # of rows of matrx
153.376 +
153.377 + -10 (unused; see symamd.c)
153.378 +
153.379 + -999 (unused; see symamd.c)
153.380 +
153.381 + Future versions may return more statistics in the stats array.
153.382 +
153.383 + Example:
153.384 +
153.385 + See http://www.cise.ufl.edu/research/sparse/colamd/example.c
153.386 + for a complete example.
153.387 +
153.388 + To order the columns of a 5-by-4 matrix with 11 nonzero entries in
153.389 + the following nonzero pattern
153.390 +
153.391 + x 0 x 0
153.392 + x 0 x x
153.393 + 0 x x 0
153.394 + 0 0 x x
153.395 + x x 0 0
153.396 +
153.397 + with default knobs and no output statistics, do the following:
153.398 +
153.399 + #include "colamd.h"
153.400 + #define ALEN 100
153.401 + int A [ALEN] = {0, 1, 4, 2, 4, 0, 1, 2, 3, 1, 3} ;
153.402 + int p [ ] = {0, 3, 5, 9, 11} ;
153.403 + int stats [COLAMD_STATS] ;
153.404 + colamd (5, 4, ALEN, A, p, (double *) NULL, stats) ;
153.405 +
153.406 + The permutation is returned in the array p, and A is destroyed.
153.407 +
153.408 + ----------------------------------------------------------------------------
153.409 + symamd:
153.410 + ----------------------------------------------------------------------------
153.411 +
153.412 + C syntax:
153.413 +
153.414 + #include "colamd.h"
153.415 + int symamd (int n, int *A, int *p, int *perm,
153.416 + double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS],
153.417 + void (*allocate) (size_t, size_t), void (*release) (void *)) ;
153.418 + UF_long symamd_l (UF_long n, UF_long *A, UF_long *p, UF_long *perm,
153.419 + double knobs [COLAMD_KNOBS], UF_long stats [COLAMD_STATS],
153.420 + void (*allocate) (size_t, size_t), void (*release) (void *)) ;
153.421 +
153.422 + Purpose:
153.423 +
153.424 + The symamd routine computes an ordering P of a symmetric sparse
153.425 + matrix A such that the Cholesky factorization PAP' = LL' remains
153.426 + sparse. It is based on a column ordering of a matrix M constructed
153.427 + so that the nonzero pattern of M'M is the same as A. The matrix A
153.428 + is assumed to be symmetric; only the strictly lower triangular part
153.429 + is accessed. You must pass your selected memory allocator (usually
153.430 + calloc/free or mxCalloc/mxFree) to symamd, for it to allocate
153.431 + memory for the temporary matrix M.
153.432 +
153.433 + Returns:
153.434 +
153.435 + TRUE (1) if successful, FALSE (0) otherwise.
153.436 +
153.437 + Arguments:
153.438 +
153.439 + int n ; Input argument.
153.440 +
153.441 + Number of rows and columns in the symmetrix matrix A.
153.442 + Restriction: n >= 0.
153.443 + Symamd returns FALSE if n is negative.
153.444 +
153.445 + int A [nnz] ; Input argument.
153.446 +
153.447 + A is an integer array of size nnz, where nnz = p [n].
153.448 +
153.449 + The row indices of the entries in column c of the matrix are
153.450 + held in A [(p [c]) ... (p [c+1]-1)]. The row indices in a
153.451 + given column c need not be in ascending order, and duplicate
153.452 + row indices may be present. However, symamd will run faster
153.453 + if the columns are in sorted order with no duplicate entries.
153.454 +
153.455 + The matrix is 0-based. That is, rows are in the range 0 to
153.456 + n-1, and columns are in the range 0 to n-1. Symamd
153.457 + returns FALSE if any row index is out of range.
153.458 +
153.459 + The contents of A are not modified.
153.460 +
153.461 + int p [n+1] ; Input argument.
153.462 +
153.463 + p is an integer array of size n+1. On input, it holds the
153.464 + "pointers" for the column form of the matrix A. Column c of
153.465 + the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first
153.466 + entry, p [0], must be zero, and p [c] <= p [c+1] must hold
153.467 + for all c in the range 0 to n-1. The value p [n] is
153.468 + thus the total number of entries in the pattern of the matrix A.
153.469 + Symamd returns FALSE if these conditions are not met.
153.470 +
153.471 + The contents of p are not modified.
153.472 +
153.473 + int perm [n+1] ; Output argument.
153.474 +
153.475 + On output, if symamd returns TRUE, the array perm holds the
153.476 + permutation P, where perm [0] is the first index in the new
153.477 + ordering, and perm [n-1] is the last. That is, perm [k] = j
153.478 + means that row and column j of A is the kth column in PAP',
153.479 + where k is in the range 0 to n-1 (perm [0] = j means
153.480 + that row and column j of A are the first row and column in
153.481 + PAP'). The array is used as a workspace during the ordering,
153.482 + which is why it must be of length n+1, not just n.
153.483 +
153.484 + double knobs [COLAMD_KNOBS] ; Input argument.
153.485 +
153.486 + See colamd_set_defaults for a description.
153.487 +
153.488 + int stats [COLAMD_STATS] ; Output argument.
153.489 +
153.490 + Statistics on the ordering, and error status.
153.491 + See colamd.h for related definitions.
153.492 + Symamd returns FALSE if stats is not present.
153.493 +
153.494 + stats [0]: number of dense or empty row and columns ignored
153.495 + (and ordered last in the output permutation
153.496 + perm). Note that a row/column can become
153.497 + "empty" if it contains only "dense" and/or
153.498 + "empty" columns/rows.
153.499 +
153.500 + stats [1]: (same as stats [0])
153.501 +
153.502 + stats [2]: number of garbage collections performed.
153.503 +
153.504 + stats [3]: status code. < 0 is an error code.
153.505 + > 1 is a warning or notice.
153.506 +
153.507 + 0 OK. Each column of the input matrix contained
153.508 + row indices in increasing order, with no
153.509 + duplicates.
153.510 +
153.511 + 1 OK, but columns of input matrix were jumbled
153.512 + (unsorted columns or duplicate entries). Symamd
153.513 + had to do some extra work to sort the matrix
153.514 + first and remove duplicate entries, but it
153.515 + still was able to return a valid permutation
153.516 + (return value of symamd was TRUE).
153.517 +
153.518 + stats [4]: highest numbered column that
153.519 + is unsorted or has duplicate
153.520 + entries.
153.521 + stats [5]: last seen duplicate or
153.522 + unsorted row index.
153.523 + stats [6]: number of duplicate or
153.524 + unsorted row indices.
153.525 +
153.526 + -1 A is a null pointer
153.527 +
153.528 + -2 p is a null pointer
153.529 +
153.530 + -3 (unused, see colamd.c)
153.531 +
153.532 + -4 n is negative
153.533 +
153.534 + stats [4]: n
153.535 +
153.536 + -5 number of nonzeros in matrix is negative
153.537 +
153.538 + stats [4]: # of nonzeros (p [n]).
153.539 +
153.540 + -6 p [0] is nonzero
153.541 +
153.542 + stats [4]: p [0]
153.543 +
153.544 + -7 (unused)
153.545 +
153.546 + -8 a column has a negative number of entries
153.547 +
153.548 + stats [4]: column with < 0 entries
153.549 + stats [5]: number of entries in col
153.550 +
153.551 + -9 a row index is out of bounds
153.552 +
153.553 + stats [4]: column with bad row index
153.554 + stats [5]: bad row index
153.555 + stats [6]: n_row, # of rows of matrx
153.556 +
153.557 + -10 out of memory (unable to allocate temporary
153.558 + workspace for M or count arrays using the
153.559 + "allocate" routine passed into symamd).
153.560 +
153.561 + Future versions may return more statistics in the stats array.
153.562 +
153.563 + void * (*allocate) (size_t, size_t)
153.564 +
153.565 + A pointer to a function providing memory allocation. The
153.566 + allocated memory must be returned initialized to zero. For a
153.567 + C application, this argument should normally be a pointer to
153.568 + calloc. For a MATLAB mexFunction, the routine mxCalloc is
153.569 + passed instead.
153.570 +
153.571 + void (*release) (size_t, size_t)
153.572 +
153.573 + A pointer to a function that frees memory allocated by the
153.574 + memory allocation routine above. For a C application, this
153.575 + argument should normally be a pointer to free. For a MATLAB
153.576 + mexFunction, the routine mxFree is passed instead.
153.577 +
153.578 +
153.579 + ----------------------------------------------------------------------------
153.580 + colamd_report:
153.581 + ----------------------------------------------------------------------------
153.582 +
153.583 + C syntax:
153.584 +
153.585 + #include "colamd.h"
153.586 + colamd_report (int stats [COLAMD_STATS]) ;
153.587 + colamd_l_report (UF_long stats [COLAMD_STATS]) ;
153.588 +
153.589 + Purpose:
153.590 +
153.591 + Prints the error status and statistics recorded in the stats
153.592 + array on the standard error output (for a standard C routine)
153.593 + or on the MATLAB output (for a mexFunction).
153.594 +
153.595 + Arguments:
153.596 +
153.597 + int stats [COLAMD_STATS] ; Input only. Statistics from colamd.
153.598 +
153.599 +
153.600 + ----------------------------------------------------------------------------
153.601 + symamd_report:
153.602 + ----------------------------------------------------------------------------
153.603 +
153.604 + C syntax:
153.605 +
153.606 + #include "colamd.h"
153.607 + symamd_report (int stats [COLAMD_STATS]) ;
153.608 + symamd_l_report (UF_long stats [COLAMD_STATS]) ;
153.609 +
153.610 + Purpose:
153.611 +
153.612 + Prints the error status and statistics recorded in the stats
153.613 + array on the standard error output (for a standard C routine)
153.614 + or on the MATLAB output (for a mexFunction).
153.615 +
153.616 + Arguments:
153.617 +
153.618 + int stats [COLAMD_STATS] ; Input only. Statistics from symamd.
153.619 +
153.620 +
153.621 +*/
153.622 +
153.623 +/* ========================================================================== */
153.624 +/* === Scaffolding code definitions ======================================== */
153.625 +/* ========================================================================== */
153.626 +
153.627 +/* Ensure that debugging is turned off: */
153.628 +#ifndef NDEBUG
153.629 +#define NDEBUG
153.630 +#endif
153.631 +
153.632 +/* turn on debugging by uncommenting the following line
153.633 + #undef NDEBUG
153.634 +*/
153.635 +
153.636 +/*
153.637 + Our "scaffolding code" philosophy: In our opinion, well-written library
153.638 + code should keep its "debugging" code, and just normally have it turned off
153.639 + by the compiler so as not to interfere with performance. This serves
153.640 + several purposes:
153.641 +
153.642 + (1) assertions act as comments to the reader, telling you what the code
153.643 + expects at that point. All assertions will always be true (unless
153.644 + there really is a bug, of course).
153.645 +
153.646 + (2) leaving in the scaffolding code assists anyone who would like to modify
153.647 + the code, or understand the algorithm (by reading the debugging output,
153.648 + one can get a glimpse into what the code is doing).
153.649 +
153.650 + (3) (gasp!) for actually finding bugs. This code has been heavily tested
153.651 + and "should" be fully functional and bug-free ... but you never know...
153.652 +
153.653 + The code will become outrageously slow when debugging is
153.654 + enabled. To control the level of debugging output, set an environment
153.655 + variable D to 0 (little), 1 (some), 2, 3, or 4 (lots). When debugging,
153.656 + you should see the following message on the standard output:
153.657 +
153.658 + colamd: debug version, D = 1 (THIS WILL BE SLOW!)
153.659 +
153.660 + or a similar message for symamd. If you don't, then debugging has not
153.661 + been enabled.
153.662 +
153.663 +*/
153.664 +
153.665 +/* ========================================================================== */
153.666 +/* === Include files ======================================================== */
153.667 +/* ========================================================================== */
153.668 +
153.669 +#include "colamd.h"
153.670 +
153.671 +#if 0 /* by mao */
153.672 +#include <limits.h>
153.673 +#include <math.h>
153.674 +
153.675 +#ifdef MATLAB_MEX_FILE
153.676 +#include "mex.h"
153.677 +#include "matrix.h"
153.678 +#endif /* MATLAB_MEX_FILE */
153.679 +
153.680 +#if !defined (NPRINT) || !defined (NDEBUG)
153.681 +#include <stdio.h>
153.682 +#endif
153.683 +
153.684 +#ifndef NULL
153.685 +#define NULL ((void *) 0)
153.686 +#endif
153.687 +#endif
153.688 +
153.689 +/* ========================================================================== */
153.690 +/* === int or UF_long ======================================================= */
153.691 +/* ========================================================================== */
153.692 +
153.693 +#if 0 /* by mao */
153.694 +/* define UF_long */
153.695 +#include "UFconfig.h"
153.696 +#endif
153.697 +
153.698 +#ifdef DLONG
153.699 +
153.700 +#define Int UF_long
153.701 +#define ID UF_long_id
153.702 +#define Int_MAX UF_long_max
153.703 +
153.704 +#define COLAMD_recommended colamd_l_recommended
153.705 +#define COLAMD_set_defaults colamd_l_set_defaults
153.706 +#define COLAMD_MAIN colamd_l
153.707 +#define SYMAMD_MAIN symamd_l
153.708 +#define COLAMD_report colamd_l_report
153.709 +#define SYMAMD_report symamd_l_report
153.710 +
153.711 +#else
153.712 +
153.713 +#define Int int
153.714 +#define ID "%d"
153.715 +#define Int_MAX INT_MAX
153.716 +
153.717 +#define COLAMD_recommended colamd_recommended
153.718 +#define COLAMD_set_defaults colamd_set_defaults
153.719 +#define COLAMD_MAIN colamd
153.720 +#define SYMAMD_MAIN symamd
153.721 +#define COLAMD_report colamd_report
153.722 +#define SYMAMD_report symamd_report
153.723 +
153.724 +#endif
153.725 +
153.726 +/* ========================================================================== */
153.727 +/* === Row and Column structures ============================================ */
153.728 +/* ========================================================================== */
153.729 +
153.730 +/* User code that makes use of the colamd/symamd routines need not directly */
153.731 +/* reference these structures. They are used only for colamd_recommended. */
153.732 +
153.733 +typedef struct Colamd_Col_struct
153.734 +{
153.735 + Int start ; /* index for A of first row in this column, or DEAD */
153.736 + /* if column is dead */
153.737 + Int length ; /* number of rows in this column */
153.738 + union
153.739 + {
153.740 + Int thickness ; /* number of original columns represented by this */
153.741 + /* col, if the column is alive */
153.742 + Int parent ; /* parent in parent tree super-column structure, if */
153.743 + /* the column is dead */
153.744 + } shared1 ;
153.745 + union
153.746 + {
153.747 + Int score ; /* the score used to maintain heap, if col is alive */
153.748 + Int order ; /* pivot ordering of this column, if col is dead */
153.749 + } shared2 ;
153.750 + union
153.751 + {
153.752 + Int headhash ; /* head of a hash bucket, if col is at the head of */
153.753 + /* a degree list */
153.754 + Int hash ; /* hash value, if col is not in a degree list */
153.755 + Int prev ; /* previous column in degree list, if col is in a */
153.756 + /* degree list (but not at the head of a degree list) */
153.757 + } shared3 ;
153.758 + union
153.759 + {
153.760 + Int degree_next ; /* next column, if col is in a degree list */
153.761 + Int hash_next ; /* next column, if col is in a hash list */
153.762 + } shared4 ;
153.763 +
153.764 +} Colamd_Col ;
153.765 +
153.766 +typedef struct Colamd_Row_struct
153.767 +{
153.768 + Int start ; /* index for A of first col in this row */
153.769 + Int length ; /* number of principal columns in this row */
153.770 + union
153.771 + {
153.772 + Int degree ; /* number of principal & non-principal columns in row */
153.773 + Int p ; /* used as a row pointer in init_rows_cols () */
153.774 + } shared1 ;
153.775 + union
153.776 + {
153.777 + Int mark ; /* for computing set differences and marking dead rows*/
153.778 + Int first_column ;/* first column in row (used in garbage collection) */
153.779 + } shared2 ;
153.780 +
153.781 +} Colamd_Row ;
153.782 +
153.783 +/* ========================================================================== */
153.784 +/* === Definitions ========================================================== */
153.785 +/* ========================================================================== */
153.786 +
153.787 +/* Routines are either PUBLIC (user-callable) or PRIVATE (not user-callable) */
153.788 +#define PUBLIC
153.789 +#define PRIVATE static
153.790 +
153.791 +#define DENSE_DEGREE(alpha,n) \
153.792 + ((Int) MAX (16.0, (alpha) * sqrt ((double) (n))))
153.793 +
153.794 +#define MAX(a,b) (((a) > (b)) ? (a) : (b))
153.795 +#define MIN(a,b) (((a) < (b)) ? (a) : (b))
153.796 +
153.797 +#define ONES_COMPLEMENT(r) (-(r)-1)
153.798 +
153.799 +/* -------------------------------------------------------------------------- */
153.800 +/* Change for version 2.1: define TRUE and FALSE only if not yet defined */
153.801 +/* -------------------------------------------------------------------------- */
153.802 +
153.803 +#ifndef TRUE
153.804 +#define TRUE (1)
153.805 +#endif
153.806 +
153.807 +#ifndef FALSE
153.808 +#define FALSE (0)
153.809 +#endif
153.810 +
153.811 +/* -------------------------------------------------------------------------- */
153.812 +
153.813 +#define EMPTY (-1)
153.814 +
153.815 +/* Row and column status */
153.816 +#define ALIVE (0)
153.817 +#define DEAD (-1)
153.818 +
153.819 +/* Column status */
153.820 +#define DEAD_PRINCIPAL (-1)
153.821 +#define DEAD_NON_PRINCIPAL (-2)
153.822 +
153.823 +/* Macros for row and column status update and checking. */
153.824 +#define ROW_IS_DEAD(r) ROW_IS_MARKED_DEAD (Row[r].shared2.mark)
153.825 +#define ROW_IS_MARKED_DEAD(row_mark) (row_mark < ALIVE)
153.826 +#define ROW_IS_ALIVE(r) (Row [r].shared2.mark >= ALIVE)
153.827 +#define COL_IS_DEAD(c) (Col [c].start < ALIVE)
153.828 +#define COL_IS_ALIVE(c) (Col [c].start >= ALIVE)
153.829 +#define COL_IS_DEAD_PRINCIPAL(c) (Col [c].start == DEAD_PRINCIPAL)
153.830 +#define KILL_ROW(r) { Row [r].shared2.mark = DEAD ; }
153.831 +#define KILL_PRINCIPAL_COL(c) { Col [c].start = DEAD_PRINCIPAL ; }
153.832 +#define KILL_NON_PRINCIPAL_COL(c) { Col [c].start = DEAD_NON_PRINCIPAL ; }
153.833 +
153.834 +/* ========================================================================== */
153.835 +/* === Colamd reporting mechanism =========================================== */
153.836 +/* ========================================================================== */
153.837 +
153.838 +#if defined (MATLAB_MEX_FILE) || defined (MATHWORKS)
153.839 +/* In MATLAB, matrices are 1-based to the user, but 0-based internally */
153.840 +#define INDEX(i) ((i)+1)
153.841 +#else
153.842 +/* In C, matrices are 0-based and indices are reported as such in *_report */
153.843 +#define INDEX(i) (i)
153.844 +#endif
153.845 +
153.846 +/* All output goes through the PRINTF macro. */
153.847 +#define PRINTF(params) { if (colamd_printf != NULL) (void) colamd_printf params ; }
153.848 +
153.849 +/* ========================================================================== */
153.850 +/* === Prototypes of PRIVATE routines ======================================= */
153.851 +/* ========================================================================== */
153.852 +
153.853 +PRIVATE Int init_rows_cols
153.854 +(
153.855 + Int n_row,
153.856 + Int n_col,
153.857 + Colamd_Row Row [],
153.858 + Colamd_Col Col [],
153.859 + Int A [],
153.860 + Int p [],
153.861 + Int stats [COLAMD_STATS]
153.862 +) ;
153.863 +
153.864 +PRIVATE void init_scoring
153.865 +(
153.866 + Int n_row,
153.867 + Int n_col,
153.868 + Colamd_Row Row [],
153.869 + Colamd_Col Col [],
153.870 + Int A [],
153.871 + Int head [],
153.872 + double knobs [COLAMD_KNOBS],
153.873 + Int *p_n_row2,
153.874 + Int *p_n_col2,
153.875 + Int *p_max_deg
153.876 +) ;
153.877 +
153.878 +PRIVATE Int find_ordering
153.879 +(
153.880 + Int n_row,
153.881 + Int n_col,
153.882 + Int Alen,
153.883 + Colamd_Row Row [],
153.884 + Colamd_Col Col [],
153.885 + Int A [],
153.886 + Int head [],
153.887 + Int n_col2,
153.888 + Int max_deg,
153.889 + Int pfree,
153.890 + Int aggressive
153.891 +) ;
153.892 +
153.893 +PRIVATE void order_children
153.894 +(
153.895 + Int n_col,
153.896 + Colamd_Col Col [],
153.897 + Int p []
153.898 +) ;
153.899 +
153.900 +PRIVATE void detect_super_cols
153.901 +(
153.902 +
153.903 +#ifndef NDEBUG
153.904 + Int n_col,
153.905 + Colamd_Row Row [],
153.906 +#endif /* NDEBUG */
153.907 +
153.908 + Colamd_Col Col [],
153.909 + Int A [],
153.910 + Int head [],
153.911 + Int row_start,
153.912 + Int row_length
153.913 +) ;
153.914 +
153.915 +PRIVATE Int garbage_collection
153.916 +(
153.917 + Int n_row,
153.918 + Int n_col,
153.919 + Colamd_Row Row [],
153.920 + Colamd_Col Col [],
153.921 + Int A [],
153.922 + Int *pfree
153.923 +) ;
153.924 +
153.925 +PRIVATE Int clear_mark
153.926 +(
153.927 + Int tag_mark,
153.928 + Int max_mark,
153.929 + Int n_row,
153.930 + Colamd_Row Row []
153.931 +) ;
153.932 +
153.933 +PRIVATE void print_report
153.934 +(
153.935 + char *method,
153.936 + Int stats [COLAMD_STATS]
153.937 +) ;
153.938 +
153.939 +/* ========================================================================== */
153.940 +/* === Debugging prototypes and definitions ================================= */
153.941 +/* ========================================================================== */
153.942 +
153.943 +#ifndef NDEBUG
153.944 +
153.945 +#if 0 /* by mao */
153.946 +#include <assert.h>
153.947 +#endif
153.948 +
153.949 +/* colamd_debug is the *ONLY* global variable, and is only */
153.950 +/* present when debugging */
153.951 +
153.952 +PRIVATE Int colamd_debug = 0 ; /* debug print level */
153.953 +
153.954 +#define DEBUG0(params) { PRINTF (params) ; }
153.955 +#define DEBUG1(params) { if (colamd_debug >= 1) PRINTF (params) ; }
153.956 +#define DEBUG2(params) { if (colamd_debug >= 2) PRINTF (params) ; }
153.957 +#define DEBUG3(params) { if (colamd_debug >= 3) PRINTF (params) ; }
153.958 +#define DEBUG4(params) { if (colamd_debug >= 4) PRINTF (params) ; }
153.959 +
153.960 +#if 0 /* by mao */
153.961 +#ifdef MATLAB_MEX_FILE
153.962 +#define ASSERT(expression) (mxAssert ((expression), ""))
153.963 +#else
153.964 +#define ASSERT(expression) (assert (expression))
153.965 +#endif /* MATLAB_MEX_FILE */
153.966 +#else
153.967 +#define ASSERT xassert
153.968 +#endif
153.969 +
153.970 +PRIVATE void colamd_get_debug /* gets the debug print level from getenv */
153.971 +(
153.972 + char *method
153.973 +) ;
153.974 +
153.975 +PRIVATE void debug_deg_lists
153.976 +(
153.977 + Int n_row,
153.978 + Int n_col,
153.979 + Colamd_Row Row [],
153.980 + Colamd_Col Col [],
153.981 + Int head [],
153.982 + Int min_score,
153.983 + Int should,
153.984 + Int max_deg
153.985 +) ;
153.986 +
153.987 +PRIVATE void debug_mark
153.988 +(
153.989 + Int n_row,
153.990 + Colamd_Row Row [],
153.991 + Int tag_mark,
153.992 + Int max_mark
153.993 +) ;
153.994 +
153.995 +PRIVATE void debug_matrix
153.996 +(
153.997 + Int n_row,
153.998 + Int n_col,
153.999 + Colamd_Row Row [],
153.1000 + Colamd_Col Col [],
153.1001 + Int A []
153.1002 +) ;
153.1003 +
153.1004 +PRIVATE void debug_structures
153.1005 +(
153.1006 + Int n_row,
153.1007 + Int n_col,
153.1008 + Colamd_Row Row [],
153.1009 + Colamd_Col Col [],
153.1010 + Int A [],
153.1011 + Int n_col2
153.1012 +) ;
153.1013 +
153.1014 +#else /* NDEBUG */
153.1015 +
153.1016 +/* === No debugging ========================================================= */
153.1017 +
153.1018 +#define DEBUG0(params) ;
153.1019 +#define DEBUG1(params) ;
153.1020 +#define DEBUG2(params) ;
153.1021 +#define DEBUG3(params) ;
153.1022 +#define DEBUG4(params) ;
153.1023 +
153.1024 +#define ASSERT(expression)
153.1025 +
153.1026 +#endif /* NDEBUG */
153.1027 +
153.1028 +/* ========================================================================== */
153.1029 +/* === USER-CALLABLE ROUTINES: ============================================== */
153.1030 +/* ========================================================================== */
153.1031 +
153.1032 +/* ========================================================================== */
153.1033 +/* === colamd_recommended =================================================== */
153.1034 +/* ========================================================================== */
153.1035 +
153.1036 +/*
153.1037 + The colamd_recommended routine returns the suggested size for Alen. This
153.1038 + value has been determined to provide good balance between the number of
153.1039 + garbage collections and the memory requirements for colamd. If any
153.1040 + argument is negative, or if integer overflow occurs, a 0 is returned as an
153.1041 + error condition. 2*nnz space is required for the row and column
153.1042 + indices of the matrix. COLAMD_C (n_col) + COLAMD_R (n_row) space is
153.1043 + required for the Col and Row arrays, respectively, which are internal to
153.1044 + colamd (roughly 6*n_col + 4*n_row). An additional n_col space is the
153.1045 + minimal amount of "elbow room", and nnz/5 more space is recommended for
153.1046 + run time efficiency.
153.1047 +
153.1048 + Alen is approximately 2.2*nnz + 7*n_col + 4*n_row + 10.
153.1049 +
153.1050 + This function is not needed when using symamd.
153.1051 +*/
153.1052 +
153.1053 +/* add two values of type size_t, and check for integer overflow */
153.1054 +static size_t t_add (size_t a, size_t b, int *ok)
153.1055 +{
153.1056 + (*ok) = (*ok) && ((a + b) >= MAX (a,b)) ;
153.1057 + return ((*ok) ? (a + b) : 0) ;
153.1058 +}
153.1059 +
153.1060 +/* compute a*k where k is a small integer, and check for integer overflow */
153.1061 +static size_t t_mult (size_t a, size_t k, int *ok)
153.1062 +{
153.1063 + size_t i, s = 0 ;
153.1064 + for (i = 0 ; i < k ; i++)
153.1065 + {
153.1066 + s = t_add (s, a, ok) ;
153.1067 + }
153.1068 + return (s) ;
153.1069 +}
153.1070 +
153.1071 +/* size of the Col and Row structures */
153.1072 +#define COLAMD_C(n_col,ok) \
153.1073 + ((t_mult (t_add (n_col, 1, ok), sizeof (Colamd_Col), ok) / sizeof (Int)))
153.1074 +
153.1075 +#define COLAMD_R(n_row,ok) \
153.1076 + ((t_mult (t_add (n_row, 1, ok), sizeof (Colamd_Row), ok) / sizeof (Int)))
153.1077 +
153.1078 +
153.1079 +PUBLIC size_t COLAMD_recommended /* returns recommended value of Alen. */
153.1080 +(
153.1081 + /* === Parameters ======================================================= */
153.1082 +
153.1083 + Int nnz, /* number of nonzeros in A */
153.1084 + Int n_row, /* number of rows in A */
153.1085 + Int n_col /* number of columns in A */
153.1086 +)
153.1087 +{
153.1088 + size_t s, c, r ;
153.1089 + int ok = TRUE ;
153.1090 + if (nnz < 0 || n_row < 0 || n_col < 0)
153.1091 + {
153.1092 + return (0) ;
153.1093 + }
153.1094 + s = t_mult (nnz, 2, &ok) ; /* 2*nnz */
153.1095 + c = COLAMD_C (n_col, &ok) ; /* size of column structures */
153.1096 + r = COLAMD_R (n_row, &ok) ; /* size of row structures */
153.1097 + s = t_add (s, c, &ok) ;
153.1098 + s = t_add (s, r, &ok) ;
153.1099 + s = t_add (s, n_col, &ok) ; /* elbow room */
153.1100 + s = t_add (s, nnz/5, &ok) ; /* elbow room */
153.1101 + ok = ok && (s < Int_MAX) ;
153.1102 + return (ok ? s : 0) ;
153.1103 +}
153.1104 +
153.1105 +
153.1106 +/* ========================================================================== */
153.1107 +/* === colamd_set_defaults ================================================== */
153.1108 +/* ========================================================================== */
153.1109 +
153.1110 +/*
153.1111 + The colamd_set_defaults routine sets the default values of the user-
153.1112 + controllable parameters for colamd and symamd:
153.1113 +
153.1114 + Colamd: rows with more than max (16, knobs [0] * sqrt (n_col))
153.1115 + entries are removed prior to ordering. Columns with more than
153.1116 + max (16, knobs [1] * sqrt (MIN (n_row,n_col))) entries are removed
153.1117 + prior to ordering, and placed last in the output column ordering.
153.1118 +
153.1119 + Symamd: Rows and columns with more than max (16, knobs [0] * sqrt (n))
153.1120 + entries are removed prior to ordering, and placed last in the
153.1121 + output ordering.
153.1122 +
153.1123 + knobs [0] dense row control
153.1124 +
153.1125 + knobs [1] dense column control
153.1126 +
153.1127 + knobs [2] if nonzero, do aggresive absorption
153.1128 +
153.1129 + knobs [3..19] unused, but future versions might use this
153.1130 +
153.1131 +*/
153.1132 +
153.1133 +PUBLIC void COLAMD_set_defaults
153.1134 +(
153.1135 + /* === Parameters ======================================================= */
153.1136 +
153.1137 + double knobs [COLAMD_KNOBS] /* knob array */
153.1138 +)
153.1139 +{
153.1140 + /* === Local variables ================================================== */
153.1141 +
153.1142 + Int i ;
153.1143 +
153.1144 + if (!knobs)
153.1145 + {
153.1146 + return ; /* no knobs to initialize */
153.1147 + }
153.1148 + for (i = 0 ; i < COLAMD_KNOBS ; i++)
153.1149 + {
153.1150 + knobs [i] = 0 ;
153.1151 + }
153.1152 + knobs [COLAMD_DENSE_ROW] = 10 ;
153.1153 + knobs [COLAMD_DENSE_COL] = 10 ;
153.1154 + knobs [COLAMD_AGGRESSIVE] = TRUE ; /* default: do aggressive absorption*/
153.1155 +}
153.1156 +
153.1157 +
153.1158 +/* ========================================================================== */
153.1159 +/* === symamd =============================================================== */
153.1160 +/* ========================================================================== */
153.1161 +
153.1162 +PUBLIC Int SYMAMD_MAIN /* return TRUE if OK, FALSE otherwise */
153.1163 +(
153.1164 + /* === Parameters ======================================================= */
153.1165 +
153.1166 + Int n, /* number of rows and columns of A */
153.1167 + Int A [], /* row indices of A */
153.1168 + Int p [], /* column pointers of A */
153.1169 + Int perm [], /* output permutation, size n+1 */
153.1170 + double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */
153.1171 + Int stats [COLAMD_STATS], /* output statistics and error codes */
153.1172 + void * (*allocate) (size_t, size_t),
153.1173 + /* pointer to calloc (ANSI C) or */
153.1174 + /* mxCalloc (for MATLAB mexFunction) */
153.1175 + void (*release) (void *)
153.1176 + /* pointer to free (ANSI C) or */
153.1177 + /* mxFree (for MATLAB mexFunction) */
153.1178 +)
153.1179 +{
153.1180 + /* === Local variables ================================================== */
153.1181 +
153.1182 + Int *count ; /* length of each column of M, and col pointer*/
153.1183 + Int *mark ; /* mark array for finding duplicate entries */
153.1184 + Int *M ; /* row indices of matrix M */
153.1185 + size_t Mlen ; /* length of M */
153.1186 + Int n_row ; /* number of rows in M */
153.1187 + Int nnz ; /* number of entries in A */
153.1188 + Int i ; /* row index of A */
153.1189 + Int j ; /* column index of A */
153.1190 + Int k ; /* row index of M */
153.1191 + Int mnz ; /* number of nonzeros in M */
153.1192 + Int pp ; /* index into a column of A */
153.1193 + Int last_row ; /* last row seen in the current column */
153.1194 + Int length ; /* number of nonzeros in a column */
153.1195 +
153.1196 + double cknobs [COLAMD_KNOBS] ; /* knobs for colamd */
153.1197 + double default_knobs [COLAMD_KNOBS] ; /* default knobs for colamd */
153.1198 +
153.1199 +#ifndef NDEBUG
153.1200 + colamd_get_debug ("symamd") ;
153.1201 +#endif /* NDEBUG */
153.1202 +
153.1203 + /* === Check the input arguments ======================================== */
153.1204 +
153.1205 + if (!stats)
153.1206 + {
153.1207 + DEBUG0 (("symamd: stats not present\n")) ;
153.1208 + return (FALSE) ;
153.1209 + }
153.1210 + for (i = 0 ; i < COLAMD_STATS ; i++)
153.1211 + {
153.1212 + stats [i] = 0 ;
153.1213 + }
153.1214 + stats [COLAMD_STATUS] = COLAMD_OK ;
153.1215 + stats [COLAMD_INFO1] = -1 ;
153.1216 + stats [COLAMD_INFO2] = -1 ;
153.1217 +
153.1218 + if (!A)
153.1219 + {
153.1220 + stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
153.1221 + DEBUG0 (("symamd: A not present\n")) ;
153.1222 + return (FALSE) ;
153.1223 + }
153.1224 +
153.1225 + if (!p) /* p is not present */
153.1226 + {
153.1227 + stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
153.1228 + DEBUG0 (("symamd: p not present\n")) ;
153.1229 + return (FALSE) ;
153.1230 + }
153.1231 +
153.1232 + if (n < 0) /* n must be >= 0 */
153.1233 + {
153.1234 + stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
153.1235 + stats [COLAMD_INFO1] = n ;
153.1236 + DEBUG0 (("symamd: n negative %d\n", n)) ;
153.1237 + return (FALSE) ;
153.1238 + }
153.1239 +
153.1240 + nnz = p [n] ;
153.1241 + if (nnz < 0) /* nnz must be >= 0 */
153.1242 + {
153.1243 + stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
153.1244 + stats [COLAMD_INFO1] = nnz ;
153.1245 + DEBUG0 (("symamd: number of entries negative %d\n", nnz)) ;
153.1246 + return (FALSE) ;
153.1247 + }
153.1248 +
153.1249 + if (p [0] != 0)
153.1250 + {
153.1251 + stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ;
153.1252 + stats [COLAMD_INFO1] = p [0] ;
153.1253 + DEBUG0 (("symamd: p[0] not zero %d\n", p [0])) ;
153.1254 + return (FALSE) ;
153.1255 + }
153.1256 +
153.1257 + /* === If no knobs, set default knobs =================================== */
153.1258 +
153.1259 + if (!knobs)
153.1260 + {
153.1261 + COLAMD_set_defaults (default_knobs) ;
153.1262 + knobs = default_knobs ;
153.1263 + }
153.1264 +
153.1265 + /* === Allocate count and mark ========================================== */
153.1266 +
153.1267 + count = (Int *) ((*allocate) (n+1, sizeof (Int))) ;
153.1268 + if (!count)
153.1269 + {
153.1270 + stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
153.1271 + DEBUG0 (("symamd: allocate count (size %d) failed\n", n+1)) ;
153.1272 + return (FALSE) ;
153.1273 + }
153.1274 +
153.1275 + mark = (Int *) ((*allocate) (n+1, sizeof (Int))) ;
153.1276 + if (!mark)
153.1277 + {
153.1278 + stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
153.1279 + (*release) ((void *) count) ;
153.1280 + DEBUG0 (("symamd: allocate mark (size %d) failed\n", n+1)) ;
153.1281 + return (FALSE) ;
153.1282 + }
153.1283 +
153.1284 + /* === Compute column counts of M, check if A is valid ================== */
153.1285 +
153.1286 + stats [COLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/
153.1287 +
153.1288 + for (i = 0 ; i < n ; i++)
153.1289 + {
153.1290 + mark [i] = -1 ;
153.1291 + }
153.1292 +
153.1293 + for (j = 0 ; j < n ; j++)
153.1294 + {
153.1295 + last_row = -1 ;
153.1296 +
153.1297 + length = p [j+1] - p [j] ;
153.1298 + if (length < 0)
153.1299 + {
153.1300 + /* column pointers must be non-decreasing */
153.1301 + stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
153.1302 + stats [COLAMD_INFO1] = j ;
153.1303 + stats [COLAMD_INFO2] = length ;
153.1304 + (*release) ((void *) count) ;
153.1305 + (*release) ((void *) mark) ;
153.1306 + DEBUG0 (("symamd: col %d negative length %d\n", j, length)) ;
153.1307 + return (FALSE) ;
153.1308 + }
153.1309 +
153.1310 + for (pp = p [j] ; pp < p [j+1] ; pp++)
153.1311 + {
153.1312 + i = A [pp] ;
153.1313 + if (i < 0 || i >= n)
153.1314 + {
153.1315 + /* row index i, in column j, is out of bounds */
153.1316 + stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
153.1317 + stats [COLAMD_INFO1] = j ;
153.1318 + stats [COLAMD_INFO2] = i ;
153.1319 + stats [COLAMD_INFO3] = n ;
153.1320 + (*release) ((void *) count) ;
153.1321 + (*release) ((void *) mark) ;
153.1322 + DEBUG0 (("symamd: row %d col %d out of bounds\n", i, j)) ;
153.1323 + return (FALSE) ;
153.1324 + }
153.1325 +
153.1326 + if (i <= last_row || mark [i] == j)
153.1327 + {
153.1328 + /* row index is unsorted or repeated (or both), thus col */
153.1329 + /* is jumbled. This is a notice, not an error condition. */
153.1330 + stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ;
153.1331 + stats [COLAMD_INFO1] = j ;
153.1332 + stats [COLAMD_INFO2] = i ;
153.1333 + (stats [COLAMD_INFO3]) ++ ;
153.1334 + DEBUG1 (("symamd: row %d col %d unsorted/duplicate\n", i, j)) ;
153.1335 + }
153.1336 +
153.1337 + if (i > j && mark [i] != j)
153.1338 + {
153.1339 + /* row k of M will contain column indices i and j */
153.1340 + count [i]++ ;
153.1341 + count [j]++ ;
153.1342 + }
153.1343 +
153.1344 + /* mark the row as having been seen in this column */
153.1345 + mark [i] = j ;
153.1346 +
153.1347 + last_row = i ;
153.1348 + }
153.1349 + }
153.1350 +
153.1351 + /* v2.4: removed free(mark) */
153.1352 +
153.1353 + /* === Compute column pointers of M ===================================== */
153.1354 +
153.1355 + /* use output permutation, perm, for column pointers of M */
153.1356 + perm [0] = 0 ;
153.1357 + for (j = 1 ; j <= n ; j++)
153.1358 + {
153.1359 + perm [j] = perm [j-1] + count [j-1] ;
153.1360 + }
153.1361 + for (j = 0 ; j < n ; j++)
153.1362 + {
153.1363 + count [j] = perm [j] ;
153.1364 + }
153.1365 +
153.1366 + /* === Construct M ====================================================== */
153.1367 +
153.1368 + mnz = perm [n] ;
153.1369 + n_row = mnz / 2 ;
153.1370 + Mlen = COLAMD_recommended (mnz, n_row, n) ;
153.1371 + M = (Int *) ((*allocate) (Mlen, sizeof (Int))) ;
153.1372 + DEBUG0 (("symamd: M is %d-by-%d with %d entries, Mlen = %g\n",
153.1373 + n_row, n, mnz, (double) Mlen)) ;
153.1374 +
153.1375 + if (!M)
153.1376 + {
153.1377 + stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
153.1378 + (*release) ((void *) count) ;
153.1379 + (*release) ((void *) mark) ;
153.1380 + DEBUG0 (("symamd: allocate M (size %g) failed\n", (double) Mlen)) ;
153.1381 + return (FALSE) ;
153.1382 + }
153.1383 +
153.1384 + k = 0 ;
153.1385 +
153.1386 + if (stats [COLAMD_STATUS] == COLAMD_OK)
153.1387 + {
153.1388 + /* Matrix is OK */
153.1389 + for (j = 0 ; j < n ; j++)
153.1390 + {
153.1391 + ASSERT (p [j+1] - p [j] >= 0) ;
153.1392 + for (pp = p [j] ; pp < p [j+1] ; pp++)
153.1393 + {
153.1394 + i = A [pp] ;
153.1395 + ASSERT (i >= 0 && i < n) ;
153.1396 + if (i > j)
153.1397 + {
153.1398 + /* row k of M contains column indices i and j */
153.1399 + M [count [i]++] = k ;
153.1400 + M [count [j]++] = k ;
153.1401 + k++ ;
153.1402 + }
153.1403 + }
153.1404 + }
153.1405 + }
153.1406 + else
153.1407 + {
153.1408 + /* Matrix is jumbled. Do not add duplicates to M. Unsorted cols OK. */
153.1409 + DEBUG0 (("symamd: Duplicates in A.\n")) ;
153.1410 + for (i = 0 ; i < n ; i++)
153.1411 + {
153.1412 + mark [i] = -1 ;
153.1413 + }
153.1414 + for (j = 0 ; j < n ; j++)
153.1415 + {
153.1416 + ASSERT (p [j+1] - p [j] >= 0) ;
153.1417 + for (pp = p [j] ; pp < p [j+1] ; pp++)
153.1418 + {
153.1419 + i = A [pp] ;
153.1420 + ASSERT (i >= 0 && i < n) ;
153.1421 + if (i > j && mark [i] != j)
153.1422 + {
153.1423 + /* row k of M contains column indices i and j */
153.1424 + M [count [i]++] = k ;
153.1425 + M [count [j]++] = k ;
153.1426 + k++ ;
153.1427 + mark [i] = j ;
153.1428 + }
153.1429 + }
153.1430 + }
153.1431 + /* v2.4: free(mark) moved below */
153.1432 + }
153.1433 +
153.1434 + /* count and mark no longer needed */
153.1435 + (*release) ((void *) count) ;
153.1436 + (*release) ((void *) mark) ; /* v2.4: free (mark) moved here */
153.1437 + ASSERT (k == n_row) ;
153.1438 +
153.1439 + /* === Adjust the knobs for M =========================================== */
153.1440 +
153.1441 + for (i = 0 ; i < COLAMD_KNOBS ; i++)
153.1442 + {
153.1443 + cknobs [i] = knobs [i] ;
153.1444 + }
153.1445 +
153.1446 + /* there are no dense rows in M */
153.1447 + cknobs [COLAMD_DENSE_ROW] = -1 ;
153.1448 + cknobs [COLAMD_DENSE_COL] = knobs [COLAMD_DENSE_ROW] ;
153.1449 +
153.1450 + /* === Order the columns of M =========================================== */
153.1451 +
153.1452 + /* v2.4: colamd cannot fail here, so the error check is removed */
153.1453 + (void) COLAMD_MAIN (n_row, n, (Int) Mlen, M, perm, cknobs, stats) ;
153.1454 +
153.1455 + /* Note that the output permutation is now in perm */
153.1456 +
153.1457 + /* === get the statistics for symamd from colamd ======================== */
153.1458 +
153.1459 + /* a dense column in colamd means a dense row and col in symamd */
153.1460 + stats [COLAMD_DENSE_ROW] = stats [COLAMD_DENSE_COL] ;
153.1461 +
153.1462 + /* === Free M =========================================================== */
153.1463 +
153.1464 + (*release) ((void *) M) ;
153.1465 + DEBUG0 (("symamd: done.\n")) ;
153.1466 + return (TRUE) ;
153.1467 +
153.1468 +}
153.1469 +
153.1470 +/* ========================================================================== */
153.1471 +/* === colamd =============================================================== */
153.1472 +/* ========================================================================== */
153.1473 +
153.1474 +/*
153.1475 + The colamd routine computes a column ordering Q of a sparse matrix
153.1476 + A such that the LU factorization P(AQ) = LU remains sparse, where P is
153.1477 + selected via partial pivoting. The routine can also be viewed as
153.1478 + providing a permutation Q such that the Cholesky factorization
153.1479 + (AQ)'(AQ) = LL' remains sparse.
153.1480 +*/
153.1481 +
153.1482 +PUBLIC Int COLAMD_MAIN /* returns TRUE if successful, FALSE otherwise*/
153.1483 +(
153.1484 + /* === Parameters ======================================================= */
153.1485 +
153.1486 + Int n_row, /* number of rows in A */
153.1487 + Int n_col, /* number of columns in A */
153.1488 + Int Alen, /* length of A */
153.1489 + Int A [], /* row indices of A */
153.1490 + Int p [], /* pointers to columns in A */
153.1491 + double knobs [COLAMD_KNOBS],/* parameters (uses defaults if NULL) */
153.1492 + Int stats [COLAMD_STATS] /* output statistics and error codes */
153.1493 +)
153.1494 +{
153.1495 + /* === Local variables ================================================== */
153.1496 +
153.1497 + Int i ; /* loop index */
153.1498 + Int nnz ; /* nonzeros in A */
153.1499 + size_t Row_size ; /* size of Row [], in integers */
153.1500 + size_t Col_size ; /* size of Col [], in integers */
153.1501 + size_t need ; /* minimum required length of A */
153.1502 + Colamd_Row *Row ; /* pointer into A of Row [0..n_row] array */
153.1503 + Colamd_Col *Col ; /* pointer into A of Col [0..n_col] array */
153.1504 + Int n_col2 ; /* number of non-dense, non-empty columns */
153.1505 + Int n_row2 ; /* number of non-dense, non-empty rows */
153.1506 + Int ngarbage ; /* number of garbage collections performed */
153.1507 + Int max_deg ; /* maximum row degree */
153.1508 + double default_knobs [COLAMD_KNOBS] ; /* default knobs array */
153.1509 + Int aggressive ; /* do aggressive absorption */
153.1510 + int ok ;
153.1511 +
153.1512 +#ifndef NDEBUG
153.1513 + colamd_get_debug ("colamd") ;
153.1514 +#endif /* NDEBUG */
153.1515 +
153.1516 + /* === Check the input arguments ======================================== */
153.1517 +
153.1518 + if (!stats)
153.1519 + {
153.1520 + DEBUG0 (("colamd: stats not present\n")) ;
153.1521 + return (FALSE) ;
153.1522 + }
153.1523 + for (i = 0 ; i < COLAMD_STATS ; i++)
153.1524 + {
153.1525 + stats [i] = 0 ;
153.1526 + }
153.1527 + stats [COLAMD_STATUS] = COLAMD_OK ;
153.1528 + stats [COLAMD_INFO1] = -1 ;
153.1529 + stats [COLAMD_INFO2] = -1 ;
153.1530 +
153.1531 + if (!A) /* A is not present */
153.1532 + {
153.1533 + stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
153.1534 + DEBUG0 (("colamd: A not present\n")) ;
153.1535 + return (FALSE) ;
153.1536 + }
153.1537 +
153.1538 + if (!p) /* p is not present */
153.1539 + {
153.1540 + stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
153.1541 + DEBUG0 (("colamd: p not present\n")) ;
153.1542 + return (FALSE) ;
153.1543 + }
153.1544 +
153.1545 + if (n_row < 0) /* n_row must be >= 0 */
153.1546 + {
153.1547 + stats [COLAMD_STATUS] = COLAMD_ERROR_nrow_negative ;
153.1548 + stats [COLAMD_INFO1] = n_row ;
153.1549 + DEBUG0 (("colamd: nrow negative %d\n", n_row)) ;
153.1550 + return (FALSE) ;
153.1551 + }
153.1552 +
153.1553 + if (n_col < 0) /* n_col must be >= 0 */
153.1554 + {
153.1555 + stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
153.1556 + stats [COLAMD_INFO1] = n_col ;
153.1557 + DEBUG0 (("colamd: ncol negative %d\n", n_col)) ;
153.1558 + return (FALSE) ;
153.1559 + }
153.1560 +
153.1561 + nnz = p [n_col] ;
153.1562 + if (nnz < 0) /* nnz must be >= 0 */
153.1563 + {
153.1564 + stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
153.1565 + stats [COLAMD_INFO1] = nnz ;
153.1566 + DEBUG0 (("colamd: number of entries negative %d\n", nnz)) ;
153.1567 + return (FALSE) ;
153.1568 + }
153.1569 +
153.1570 + if (p [0] != 0)
153.1571 + {
153.1572 + stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ;
153.1573 + stats [COLAMD_INFO1] = p [0] ;
153.1574 + DEBUG0 (("colamd: p[0] not zero %d\n", p [0])) ;
153.1575 + return (FALSE) ;
153.1576 + }
153.1577 +
153.1578 + /* === If no knobs, set default knobs =================================== */
153.1579 +
153.1580 + if (!knobs)
153.1581 + {
153.1582 + COLAMD_set_defaults (default_knobs) ;
153.1583 + knobs = default_knobs ;
153.1584 + }
153.1585 +
153.1586 + aggressive = (knobs [COLAMD_AGGRESSIVE] != FALSE) ;
153.1587 +
153.1588 + /* === Allocate the Row and Col arrays from array A ===================== */
153.1589 +
153.1590 + ok = TRUE ;
153.1591 + Col_size = COLAMD_C (n_col, &ok) ; /* size of Col array of structs */
153.1592 + Row_size = COLAMD_R (n_row, &ok) ; /* size of Row array of structs */
153.1593 +
153.1594 + /* need = 2*nnz + n_col + Col_size + Row_size ; */
153.1595 + need = t_mult (nnz, 2, &ok) ;
153.1596 + need = t_add (need, n_col, &ok) ;
153.1597 + need = t_add (need, Col_size, &ok) ;
153.1598 + need = t_add (need, Row_size, &ok) ;
153.1599 +
153.1600 + if (!ok || need > (size_t) Alen || need > Int_MAX)
153.1601 + {
153.1602 + /* not enough space in array A to perform the ordering */
153.1603 + stats [COLAMD_STATUS] = COLAMD_ERROR_A_too_small ;
153.1604 + stats [COLAMD_INFO1] = need ;
153.1605 + stats [COLAMD_INFO2] = Alen ;
153.1606 + DEBUG0 (("colamd: Need Alen >= %d, given only Alen = %d\n", need,Alen));
153.1607 + return (FALSE) ;
153.1608 + }
153.1609 +
153.1610 + Alen -= Col_size + Row_size ;
153.1611 + Col = (Colamd_Col *) &A [Alen] ;
153.1612 + Row = (Colamd_Row *) &A [Alen + Col_size] ;
153.1613 +
153.1614 + /* === Construct the row and column data structures ===================== */
153.1615 +
153.1616 + if (!init_rows_cols (n_row, n_col, Row, Col, A, p, stats))
153.1617 + {
153.1618 + /* input matrix is invalid */
153.1619 + DEBUG0 (("colamd: Matrix invalid\n")) ;
153.1620 + return (FALSE) ;
153.1621 + }
153.1622 +
153.1623 + /* === Initialize scores, kill dense rows/columns ======================= */
153.1624 +
153.1625 + init_scoring (n_row, n_col, Row, Col, A, p, knobs,
153.1626 + &n_row2, &n_col2, &max_deg) ;
153.1627 +
153.1628 + /* === Order the supercolumns =========================================== */
153.1629 +
153.1630 + ngarbage = find_ordering (n_row, n_col, Alen, Row, Col, A, p,
153.1631 + n_col2, max_deg, 2*nnz, aggressive) ;
153.1632 +
153.1633 + /* === Order the non-principal columns ================================== */
153.1634 +
153.1635 + order_children (n_col, Col, p) ;
153.1636 +
153.1637 + /* === Return statistics in stats ======================================= */
153.1638 +
153.1639 + stats [COLAMD_DENSE_ROW] = n_row - n_row2 ;
153.1640 + stats [COLAMD_DENSE_COL] = n_col - n_col2 ;
153.1641 + stats [COLAMD_DEFRAG_COUNT] = ngarbage ;
153.1642 + DEBUG0 (("colamd: done.\n")) ;
153.1643 + return (TRUE) ;
153.1644 +}
153.1645 +
153.1646 +
153.1647 +/* ========================================================================== */
153.1648 +/* === colamd_report ======================================================== */
153.1649 +/* ========================================================================== */
153.1650 +
153.1651 +PUBLIC void COLAMD_report
153.1652 +(
153.1653 + Int stats [COLAMD_STATS]
153.1654 +)
153.1655 +{
153.1656 + print_report ("colamd", stats) ;
153.1657 +}
153.1658 +
153.1659 +
153.1660 +/* ========================================================================== */
153.1661 +/* === symamd_report ======================================================== */
153.1662 +/* ========================================================================== */
153.1663 +
153.1664 +PUBLIC void SYMAMD_report
153.1665 +(
153.1666 + Int stats [COLAMD_STATS]
153.1667 +)
153.1668 +{
153.1669 + print_report ("symamd", stats) ;
153.1670 +}
153.1671 +
153.1672 +
153.1673 +
153.1674 +/* ========================================================================== */
153.1675 +/* === NON-USER-CALLABLE ROUTINES: ========================================== */
153.1676 +/* ========================================================================== */
153.1677 +
153.1678 +/* There are no user-callable routines beyond this point in the file */
153.1679 +
153.1680 +
153.1681 +/* ========================================================================== */
153.1682 +/* === init_rows_cols ======================================================= */
153.1683 +/* ========================================================================== */
153.1684 +
153.1685 +/*
153.1686 + Takes the column form of the matrix in A and creates the row form of the
153.1687 + matrix. Also, row and column attributes are stored in the Col and Row
153.1688 + structs. If the columns are un-sorted or contain duplicate row indices,
153.1689 + this routine will also sort and remove duplicate row indices from the
153.1690 + column form of the matrix. Returns FALSE if the matrix is invalid,
153.1691 + TRUE otherwise. Not user-callable.
153.1692 +*/
153.1693 +
153.1694 +PRIVATE Int init_rows_cols /* returns TRUE if OK, or FALSE otherwise */
153.1695 +(
153.1696 + /* === Parameters ======================================================= */
153.1697 +
153.1698 + Int n_row, /* number of rows of A */
153.1699 + Int n_col, /* number of columns of A */
153.1700 + Colamd_Row Row [], /* of size n_row+1 */
153.1701 + Colamd_Col Col [], /* of size n_col+1 */
153.1702 + Int A [], /* row indices of A, of size Alen */
153.1703 + Int p [], /* pointers to columns in A, of size n_col+1 */
153.1704 + Int stats [COLAMD_STATS] /* colamd statistics */
153.1705 +)
153.1706 +{
153.1707 + /* === Local variables ================================================== */
153.1708 +
153.1709 + Int col ; /* a column index */
153.1710 + Int row ; /* a row index */
153.1711 + Int *cp ; /* a column pointer */
153.1712 + Int *cp_end ; /* a pointer to the end of a column */
153.1713 + Int *rp ; /* a row pointer */
153.1714 + Int *rp_end ; /* a pointer to the end of a row */
153.1715 + Int last_row ; /* previous row */
153.1716 +
153.1717 + /* === Initialize columns, and check column pointers ==================== */
153.1718 +
153.1719 + for (col = 0 ; col < n_col ; col++)
153.1720 + {
153.1721 + Col [col].start = p [col] ;
153.1722 + Col [col].length = p [col+1] - p [col] ;
153.1723 +
153.1724 + if (Col [col].length < 0)
153.1725 + {
153.1726 + /* column pointers must be non-decreasing */
153.1727 + stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
153.1728 + stats [COLAMD_INFO1] = col ;
153.1729 + stats [COLAMD_INFO2] = Col [col].length ;
153.1730 + DEBUG0 (("colamd: col %d length %d < 0\n", col, Col [col].length)) ;
153.1731 + return (FALSE) ;
153.1732 + }
153.1733 +
153.1734 + Col [col].shared1.thickness = 1 ;
153.1735 + Col [col].shared2.score = 0 ;
153.1736 + Col [col].shared3.prev = EMPTY ;
153.1737 + Col [col].shared4.degree_next = EMPTY ;
153.1738 + }
153.1739 +
153.1740 + /* p [0..n_col] no longer needed, used as "head" in subsequent routines */
153.1741 +
153.1742 + /* === Scan columns, compute row degrees, and check row indices ========= */
153.1743 +
153.1744 + stats [COLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/
153.1745 +
153.1746 + for (row = 0 ; row < n_row ; row++)
153.1747 + {
153.1748 + Row [row].length = 0 ;
153.1749 + Row [row].shared2.mark = -1 ;
153.1750 + }
153.1751 +
153.1752 + for (col = 0 ; col < n_col ; col++)
153.1753 + {
153.1754 + last_row = -1 ;
153.1755 +
153.1756 + cp = &A [p [col]] ;
153.1757 + cp_end = &A [p [col+1]] ;
153.1758 +
153.1759 + while (cp < cp_end)
153.1760 + {
153.1761 + row = *cp++ ;
153.1762 +
153.1763 + /* make sure row indices within range */
153.1764 + if (row < 0 || row >= n_row)
153.1765 + {
153.1766 + stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
153.1767 + stats [COLAMD_INFO1] = col ;
153.1768 + stats [COLAMD_INFO2] = row ;
153.1769 + stats [COLAMD_INFO3] = n_row ;
153.1770 + DEBUG0 (("colamd: row %d col %d out of bounds\n", row, col)) ;
153.1771 + return (FALSE) ;
153.1772 + }
153.1773 +
153.1774 + if (row <= last_row || Row [row].shared2.mark == col)
153.1775 + {
153.1776 + /* row index are unsorted or repeated (or both), thus col */
153.1777 + /* is jumbled. This is a notice, not an error condition. */
153.1778 + stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ;
153.1779 + stats [COLAMD_INFO1] = col ;
153.1780 + stats [COLAMD_INFO2] = row ;
153.1781 + (stats [COLAMD_INFO3]) ++ ;
153.1782 + DEBUG1 (("colamd: row %d col %d unsorted/duplicate\n",row,col));
153.1783 + }
153.1784 +
153.1785 + if (Row [row].shared2.mark != col)
153.1786 + {
153.1787 + Row [row].length++ ;
153.1788 + }
153.1789 + else
153.1790 + {
153.1791 + /* this is a repeated entry in the column, */
153.1792 + /* it will be removed */
153.1793 + Col [col].length-- ;
153.1794 + }
153.1795 +
153.1796 + /* mark the row as having been seen in this column */
153.1797 + Row [row].shared2.mark = col ;
153.1798 +
153.1799 + last_row = row ;
153.1800 + }
153.1801 + }
153.1802 +
153.1803 + /* === Compute row pointers ============================================= */
153.1804 +
153.1805 + /* row form of the matrix starts directly after the column */
153.1806 + /* form of matrix in A */
153.1807 + Row [0].start = p [n_col] ;
153.1808 + Row [0].shared1.p = Row [0].start ;
153.1809 + Row [0].shared2.mark = -1 ;
153.1810 + for (row = 1 ; row < n_row ; row++)
153.1811 + {
153.1812 + Row [row].start = Row [row-1].start + Row [row-1].length ;
153.1813 + Row [row].shared1.p = Row [row].start ;
153.1814 + Row [row].shared2.mark = -1 ;
153.1815 + }
153.1816 +
153.1817 + /* === Create row form ================================================== */
153.1818 +
153.1819 + if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
153.1820 + {
153.1821 + /* if cols jumbled, watch for repeated row indices */
153.1822 + for (col = 0 ; col < n_col ; col++)
153.1823 + {
153.1824 + cp = &A [p [col]] ;
153.1825 + cp_end = &A [p [col+1]] ;
153.1826 + while (cp < cp_end)
153.1827 + {
153.1828 + row = *cp++ ;
153.1829 + if (Row [row].shared2.mark != col)
153.1830 + {
153.1831 + A [(Row [row].shared1.p)++] = col ;
153.1832 + Row [row].shared2.mark = col ;
153.1833 + }
153.1834 + }
153.1835 + }
153.1836 + }
153.1837 + else
153.1838 + {
153.1839 + /* if cols not jumbled, we don't need the mark (this is faster) */
153.1840 + for (col = 0 ; col < n_col ; col++)
153.1841 + {
153.1842 + cp = &A [p [col]] ;
153.1843 + cp_end = &A [p [col+1]] ;
153.1844 + while (cp < cp_end)
153.1845 + {
153.1846 + A [(Row [*cp++].shared1.p)++] = col ;
153.1847 + }
153.1848 + }
153.1849 + }
153.1850 +
153.1851 + /* === Clear the row marks and set row degrees ========================== */
153.1852 +
153.1853 + for (row = 0 ; row < n_row ; row++)
153.1854 + {
153.1855 + Row [row].shared2.mark = 0 ;
153.1856 + Row [row].shared1.degree = Row [row].length ;
153.1857 + }
153.1858 +
153.1859 + /* === See if we need to re-create columns ============================== */
153.1860 +
153.1861 + if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
153.1862 + {
153.1863 + DEBUG0 (("colamd: reconstructing column form, matrix jumbled\n")) ;
153.1864 +
153.1865 +#ifndef NDEBUG
153.1866 + /* make sure column lengths are correct */
153.1867 + for (col = 0 ; col < n_col ; col++)
153.1868 + {
153.1869 + p [col] = Col [col].length ;
153.1870 + }
153.1871 + for (row = 0 ; row < n_row ; row++)
153.1872 + {
153.1873 + rp = &A [Row [row].start] ;
153.1874 + rp_end = rp + Row [row].length ;
153.1875 + while (rp < rp_end)
153.1876 + {
153.1877 + p [*rp++]-- ;
153.1878 + }
153.1879 + }
153.1880 + for (col = 0 ; col < n_col ; col++)
153.1881 + {
153.1882 + ASSERT (p [col] == 0) ;
153.1883 + }
153.1884 + /* now p is all zero (different than when debugging is turned off) */
153.1885 +#endif /* NDEBUG */
153.1886 +
153.1887 + /* === Compute col pointers ========================================= */
153.1888 +
153.1889 + /* col form of the matrix starts at A [0]. */
153.1890 + /* Note, we may have a gap between the col form and the row */
153.1891 + /* form if there were duplicate entries, if so, it will be */
153.1892 + /* removed upon the first garbage collection */
153.1893 + Col [0].start = 0 ;
153.1894 + p [0] = Col [0].start ;
153.1895 + for (col = 1 ; col < n_col ; col++)
153.1896 + {
153.1897 + /* note that the lengths here are for pruned columns, i.e. */
153.1898 + /* no duplicate row indices will exist for these columns */
153.1899 + Col [col].start = Col [col-1].start + Col [col-1].length ;
153.1900 + p [col] = Col [col].start ;
153.1901 + }
153.1902 +
153.1903 + /* === Re-create col form =========================================== */
153.1904 +
153.1905 + for (row = 0 ; row < n_row ; row++)
153.1906 + {
153.1907 + rp = &A [Row [row].start] ;
153.1908 + rp_end = rp + Row [row].length ;
153.1909 + while (rp < rp_end)
153.1910 + {
153.1911 + A [(p [*rp++])++] = row ;
153.1912 + }
153.1913 + }
153.1914 + }
153.1915 +
153.1916 + /* === Done. Matrix is not (or no longer) jumbled ====================== */
153.1917 +
153.1918 + return (TRUE) ;
153.1919 +}
153.1920 +
153.1921 +
153.1922 +/* ========================================================================== */
153.1923 +/* === init_scoring ========================================================= */
153.1924 +/* ========================================================================== */
153.1925 +
153.1926 +/*
153.1927 + Kills dense or empty columns and rows, calculates an initial score for
153.1928 + each column, and places all columns in the degree lists. Not user-callable.
153.1929 +*/
153.1930 +
153.1931 +PRIVATE void init_scoring
153.1932 +(
153.1933 + /* === Parameters ======================================================= */
153.1934 +
153.1935 + Int n_row, /* number of rows of A */
153.1936 + Int n_col, /* number of columns of A */
153.1937 + Colamd_Row Row [], /* of size n_row+1 */
153.1938 + Colamd_Col Col [], /* of size n_col+1 */
153.1939 + Int A [], /* column form and row form of A */
153.1940 + Int head [], /* of size n_col+1 */
153.1941 + double knobs [COLAMD_KNOBS],/* parameters */
153.1942 + Int *p_n_row2, /* number of non-dense, non-empty rows */
153.1943 + Int *p_n_col2, /* number of non-dense, non-empty columns */
153.1944 + Int *p_max_deg /* maximum row degree */
153.1945 +)
153.1946 +{
153.1947 + /* === Local variables ================================================== */
153.1948 +
153.1949 + Int c ; /* a column index */
153.1950 + Int r, row ; /* a row index */
153.1951 + Int *cp ; /* a column pointer */
153.1952 + Int deg ; /* degree of a row or column */
153.1953 + Int *cp_end ; /* a pointer to the end of a column */
153.1954 + Int *new_cp ; /* new column pointer */
153.1955 + Int col_length ; /* length of pruned column */
153.1956 + Int score ; /* current column score */
153.1957 + Int n_col2 ; /* number of non-dense, non-empty columns */
153.1958 + Int n_row2 ; /* number of non-dense, non-empty rows */
153.1959 + Int dense_row_count ; /* remove rows with more entries than this */
153.1960 + Int dense_col_count ; /* remove cols with more entries than this */
153.1961 + Int min_score ; /* smallest column score */
153.1962 + Int max_deg ; /* maximum row degree */
153.1963 + Int next_col ; /* Used to add to degree list.*/
153.1964 +
153.1965 +#ifndef NDEBUG
153.1966 + Int debug_count ; /* debug only. */
153.1967 +#endif /* NDEBUG */
153.1968 +
153.1969 + /* === Extract knobs ==================================================== */
153.1970 +
153.1971 + /* Note: if knobs contains a NaN, this is undefined: */
153.1972 + if (knobs [COLAMD_DENSE_ROW] < 0)
153.1973 + {
153.1974 + /* only remove completely dense rows */
153.1975 + dense_row_count = n_col-1 ;
153.1976 + }
153.1977 + else
153.1978 + {
153.1979 + dense_row_count = DENSE_DEGREE (knobs [COLAMD_DENSE_ROW], n_col) ;
153.1980 + }
153.1981 + if (knobs [COLAMD_DENSE_COL] < 0)
153.1982 + {
153.1983 + /* only remove completely dense columns */
153.1984 + dense_col_count = n_row-1 ;
153.1985 + }
153.1986 + else
153.1987 + {
153.1988 + dense_col_count =
153.1989 + DENSE_DEGREE (knobs [COLAMD_DENSE_COL], MIN (n_row, n_col)) ;
153.1990 + }
153.1991 +
153.1992 + DEBUG1 (("colamd: densecount: %d %d\n", dense_row_count, dense_col_count)) ;
153.1993 + max_deg = 0 ;
153.1994 + n_col2 = n_col ;
153.1995 + n_row2 = n_row ;
153.1996 +
153.1997 + /* === Kill empty columns =============================================== */
153.1998 +
153.1999 + /* Put the empty columns at the end in their natural order, so that LU */
153.2000 + /* factorization can proceed as far as possible. */
153.2001 + for (c = n_col-1 ; c >= 0 ; c--)
153.2002 + {
153.2003 + deg = Col [c].length ;
153.2004 + if (deg == 0)
153.2005 + {
153.2006 + /* this is a empty column, kill and order it last */
153.2007 + Col [c].shared2.order = --n_col2 ;
153.2008 + KILL_PRINCIPAL_COL (c) ;
153.2009 + }
153.2010 + }
153.2011 + DEBUG1 (("colamd: null columns killed: %d\n", n_col - n_col2)) ;
153.2012 +
153.2013 + /* === Kill dense columns =============================================== */
153.2014 +
153.2015 + /* Put the dense columns at the end, in their natural order */
153.2016 + for (c = n_col-1 ; c >= 0 ; c--)
153.2017 + {
153.2018 + /* skip any dead columns */
153.2019 + if (COL_IS_DEAD (c))
153.2020 + {
153.2021 + continue ;
153.2022 + }
153.2023 + deg = Col [c].length ;
153.2024 + if (deg > dense_col_count)
153.2025 + {
153.2026 + /* this is a dense column, kill and order it last */
153.2027 + Col [c].shared2.order = --n_col2 ;
153.2028 + /* decrement the row degrees */
153.2029 + cp = &A [Col [c].start] ;
153.2030 + cp_end = cp + Col [c].length ;
153.2031 + while (cp < cp_end)
153.2032 + {
153.2033 + Row [*cp++].shared1.degree-- ;
153.2034 + }
153.2035 + KILL_PRINCIPAL_COL (c) ;
153.2036 + }
153.2037 + }
153.2038 + DEBUG1 (("colamd: Dense and null columns killed: %d\n", n_col - n_col2)) ;
153.2039 +
153.2040 + /* === Kill dense and empty rows ======================================== */
153.2041 +
153.2042 + for (r = 0 ; r < n_row ; r++)
153.2043 + {
153.2044 + deg = Row [r].shared1.degree ;
153.2045 + ASSERT (deg >= 0 && deg <= n_col) ;
153.2046 + if (deg > dense_row_count || deg == 0)
153.2047 + {
153.2048 + /* kill a dense or empty row */
153.2049 + KILL_ROW (r) ;
153.2050 + --n_row2 ;
153.2051 + }
153.2052 + else
153.2053 + {
153.2054 + /* keep track of max degree of remaining rows */
153.2055 + max_deg = MAX (max_deg, deg) ;
153.2056 + }
153.2057 + }
153.2058 + DEBUG1 (("colamd: Dense and null rows killed: %d\n", n_row - n_row2)) ;
153.2059 +
153.2060 + /* === Compute initial column scores ==================================== */
153.2061 +
153.2062 + /* At this point the row degrees are accurate. They reflect the number */
153.2063 + /* of "live" (non-dense) columns in each row. No empty rows exist. */
153.2064 + /* Some "live" columns may contain only dead rows, however. These are */
153.2065 + /* pruned in the code below. */
153.2066 +
153.2067 + /* now find the initial matlab score for each column */
153.2068 + for (c = n_col-1 ; c >= 0 ; c--)
153.2069 + {
153.2070 + /* skip dead column */
153.2071 + if (COL_IS_DEAD (c))
153.2072 + {
153.2073 + continue ;
153.2074 + }
153.2075 + score = 0 ;
153.2076 + cp = &A [Col [c].start] ;
153.2077 + new_cp = cp ;
153.2078 + cp_end = cp + Col [c].length ;
153.2079 + while (cp < cp_end)
153.2080 + {
153.2081 + /* get a row */
153.2082 + row = *cp++ ;
153.2083 + /* skip if dead */
153.2084 + if (ROW_IS_DEAD (row))
153.2085 + {
153.2086 + continue ;
153.2087 + }
153.2088 + /* compact the column */
153.2089 + *new_cp++ = row ;
153.2090 + /* add row's external degree */
153.2091 + score += Row [row].shared1.degree - 1 ;
153.2092 + /* guard against integer overflow */
153.2093 + score = MIN (score, n_col) ;
153.2094 + }
153.2095 + /* determine pruned column length */
153.2096 + col_length = (Int) (new_cp - &A [Col [c].start]) ;
153.2097 + if (col_length == 0)
153.2098 + {
153.2099 + /* a newly-made null column (all rows in this col are "dense" */
153.2100 + /* and have already been killed) */
153.2101 + DEBUG2 (("Newly null killed: %d\n", c)) ;
153.2102 + Col [c].shared2.order = --n_col2 ;
153.2103 + KILL_PRINCIPAL_COL (c) ;
153.2104 + }
153.2105 + else
153.2106 + {
153.2107 + /* set column length and set score */
153.2108 + ASSERT (score >= 0) ;
153.2109 + ASSERT (score <= n_col) ;
153.2110 + Col [c].length = col_length ;
153.2111 + Col [c].shared2.score = score ;
153.2112 + }
153.2113 + }
153.2114 + DEBUG1 (("colamd: Dense, null, and newly-null columns killed: %d\n",
153.2115 + n_col-n_col2)) ;
153.2116 +
153.2117 + /* At this point, all empty rows and columns are dead. All live columns */
153.2118 + /* are "clean" (containing no dead rows) and simplicial (no supercolumns */
153.2119 + /* yet). Rows may contain dead columns, but all live rows contain at */
153.2120 + /* least one live column. */
153.2121 +
153.2122 +#ifndef NDEBUG
153.2123 + debug_structures (n_row, n_col, Row, Col, A, n_col2) ;
153.2124 +#endif /* NDEBUG */
153.2125 +
153.2126 + /* === Initialize degree lists ========================================== */
153.2127 +
153.2128 +#ifndef NDEBUG
153.2129 + debug_count = 0 ;
153.2130 +#endif /* NDEBUG */
153.2131 +
153.2132 + /* clear the hash buckets */
153.2133 + for (c = 0 ; c <= n_col ; c++)
153.2134 + {
153.2135 + head [c] = EMPTY ;
153.2136 + }
153.2137 + min_score = n_col ;
153.2138 + /* place in reverse order, so low column indices are at the front */
153.2139 + /* of the lists. This is to encourage natural tie-breaking */
153.2140 + for (c = n_col-1 ; c >= 0 ; c--)
153.2141 + {
153.2142 + /* only add principal columns to degree lists */
153.2143 + if (COL_IS_ALIVE (c))
153.2144 + {
153.2145 + DEBUG4 (("place %d score %d minscore %d ncol %d\n",
153.2146 + c, Col [c].shared2.score, min_score, n_col)) ;
153.2147 +
153.2148 + /* === Add columns score to DList =============================== */
153.2149 +
153.2150 + score = Col [c].shared2.score ;
153.2151 +
153.2152 + ASSERT (min_score >= 0) ;
153.2153 + ASSERT (min_score <= n_col) ;
153.2154 + ASSERT (score >= 0) ;
153.2155 + ASSERT (score <= n_col) ;
153.2156 + ASSERT (head [score] >= EMPTY) ;
153.2157 +
153.2158 + /* now add this column to dList at proper score location */
153.2159 + next_col = head [score] ;
153.2160 + Col [c].shared3.prev = EMPTY ;
153.2161 + Col [c].shared4.degree_next = next_col ;
153.2162 +
153.2163 + /* if there already was a column with the same score, set its */
153.2164 + /* previous pointer to this new column */
153.2165 + if (next_col != EMPTY)
153.2166 + {
153.2167 + Col [next_col].shared3.prev = c ;
153.2168 + }
153.2169 + head [score] = c ;
153.2170 +
153.2171 + /* see if this score is less than current min */
153.2172 + min_score = MIN (min_score, score) ;
153.2173 +
153.2174 +#ifndef NDEBUG
153.2175 + debug_count++ ;
153.2176 +#endif /* NDEBUG */
153.2177 +
153.2178 + }
153.2179 + }
153.2180 +
153.2181 +#ifndef NDEBUG
153.2182 + DEBUG1 (("colamd: Live cols %d out of %d, non-princ: %d\n",
153.2183 + debug_count, n_col, n_col-debug_count)) ;
153.2184 + ASSERT (debug_count == n_col2) ;
153.2185 + debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2, max_deg) ;
153.2186 +#endif /* NDEBUG */
153.2187 +
153.2188 + /* === Return number of remaining columns, and max row degree =========== */
153.2189 +
153.2190 + *p_n_col2 = n_col2 ;
153.2191 + *p_n_row2 = n_row2 ;
153.2192 + *p_max_deg = max_deg ;
153.2193 +}
153.2194 +
153.2195 +
153.2196 +/* ========================================================================== */
153.2197 +/* === find_ordering ======================================================== */
153.2198 +/* ========================================================================== */
153.2199 +
153.2200 +/*
153.2201 + Order the principal columns of the supercolumn form of the matrix
153.2202 + (no supercolumns on input). Uses a minimum approximate column minimum
153.2203 + degree ordering method. Not user-callable.
153.2204 +*/
153.2205 +
153.2206 +PRIVATE Int find_ordering /* return the number of garbage collections */
153.2207 +(
153.2208 + /* === Parameters ======================================================= */
153.2209 +
153.2210 + Int n_row, /* number of rows of A */
153.2211 + Int n_col, /* number of columns of A */
153.2212 + Int Alen, /* size of A, 2*nnz + n_col or larger */
153.2213 + Colamd_Row Row [], /* of size n_row+1 */
153.2214 + Colamd_Col Col [], /* of size n_col+1 */
153.2215 + Int A [], /* column form and row form of A */
153.2216 + Int head [], /* of size n_col+1 */
153.2217 + Int n_col2, /* Remaining columns to order */
153.2218 + Int max_deg, /* Maximum row degree */
153.2219 + Int pfree, /* index of first free slot (2*nnz on entry) */
153.2220 + Int aggressive
153.2221 +)
153.2222 +{
153.2223 + /* === Local variables ================================================== */
153.2224 +
153.2225 + Int k ; /* current pivot ordering step */
153.2226 + Int pivot_col ; /* current pivot column */
153.2227 + Int *cp ; /* a column pointer */
153.2228 + Int *rp ; /* a row pointer */
153.2229 + Int pivot_row ; /* current pivot row */
153.2230 + Int *new_cp ; /* modified column pointer */
153.2231 + Int *new_rp ; /* modified row pointer */
153.2232 + Int pivot_row_start ; /* pointer to start of pivot row */
153.2233 + Int pivot_row_degree ; /* number of columns in pivot row */
153.2234 + Int pivot_row_length ; /* number of supercolumns in pivot row */
153.2235 + Int pivot_col_score ; /* score of pivot column */
153.2236 + Int needed_memory ; /* free space needed for pivot row */
153.2237 + Int *cp_end ; /* pointer to the end of a column */
153.2238 + Int *rp_end ; /* pointer to the end of a row */
153.2239 + Int row ; /* a row index */
153.2240 + Int col ; /* a column index */
153.2241 + Int max_score ; /* maximum possible score */
153.2242 + Int cur_score ; /* score of current column */
153.2243 + unsigned Int hash ; /* hash value for supernode detection */
153.2244 + Int head_column ; /* head of hash bucket */
153.2245 + Int first_col ; /* first column in hash bucket */
153.2246 + Int tag_mark ; /* marker value for mark array */
153.2247 + Int row_mark ; /* Row [row].shared2.mark */
153.2248 + Int set_difference ; /* set difference size of row with pivot row */
153.2249 + Int min_score ; /* smallest column score */
153.2250 + Int col_thickness ; /* "thickness" (no. of columns in a supercol) */
153.2251 + Int max_mark ; /* maximum value of tag_mark */
153.2252 + Int pivot_col_thickness ; /* number of columns represented by pivot col */
153.2253 + Int prev_col ; /* Used by Dlist operations. */
153.2254 + Int next_col ; /* Used by Dlist operations. */
153.2255 + Int ngarbage ; /* number of garbage collections performed */
153.2256 +
153.2257 +#ifndef NDEBUG
153.2258 + Int debug_d ; /* debug loop counter */
153.2259 + Int debug_step = 0 ; /* debug loop counter */
153.2260 +#endif /* NDEBUG */
153.2261 +
153.2262 + /* === Initialization and clear mark ==================================== */
153.2263 +
153.2264 + max_mark = INT_MAX - n_col ; /* INT_MAX defined in <limits.h> */
153.2265 + tag_mark = clear_mark (0, max_mark, n_row, Row) ;
153.2266 + min_score = 0 ;
153.2267 + ngarbage = 0 ;
153.2268 + DEBUG1 (("colamd: Ordering, n_col2=%d\n", n_col2)) ;
153.2269 +
153.2270 + /* === Order the columns ================================================ */
153.2271 +
153.2272 + for (k = 0 ; k < n_col2 ; /* 'k' is incremented below */)
153.2273 + {
153.2274 +
153.2275 +#ifndef NDEBUG
153.2276 + if (debug_step % 100 == 0)
153.2277 + {
153.2278 + DEBUG2 (("\n... Step k: %d out of n_col2: %d\n", k, n_col2)) ;
153.2279 + }
153.2280 + else
153.2281 + {
153.2282 + DEBUG3 (("\n----------Step k: %d out of n_col2: %d\n", k, n_col2)) ;
153.2283 + }
153.2284 + debug_step++ ;
153.2285 + debug_deg_lists (n_row, n_col, Row, Col, head,
153.2286 + min_score, n_col2-k, max_deg) ;
153.2287 + debug_matrix (n_row, n_col, Row, Col, A) ;
153.2288 +#endif /* NDEBUG */
153.2289 +
153.2290 + /* === Select pivot column, and order it ============================ */
153.2291 +
153.2292 + /* make sure degree list isn't empty */
153.2293 + ASSERT (min_score >= 0) ;
153.2294 + ASSERT (min_score <= n_col) ;
153.2295 + ASSERT (head [min_score] >= EMPTY) ;
153.2296 +
153.2297 +#ifndef NDEBUG
153.2298 + for (debug_d = 0 ; debug_d < min_score ; debug_d++)
153.2299 + {
153.2300 + ASSERT (head [debug_d] == EMPTY) ;
153.2301 + }
153.2302 +#endif /* NDEBUG */
153.2303 +
153.2304 + /* get pivot column from head of minimum degree list */
153.2305 + while (head [min_score] == EMPTY && min_score < n_col)
153.2306 + {
153.2307 + min_score++ ;
153.2308 + }
153.2309 + pivot_col = head [min_score] ;
153.2310 + ASSERT (pivot_col >= 0 && pivot_col <= n_col) ;
153.2311 + next_col = Col [pivot_col].shared4.degree_next ;
153.2312 + head [min_score] = next_col ;
153.2313 + if (next_col != EMPTY)
153.2314 + {
153.2315 + Col [next_col].shared3.prev = EMPTY ;
153.2316 + }
153.2317 +
153.2318 + ASSERT (COL_IS_ALIVE (pivot_col)) ;
153.2319 +
153.2320 + /* remember score for defrag check */
153.2321 + pivot_col_score = Col [pivot_col].shared2.score ;
153.2322 +
153.2323 + /* the pivot column is the kth column in the pivot order */
153.2324 + Col [pivot_col].shared2.order = k ;
153.2325 +
153.2326 + /* increment order count by column thickness */
153.2327 + pivot_col_thickness = Col [pivot_col].shared1.thickness ;
153.2328 + k += pivot_col_thickness ;
153.2329 + ASSERT (pivot_col_thickness > 0) ;
153.2330 + DEBUG3 (("Pivot col: %d thick %d\n", pivot_col, pivot_col_thickness)) ;
153.2331 +
153.2332 + /* === Garbage_collection, if necessary ============================= */
153.2333 +
153.2334 + needed_memory = MIN (pivot_col_score, n_col - k) ;
153.2335 + if (pfree + needed_memory >= Alen)
153.2336 + {
153.2337 + pfree = garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ;
153.2338 + ngarbage++ ;
153.2339 + /* after garbage collection we will have enough */
153.2340 + ASSERT (pfree + needed_memory < Alen) ;
153.2341 + /* garbage collection has wiped out the Row[].shared2.mark array */
153.2342 + tag_mark = clear_mark (0, max_mark, n_row, Row) ;
153.2343 +
153.2344 +#ifndef NDEBUG
153.2345 + debug_matrix (n_row, n_col, Row, Col, A) ;
153.2346 +#endif /* NDEBUG */
153.2347 + }
153.2348 +
153.2349 + /* === Compute pivot row pattern ==================================== */
153.2350 +
153.2351 + /* get starting location for this new merged row */
153.2352 + pivot_row_start = pfree ;
153.2353 +
153.2354 + /* initialize new row counts to zero */
153.2355 + pivot_row_degree = 0 ;
153.2356 +
153.2357 + /* tag pivot column as having been visited so it isn't included */
153.2358 + /* in merged pivot row */
153.2359 + Col [pivot_col].shared1.thickness = -pivot_col_thickness ;
153.2360 +
153.2361 + /* pivot row is the union of all rows in the pivot column pattern */
153.2362 + cp = &A [Col [pivot_col].start] ;
153.2363 + cp_end = cp + Col [pivot_col].length ;
153.2364 + while (cp < cp_end)
153.2365 + {
153.2366 + /* get a row */
153.2367 + row = *cp++ ;
153.2368 + DEBUG4 (("Pivot col pattern %d %d\n", ROW_IS_ALIVE (row), row)) ;
153.2369 + /* skip if row is dead */
153.2370 + if (ROW_IS_ALIVE (row))
153.2371 + {
153.2372 + rp = &A [Row [row].start] ;
153.2373 + rp_end = rp + Row [row].length ;
153.2374 + while (rp < rp_end)
153.2375 + {
153.2376 + /* get a column */
153.2377 + col = *rp++ ;
153.2378 + /* add the column, if alive and untagged */
153.2379 + col_thickness = Col [col].shared1.thickness ;
153.2380 + if (col_thickness > 0 && COL_IS_ALIVE (col))
153.2381 + {
153.2382 + /* tag column in pivot row */
153.2383 + Col [col].shared1.thickness = -col_thickness ;
153.2384 + ASSERT (pfree < Alen) ;
153.2385 + /* place column in pivot row */
153.2386 + A [pfree++] = col ;
153.2387 + pivot_row_degree += col_thickness ;
153.2388 + }
153.2389 + }
153.2390 + }
153.2391 + }
153.2392 +
153.2393 + /* clear tag on pivot column */
153.2394 + Col [pivot_col].shared1.thickness = pivot_col_thickness ;
153.2395 + max_deg = MAX (max_deg, pivot_row_degree) ;
153.2396 +
153.2397 +#ifndef NDEBUG
153.2398 + DEBUG3 (("check2\n")) ;
153.2399 + debug_mark (n_row, Row, tag_mark, max_mark) ;
153.2400 +#endif /* NDEBUG */
153.2401 +
153.2402 + /* === Kill all rows used to construct pivot row ==================== */
153.2403 +
153.2404 + /* also kill pivot row, temporarily */
153.2405 + cp = &A [Col [pivot_col].start] ;
153.2406 + cp_end = cp + Col [pivot_col].length ;
153.2407 + while (cp < cp_end)
153.2408 + {
153.2409 + /* may be killing an already dead row */
153.2410 + row = *cp++ ;
153.2411 + DEBUG3 (("Kill row in pivot col: %d\n", row)) ;
153.2412 + KILL_ROW (row) ;
153.2413 + }
153.2414 +
153.2415 + /* === Select a row index to use as the new pivot row =============== */
153.2416 +
153.2417 + pivot_row_length = pfree - pivot_row_start ;
153.2418 + if (pivot_row_length > 0)
153.2419 + {
153.2420 + /* pick the "pivot" row arbitrarily (first row in col) */
153.2421 + pivot_row = A [Col [pivot_col].start] ;
153.2422 + DEBUG3 (("Pivotal row is %d\n", pivot_row)) ;
153.2423 + }
153.2424 + else
153.2425 + {
153.2426 + /* there is no pivot row, since it is of zero length */
153.2427 + pivot_row = EMPTY ;
153.2428 + ASSERT (pivot_row_length == 0) ;
153.2429 + }
153.2430 + ASSERT (Col [pivot_col].length > 0 || pivot_row_length == 0) ;
153.2431 +
153.2432 + /* === Approximate degree computation =============================== */
153.2433 +
153.2434 + /* Here begins the computation of the approximate degree. The column */
153.2435 + /* score is the sum of the pivot row "length", plus the size of the */
153.2436 + /* set differences of each row in the column minus the pattern of the */
153.2437 + /* pivot row itself. The column ("thickness") itself is also */
153.2438 + /* excluded from the column score (we thus use an approximate */
153.2439 + /* external degree). */
153.2440 +
153.2441 + /* The time taken by the following code (compute set differences, and */
153.2442 + /* add them up) is proportional to the size of the data structure */
153.2443 + /* being scanned - that is, the sum of the sizes of each column in */
153.2444 + /* the pivot row. Thus, the amortized time to compute a column score */
153.2445 + /* is proportional to the size of that column (where size, in this */
153.2446 + /* context, is the column "length", or the number of row indices */
153.2447 + /* in that column). The number of row indices in a column is */
153.2448 + /* monotonically non-decreasing, from the length of the original */
153.2449 + /* column on input to colamd. */
153.2450 +
153.2451 + /* === Compute set differences ====================================== */
153.2452 +
153.2453 + DEBUG3 (("** Computing set differences phase. **\n")) ;
153.2454 +
153.2455 + /* pivot row is currently dead - it will be revived later. */
153.2456 +
153.2457 + DEBUG3 (("Pivot row: ")) ;
153.2458 + /* for each column in pivot row */
153.2459 + rp = &A [pivot_row_start] ;
153.2460 + rp_end = rp + pivot_row_length ;
153.2461 + while (rp < rp_end)
153.2462 + {
153.2463 + col = *rp++ ;
153.2464 + ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
153.2465 + DEBUG3 (("Col: %d\n", col)) ;
153.2466 +
153.2467 + /* clear tags used to construct pivot row pattern */
153.2468 + col_thickness = -Col [col].shared1.thickness ;
153.2469 + ASSERT (col_thickness > 0) ;
153.2470 + Col [col].shared1.thickness = col_thickness ;
153.2471 +
153.2472 + /* === Remove column from degree list =========================== */
153.2473 +
153.2474 + cur_score = Col [col].shared2.score ;
153.2475 + prev_col = Col [col].shared3.prev ;
153.2476 + next_col = Col [col].shared4.degree_next ;
153.2477 + ASSERT (cur_score >= 0) ;
153.2478 + ASSERT (cur_score <= n_col) ;
153.2479 + ASSERT (cur_score >= EMPTY) ;
153.2480 + if (prev_col == EMPTY)
153.2481 + {
153.2482 + head [cur_score] = next_col ;
153.2483 + }
153.2484 + else
153.2485 + {
153.2486 + Col [prev_col].shared4.degree_next = next_col ;
153.2487 + }
153.2488 + if (next_col != EMPTY)
153.2489 + {
153.2490 + Col [next_col].shared3.prev = prev_col ;
153.2491 + }
153.2492 +
153.2493 + /* === Scan the column ========================================== */
153.2494 +
153.2495 + cp = &A [Col [col].start] ;
153.2496 + cp_end = cp + Col [col].length ;
153.2497 + while (cp < cp_end)
153.2498 + {
153.2499 + /* get a row */
153.2500 + row = *cp++ ;
153.2501 + row_mark = Row [row].shared2.mark ;
153.2502 + /* skip if dead */
153.2503 + if (ROW_IS_MARKED_DEAD (row_mark))
153.2504 + {
153.2505 + continue ;
153.2506 + }
153.2507 + ASSERT (row != pivot_row) ;
153.2508 + set_difference = row_mark - tag_mark ;
153.2509 + /* check if the row has been seen yet */
153.2510 + if (set_difference < 0)
153.2511 + {
153.2512 + ASSERT (Row [row].shared1.degree <= max_deg) ;
153.2513 + set_difference = Row [row].shared1.degree ;
153.2514 + }
153.2515 + /* subtract column thickness from this row's set difference */
153.2516 + set_difference -= col_thickness ;
153.2517 + ASSERT (set_difference >= 0) ;
153.2518 + /* absorb this row if the set difference becomes zero */
153.2519 + if (set_difference == 0 && aggressive)
153.2520 + {
153.2521 + DEBUG3 (("aggressive absorption. Row: %d\n", row)) ;
153.2522 + KILL_ROW (row) ;
153.2523 + }
153.2524 + else
153.2525 + {
153.2526 + /* save the new mark */
153.2527 + Row [row].shared2.mark = set_difference + tag_mark ;
153.2528 + }
153.2529 + }
153.2530 + }
153.2531 +
153.2532 +#ifndef NDEBUG
153.2533 + debug_deg_lists (n_row, n_col, Row, Col, head,
153.2534 + min_score, n_col2-k-pivot_row_degree, max_deg) ;
153.2535 +#endif /* NDEBUG */
153.2536 +
153.2537 + /* === Add up set differences for each column ======================= */
153.2538 +
153.2539 + DEBUG3 (("** Adding set differences phase. **\n")) ;
153.2540 +
153.2541 + /* for each column in pivot row */
153.2542 + rp = &A [pivot_row_start] ;
153.2543 + rp_end = rp + pivot_row_length ;
153.2544 + while (rp < rp_end)
153.2545 + {
153.2546 + /* get a column */
153.2547 + col = *rp++ ;
153.2548 + ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
153.2549 + hash = 0 ;
153.2550 + cur_score = 0 ;
153.2551 + cp = &A [Col [col].start] ;
153.2552 + /* compact the column */
153.2553 + new_cp = cp ;
153.2554 + cp_end = cp + Col [col].length ;
153.2555 +
153.2556 + DEBUG4 (("Adding set diffs for Col: %d.\n", col)) ;
153.2557 +
153.2558 + while (cp < cp_end)
153.2559 + {
153.2560 + /* get a row */
153.2561 + row = *cp++ ;
153.2562 + ASSERT(row >= 0 && row < n_row) ;
153.2563 + row_mark = Row [row].shared2.mark ;
153.2564 + /* skip if dead */
153.2565 + if (ROW_IS_MARKED_DEAD (row_mark))
153.2566 + {
153.2567 + DEBUG4 ((" Row %d, dead\n", row)) ;
153.2568 + continue ;
153.2569 + }
153.2570 + DEBUG4 ((" Row %d, set diff %d\n", row, row_mark-tag_mark));
153.2571 + ASSERT (row_mark >= tag_mark) ;
153.2572 + /* compact the column */
153.2573 + *new_cp++ = row ;
153.2574 + /* compute hash function */
153.2575 + hash += row ;
153.2576 + /* add set difference */
153.2577 + cur_score += row_mark - tag_mark ;
153.2578 + /* integer overflow... */
153.2579 + cur_score = MIN (cur_score, n_col) ;
153.2580 + }
153.2581 +
153.2582 + /* recompute the column's length */
153.2583 + Col [col].length = (Int) (new_cp - &A [Col [col].start]) ;
153.2584 +
153.2585 + /* === Further mass elimination ================================= */
153.2586 +
153.2587 + if (Col [col].length == 0)
153.2588 + {
153.2589 + DEBUG4 (("further mass elimination. Col: %d\n", col)) ;
153.2590 + /* nothing left but the pivot row in this column */
153.2591 + KILL_PRINCIPAL_COL (col) ;
153.2592 + pivot_row_degree -= Col [col].shared1.thickness ;
153.2593 + ASSERT (pivot_row_degree >= 0) ;
153.2594 + /* order it */
153.2595 + Col [col].shared2.order = k ;
153.2596 + /* increment order count by column thickness */
153.2597 + k += Col [col].shared1.thickness ;
153.2598 + }
153.2599 + else
153.2600 + {
153.2601 + /* === Prepare for supercolumn detection ==================== */
153.2602 +
153.2603 + DEBUG4 (("Preparing supercol detection for Col: %d.\n", col)) ;
153.2604 +
153.2605 + /* save score so far */
153.2606 + Col [col].shared2.score = cur_score ;
153.2607 +
153.2608 + /* add column to hash table, for supercolumn detection */
153.2609 + hash %= n_col + 1 ;
153.2610 +
153.2611 + DEBUG4 ((" Hash = %d, n_col = %d.\n", hash, n_col)) ;
153.2612 + ASSERT (((Int) hash) <= n_col) ;
153.2613 +
153.2614 + head_column = head [hash] ;
153.2615 + if (head_column > EMPTY)
153.2616 + {
153.2617 + /* degree list "hash" is non-empty, use prev (shared3) of */
153.2618 + /* first column in degree list as head of hash bucket */
153.2619 + first_col = Col [head_column].shared3.headhash ;
153.2620 + Col [head_column].shared3.headhash = col ;
153.2621 + }
153.2622 + else
153.2623 + {
153.2624 + /* degree list "hash" is empty, use head as hash bucket */
153.2625 + first_col = - (head_column + 2) ;
153.2626 + head [hash] = - (col + 2) ;
153.2627 + }
153.2628 + Col [col].shared4.hash_next = first_col ;
153.2629 +
153.2630 + /* save hash function in Col [col].shared3.hash */
153.2631 + Col [col].shared3.hash = (Int) hash ;
153.2632 + ASSERT (COL_IS_ALIVE (col)) ;
153.2633 + }
153.2634 + }
153.2635 +
153.2636 + /* The approximate external column degree is now computed. */
153.2637 +
153.2638 + /* === Supercolumn detection ======================================== */
153.2639 +
153.2640 + DEBUG3 (("** Supercolumn detection phase. **\n")) ;
153.2641 +
153.2642 + detect_super_cols (
153.2643 +
153.2644 +#ifndef NDEBUG
153.2645 + n_col, Row,
153.2646 +#endif /* NDEBUG */
153.2647 +
153.2648 + Col, A, head, pivot_row_start, pivot_row_length) ;
153.2649 +
153.2650 + /* === Kill the pivotal column ====================================== */
153.2651 +
153.2652 + KILL_PRINCIPAL_COL (pivot_col) ;
153.2653 +
153.2654 + /* === Clear mark =================================================== */
153.2655 +
153.2656 + tag_mark = clear_mark (tag_mark+max_deg+1, max_mark, n_row, Row) ;
153.2657 +
153.2658 +#ifndef NDEBUG
153.2659 + DEBUG3 (("check3\n")) ;
153.2660 + debug_mark (n_row, Row, tag_mark, max_mark) ;
153.2661 +#endif /* NDEBUG */
153.2662 +
153.2663 + /* === Finalize the new pivot row, and column scores ================ */
153.2664 +
153.2665 + DEBUG3 (("** Finalize scores phase. **\n")) ;
153.2666 +
153.2667 + /* for each column in pivot row */
153.2668 + rp = &A [pivot_row_start] ;
153.2669 + /* compact the pivot row */
153.2670 + new_rp = rp ;
153.2671 + rp_end = rp + pivot_row_length ;
153.2672 + while (rp < rp_end)
153.2673 + {
153.2674 + col = *rp++ ;
153.2675 + /* skip dead columns */
153.2676 + if (COL_IS_DEAD (col))
153.2677 + {
153.2678 + continue ;
153.2679 + }
153.2680 + *new_rp++ = col ;
153.2681 + /* add new pivot row to column */
153.2682 + A [Col [col].start + (Col [col].length++)] = pivot_row ;
153.2683 +
153.2684 + /* retrieve score so far and add on pivot row's degree. */
153.2685 + /* (we wait until here for this in case the pivot */
153.2686 + /* row's degree was reduced due to mass elimination). */
153.2687 + cur_score = Col [col].shared2.score + pivot_row_degree ;
153.2688 +
153.2689 + /* calculate the max possible score as the number of */
153.2690 + /* external columns minus the 'k' value minus the */
153.2691 + /* columns thickness */
153.2692 + max_score = n_col - k - Col [col].shared1.thickness ;
153.2693 +
153.2694 + /* make the score the external degree of the union-of-rows */
153.2695 + cur_score -= Col [col].shared1.thickness ;
153.2696 +
153.2697 + /* make sure score is less or equal than the max score */
153.2698 + cur_score = MIN (cur_score, max_score) ;
153.2699 + ASSERT (cur_score >= 0) ;
153.2700 +
153.2701 + /* store updated score */
153.2702 + Col [col].shared2.score = cur_score ;
153.2703 +
153.2704 + /* === Place column back in degree list ========================= */
153.2705 +
153.2706 + ASSERT (min_score >= 0) ;
153.2707 + ASSERT (min_score <= n_col) ;
153.2708 + ASSERT (cur_score >= 0) ;
153.2709 + ASSERT (cur_score <= n_col) ;
153.2710 + ASSERT (head [cur_score] >= EMPTY) ;
153.2711 + next_col = head [cur_score] ;
153.2712 + Col [col].shared4.degree_next = next_col ;
153.2713 + Col [col].shared3.prev = EMPTY ;
153.2714 + if (next_col != EMPTY)
153.2715 + {
153.2716 + Col [next_col].shared3.prev = col ;
153.2717 + }
153.2718 + head [cur_score] = col ;
153.2719 +
153.2720 + /* see if this score is less than current min */
153.2721 + min_score = MIN (min_score, cur_score) ;
153.2722 +
153.2723 + }
153.2724 +
153.2725 +#ifndef NDEBUG
153.2726 + debug_deg_lists (n_row, n_col, Row, Col, head,
153.2727 + min_score, n_col2-k, max_deg) ;
153.2728 +#endif /* NDEBUG */
153.2729 +
153.2730 + /* === Resurrect the new pivot row ================================== */
153.2731 +
153.2732 + if (pivot_row_degree > 0)
153.2733 + {
153.2734 + /* update pivot row length to reflect any cols that were killed */
153.2735 + /* during super-col detection and mass elimination */
153.2736 + Row [pivot_row].start = pivot_row_start ;
153.2737 + Row [pivot_row].length = (Int) (new_rp - &A[pivot_row_start]) ;
153.2738 + ASSERT (Row [pivot_row].length > 0) ;
153.2739 + Row [pivot_row].shared1.degree = pivot_row_degree ;
153.2740 + Row [pivot_row].shared2.mark = 0 ;
153.2741 + /* pivot row is no longer dead */
153.2742 +
153.2743 + DEBUG1 (("Resurrect Pivot_row %d deg: %d\n",
153.2744 + pivot_row, pivot_row_degree)) ;
153.2745 + }
153.2746 + }
153.2747 +
153.2748 + /* === All principal columns have now been ordered ====================== */
153.2749 +
153.2750 + return (ngarbage) ;
153.2751 +}
153.2752 +
153.2753 +
153.2754 +/* ========================================================================== */
153.2755 +/* === order_children ======================================================= */
153.2756 +/* ========================================================================== */
153.2757 +
153.2758 +/*
153.2759 + The find_ordering routine has ordered all of the principal columns (the
153.2760 + representatives of the supercolumns). The non-principal columns have not
153.2761 + yet been ordered. This routine orders those columns by walking up the
153.2762 + parent tree (a column is a child of the column which absorbed it). The
153.2763 + final permutation vector is then placed in p [0 ... n_col-1], with p [0]
153.2764 + being the first column, and p [n_col-1] being the last. It doesn't look
153.2765 + like it at first glance, but be assured that this routine takes time linear
153.2766 + in the number of columns. Although not immediately obvious, the time
153.2767 + taken by this routine is O (n_col), that is, linear in the number of
153.2768 + columns. Not user-callable.
153.2769 +*/
153.2770 +
153.2771 +PRIVATE void order_children
153.2772 +(
153.2773 + /* === Parameters ======================================================= */
153.2774 +
153.2775 + Int n_col, /* number of columns of A */
153.2776 + Colamd_Col Col [], /* of size n_col+1 */
153.2777 + Int p [] /* p [0 ... n_col-1] is the column permutation*/
153.2778 +)
153.2779 +{
153.2780 + /* === Local variables ================================================== */
153.2781 +
153.2782 + Int i ; /* loop counter for all columns */
153.2783 + Int c ; /* column index */
153.2784 + Int parent ; /* index of column's parent */
153.2785 + Int order ; /* column's order */
153.2786 +
153.2787 + /* === Order each non-principal column ================================== */
153.2788 +
153.2789 + for (i = 0 ; i < n_col ; i++)
153.2790 + {
153.2791 + /* find an un-ordered non-principal column */
153.2792 + ASSERT (COL_IS_DEAD (i)) ;
153.2793 + if (!COL_IS_DEAD_PRINCIPAL (i) && Col [i].shared2.order == EMPTY)
153.2794 + {
153.2795 + parent = i ;
153.2796 + /* once found, find its principal parent */
153.2797 + do
153.2798 + {
153.2799 + parent = Col [parent].shared1.parent ;
153.2800 + } while (!COL_IS_DEAD_PRINCIPAL (parent)) ;
153.2801 +
153.2802 + /* now, order all un-ordered non-principal columns along path */
153.2803 + /* to this parent. collapse tree at the same time */
153.2804 + c = i ;
153.2805 + /* get order of parent */
153.2806 + order = Col [parent].shared2.order ;
153.2807 +
153.2808 + do
153.2809 + {
153.2810 + ASSERT (Col [c].shared2.order == EMPTY) ;
153.2811 +
153.2812 + /* order this column */
153.2813 + Col [c].shared2.order = order++ ;
153.2814 + /* collaps tree */
153.2815 + Col [c].shared1.parent = parent ;
153.2816 +
153.2817 + /* get immediate parent of this column */
153.2818 + c = Col [c].shared1.parent ;
153.2819 +
153.2820 + /* continue until we hit an ordered column. There are */
153.2821 + /* guarranteed not to be anymore unordered columns */
153.2822 + /* above an ordered column */
153.2823 + } while (Col [c].shared2.order == EMPTY) ;
153.2824 +
153.2825 + /* re-order the super_col parent to largest order for this group */
153.2826 + Col [parent].shared2.order = order ;
153.2827 + }
153.2828 + }
153.2829 +
153.2830 + /* === Generate the permutation ========================================= */
153.2831 +
153.2832 + for (c = 0 ; c < n_col ; c++)
153.2833 + {
153.2834 + p [Col [c].shared2.order] = c ;
153.2835 + }
153.2836 +}
153.2837 +
153.2838 +
153.2839 +/* ========================================================================== */
153.2840 +/* === detect_super_cols ==================================================== */
153.2841 +/* ========================================================================== */
153.2842 +
153.2843 +/*
153.2844 + Detects supercolumns by finding matches between columns in the hash buckets.
153.2845 + Check amongst columns in the set A [row_start ... row_start + row_length-1].
153.2846 + The columns under consideration are currently *not* in the degree lists,
153.2847 + and have already been placed in the hash buckets.
153.2848 +
153.2849 + The hash bucket for columns whose hash function is equal to h is stored
153.2850 + as follows:
153.2851 +
153.2852 + if head [h] is >= 0, then head [h] contains a degree list, so:
153.2853 +
153.2854 + head [h] is the first column in degree bucket h.
153.2855 + Col [head [h]].headhash gives the first column in hash bucket h.
153.2856 +
153.2857 + otherwise, the degree list is empty, and:
153.2858 +
153.2859 + -(head [h] + 2) is the first column in hash bucket h.
153.2860 +
153.2861 + For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous
153.2862 + column" pointer. Col [c].shared3.hash is used instead as the hash number
153.2863 + for that column. The value of Col [c].shared4.hash_next is the next column
153.2864 + in the same hash bucket.
153.2865 +
153.2866 + Assuming no, or "few" hash collisions, the time taken by this routine is
153.2867 + linear in the sum of the sizes (lengths) of each column whose score has
153.2868 + just been computed in the approximate degree computation.
153.2869 + Not user-callable.
153.2870 +*/
153.2871 +
153.2872 +PRIVATE void detect_super_cols
153.2873 +(
153.2874 + /* === Parameters ======================================================= */
153.2875 +
153.2876 +#ifndef NDEBUG
153.2877 + /* these two parameters are only needed when debugging is enabled: */
153.2878 + Int n_col, /* number of columns of A */
153.2879 + Colamd_Row Row [], /* of size n_row+1 */
153.2880 +#endif /* NDEBUG */
153.2881 +
153.2882 + Colamd_Col Col [], /* of size n_col+1 */
153.2883 + Int A [], /* row indices of A */
153.2884 + Int head [], /* head of degree lists and hash buckets */
153.2885 + Int row_start, /* pointer to set of columns to check */
153.2886 + Int row_length /* number of columns to check */
153.2887 +)
153.2888 +{
153.2889 + /* === Local variables ================================================== */
153.2890 +
153.2891 + Int hash ; /* hash value for a column */
153.2892 + Int *rp ; /* pointer to a row */
153.2893 + Int c ; /* a column index */
153.2894 + Int super_c ; /* column index of the column to absorb into */
153.2895 + Int *cp1 ; /* column pointer for column super_c */
153.2896 + Int *cp2 ; /* column pointer for column c */
153.2897 + Int length ; /* length of column super_c */
153.2898 + Int prev_c ; /* column preceding c in hash bucket */
153.2899 + Int i ; /* loop counter */
153.2900 + Int *rp_end ; /* pointer to the end of the row */
153.2901 + Int col ; /* a column index in the row to check */
153.2902 + Int head_column ; /* first column in hash bucket or degree list */
153.2903 + Int first_col ; /* first column in hash bucket */
153.2904 +
153.2905 + /* === Consider each column in the row ================================== */
153.2906 +
153.2907 + rp = &A [row_start] ;
153.2908 + rp_end = rp + row_length ;
153.2909 + while (rp < rp_end)
153.2910 + {
153.2911 + col = *rp++ ;
153.2912 + if (COL_IS_DEAD (col))
153.2913 + {
153.2914 + continue ;
153.2915 + }
153.2916 +
153.2917 + /* get hash number for this column */
153.2918 + hash = Col [col].shared3.hash ;
153.2919 + ASSERT (hash <= n_col) ;
153.2920 +
153.2921 + /* === Get the first column in this hash bucket ===================== */
153.2922 +
153.2923 + head_column = head [hash] ;
153.2924 + if (head_column > EMPTY)
153.2925 + {
153.2926 + first_col = Col [head_column].shared3.headhash ;
153.2927 + }
153.2928 + else
153.2929 + {
153.2930 + first_col = - (head_column + 2) ;
153.2931 + }
153.2932 +
153.2933 + /* === Consider each column in the hash bucket ====================== */
153.2934 +
153.2935 + for (super_c = first_col ; super_c != EMPTY ;
153.2936 + super_c = Col [super_c].shared4.hash_next)
153.2937 + {
153.2938 + ASSERT (COL_IS_ALIVE (super_c)) ;
153.2939 + ASSERT (Col [super_c].shared3.hash == hash) ;
153.2940 + length = Col [super_c].length ;
153.2941 +
153.2942 + /* prev_c is the column preceding column c in the hash bucket */
153.2943 + prev_c = super_c ;
153.2944 +
153.2945 + /* === Compare super_c with all columns after it ================ */
153.2946 +
153.2947 + for (c = Col [super_c].shared4.hash_next ;
153.2948 + c != EMPTY ; c = Col [c].shared4.hash_next)
153.2949 + {
153.2950 + ASSERT (c != super_c) ;
153.2951 + ASSERT (COL_IS_ALIVE (c)) ;
153.2952 + ASSERT (Col [c].shared3.hash == hash) ;
153.2953 +
153.2954 + /* not identical if lengths or scores are different */
153.2955 + if (Col [c].length != length ||
153.2956 + Col [c].shared2.score != Col [super_c].shared2.score)
153.2957 + {
153.2958 + prev_c = c ;
153.2959 + continue ;
153.2960 + }
153.2961 +
153.2962 + /* compare the two columns */
153.2963 + cp1 = &A [Col [super_c].start] ;
153.2964 + cp2 = &A [Col [c].start] ;
153.2965 +
153.2966 + for (i = 0 ; i < length ; i++)
153.2967 + {
153.2968 + /* the columns are "clean" (no dead rows) */
153.2969 + ASSERT (ROW_IS_ALIVE (*cp1)) ;
153.2970 + ASSERT (ROW_IS_ALIVE (*cp2)) ;
153.2971 + /* row indices will same order for both supercols, */
153.2972 + /* no gather scatter nessasary */
153.2973 + if (*cp1++ != *cp2++)
153.2974 + {
153.2975 + break ;
153.2976 + }
153.2977 + }
153.2978 +
153.2979 + /* the two columns are different if the for-loop "broke" */
153.2980 + if (i != length)
153.2981 + {
153.2982 + prev_c = c ;
153.2983 + continue ;
153.2984 + }
153.2985 +
153.2986 + /* === Got it! two columns are identical =================== */
153.2987 +
153.2988 + ASSERT (Col [c].shared2.score == Col [super_c].shared2.score) ;
153.2989 +
153.2990 + Col [super_c].shared1.thickness += Col [c].shared1.thickness ;
153.2991 + Col [c].shared1.parent = super_c ;
153.2992 + KILL_NON_PRINCIPAL_COL (c) ;
153.2993 + /* order c later, in order_children() */
153.2994 + Col [c].shared2.order = EMPTY ;
153.2995 + /* remove c from hash bucket */
153.2996 + Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ;
153.2997 + }
153.2998 + }
153.2999 +
153.3000 + /* === Empty this hash bucket ======================================= */
153.3001 +
153.3002 + if (head_column > EMPTY)
153.3003 + {
153.3004 + /* corresponding degree list "hash" is not empty */
153.3005 + Col [head_column].shared3.headhash = EMPTY ;
153.3006 + }
153.3007 + else
153.3008 + {
153.3009 + /* corresponding degree list "hash" is empty */
153.3010 + head [hash] = EMPTY ;
153.3011 + }
153.3012 + }
153.3013 +}
153.3014 +
153.3015 +
153.3016 +/* ========================================================================== */
153.3017 +/* === garbage_collection =================================================== */
153.3018 +/* ========================================================================== */
153.3019 +
153.3020 +/*
153.3021 + Defragments and compacts columns and rows in the workspace A. Used when
153.3022 + all avaliable memory has been used while performing row merging. Returns
153.3023 + the index of the first free position in A, after garbage collection. The
153.3024 + time taken by this routine is linear is the size of the array A, which is
153.3025 + itself linear in the number of nonzeros in the input matrix.
153.3026 + Not user-callable.
153.3027 +*/
153.3028 +
153.3029 +PRIVATE Int garbage_collection /* returns the new value of pfree */
153.3030 +(
153.3031 + /* === Parameters ======================================================= */
153.3032 +
153.3033 + Int n_row, /* number of rows */
153.3034 + Int n_col, /* number of columns */
153.3035 + Colamd_Row Row [], /* row info */
153.3036 + Colamd_Col Col [], /* column info */
153.3037 + Int A [], /* A [0 ... Alen-1] holds the matrix */
153.3038 + Int *pfree /* &A [0] ... pfree is in use */
153.3039 +)
153.3040 +{
153.3041 + /* === Local variables ================================================== */
153.3042 +
153.3043 + Int *psrc ; /* source pointer */
153.3044 + Int *pdest ; /* destination pointer */
153.3045 + Int j ; /* counter */
153.3046 + Int r ; /* a row index */
153.3047 + Int c ; /* a column index */
153.3048 + Int length ; /* length of a row or column */
153.3049 +
153.3050 +#ifndef NDEBUG
153.3051 + Int debug_rows ;
153.3052 + DEBUG2 (("Defrag..\n")) ;
153.3053 + for (psrc = &A[0] ; psrc < pfree ; psrc++) ASSERT (*psrc >= 0) ;
153.3054 + debug_rows = 0 ;
153.3055 +#endif /* NDEBUG */
153.3056 +
153.3057 + /* === Defragment the columns =========================================== */
153.3058 +
153.3059 + pdest = &A[0] ;
153.3060 + for (c = 0 ; c < n_col ; c++)
153.3061 + {
153.3062 + if (COL_IS_ALIVE (c))
153.3063 + {
153.3064 + psrc = &A [Col [c].start] ;
153.3065 +
153.3066 + /* move and compact the column */
153.3067 + ASSERT (pdest <= psrc) ;
153.3068 + Col [c].start = (Int) (pdest - &A [0]) ;
153.3069 + length = Col [c].length ;
153.3070 + for (j = 0 ; j < length ; j++)
153.3071 + {
153.3072 + r = *psrc++ ;
153.3073 + if (ROW_IS_ALIVE (r))
153.3074 + {
153.3075 + *pdest++ = r ;
153.3076 + }
153.3077 + }
153.3078 + Col [c].length = (Int) (pdest - &A [Col [c].start]) ;
153.3079 + }
153.3080 + }
153.3081 +
153.3082 + /* === Prepare to defragment the rows =================================== */
153.3083 +
153.3084 + for (r = 0 ; r < n_row ; r++)
153.3085 + {
153.3086 + if (ROW_IS_DEAD (r) || (Row [r].length == 0))
153.3087 + {
153.3088 + /* This row is already dead, or is of zero length. Cannot compact
153.3089 + * a row of zero length, so kill it. NOTE: in the current version,
153.3090 + * there are no zero-length live rows. Kill the row (for the first
153.3091 + * time, or again) just to be safe. */
153.3092 + KILL_ROW (r) ;
153.3093 + }
153.3094 + else
153.3095 + {
153.3096 + /* save first column index in Row [r].shared2.first_column */
153.3097 + psrc = &A [Row [r].start] ;
153.3098 + Row [r].shared2.first_column = *psrc ;
153.3099 + ASSERT (ROW_IS_ALIVE (r)) ;
153.3100 + /* flag the start of the row with the one's complement of row */
153.3101 + *psrc = ONES_COMPLEMENT (r) ;
153.3102 +#ifndef NDEBUG
153.3103 + debug_rows++ ;
153.3104 +#endif /* NDEBUG */
153.3105 + }
153.3106 + }
153.3107 +
153.3108 + /* === Defragment the rows ============================================== */
153.3109 +
153.3110 + psrc = pdest ;
153.3111 + while (psrc < pfree)
153.3112 + {
153.3113 + /* find a negative number ... the start of a row */
153.3114 + if (*psrc++ < 0)
153.3115 + {
153.3116 + psrc-- ;
153.3117 + /* get the row index */
153.3118 + r = ONES_COMPLEMENT (*psrc) ;
153.3119 + ASSERT (r >= 0 && r < n_row) ;
153.3120 + /* restore first column index */
153.3121 + *psrc = Row [r].shared2.first_column ;
153.3122 + ASSERT (ROW_IS_ALIVE (r)) ;
153.3123 + ASSERT (Row [r].length > 0) ;
153.3124 + /* move and compact the row */
153.3125 + ASSERT (pdest <= psrc) ;
153.3126 + Row [r].start = (Int) (pdest - &A [0]) ;
153.3127 + length = Row [r].length ;
153.3128 + for (j = 0 ; j < length ; j++)
153.3129 + {
153.3130 + c = *psrc++ ;
153.3131 + if (COL_IS_ALIVE (c))
153.3132 + {
153.3133 + *pdest++ = c ;
153.3134 + }
153.3135 + }
153.3136 + Row [r].length = (Int) (pdest - &A [Row [r].start]) ;
153.3137 + ASSERT (Row [r].length > 0) ;
153.3138 +#ifndef NDEBUG
153.3139 + debug_rows-- ;
153.3140 +#endif /* NDEBUG */
153.3141 + }
153.3142 + }
153.3143 + /* ensure we found all the rows */
153.3144 + ASSERT (debug_rows == 0) ;
153.3145 +
153.3146 + /* === Return the new value of pfree ==================================== */
153.3147 +
153.3148 + return ((Int) (pdest - &A [0])) ;
153.3149 +}
153.3150 +
153.3151 +
153.3152 +/* ========================================================================== */
153.3153 +/* === clear_mark =========================================================== */
153.3154 +/* ========================================================================== */
153.3155 +
153.3156 +/*
153.3157 + Clears the Row [].shared2.mark array, and returns the new tag_mark.
153.3158 + Return value is the new tag_mark. Not user-callable.
153.3159 +*/
153.3160 +
153.3161 +PRIVATE Int clear_mark /* return the new value for tag_mark */
153.3162 +(
153.3163 + /* === Parameters ======================================================= */
153.3164 +
153.3165 + Int tag_mark, /* new value of tag_mark */
153.3166 + Int max_mark, /* max allowed value of tag_mark */
153.3167 +
153.3168 + Int n_row, /* number of rows in A */
153.3169 + Colamd_Row Row [] /* Row [0 ... n_row-1].shared2.mark is set to zero */
153.3170 +)
153.3171 +{
153.3172 + /* === Local variables ================================================== */
153.3173 +
153.3174 + Int r ;
153.3175 +
153.3176 + if (tag_mark <= 0 || tag_mark >= max_mark)
153.3177 + {
153.3178 + for (r = 0 ; r < n_row ; r++)
153.3179 + {
153.3180 + if (ROW_IS_ALIVE (r))
153.3181 + {
153.3182 + Row [r].shared2.mark = 0 ;
153.3183 + }
153.3184 + }
153.3185 + tag_mark = 1 ;
153.3186 + }
153.3187 +
153.3188 + return (tag_mark) ;
153.3189 +}
153.3190 +
153.3191 +
153.3192 +/* ========================================================================== */
153.3193 +/* === print_report ========================================================= */
153.3194 +/* ========================================================================== */
153.3195 +
153.3196 +PRIVATE void print_report
153.3197 +(
153.3198 + char *method,
153.3199 + Int stats [COLAMD_STATS]
153.3200 +)
153.3201 +{
153.3202 +
153.3203 + Int i1, i2, i3 ;
153.3204 +
153.3205 + PRINTF (("\n%s version %d.%d, %s: ", method,
153.3206 + COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE)) ;
153.3207 +
153.3208 + if (!stats)
153.3209 + {
153.3210 + PRINTF (("No statistics available.\n")) ;
153.3211 + return ;
153.3212 + }
153.3213 +
153.3214 + i1 = stats [COLAMD_INFO1] ;
153.3215 + i2 = stats [COLAMD_INFO2] ;
153.3216 + i3 = stats [COLAMD_INFO3] ;
153.3217 +
153.3218 + if (stats [COLAMD_STATUS] >= 0)
153.3219 + {
153.3220 + PRINTF (("OK. ")) ;
153.3221 + }
153.3222 + else
153.3223 + {
153.3224 + PRINTF (("ERROR. ")) ;
153.3225 + }
153.3226 +
153.3227 + switch (stats [COLAMD_STATUS])
153.3228 + {
153.3229 +
153.3230 + case COLAMD_OK_BUT_JUMBLED:
153.3231 +
153.3232 + PRINTF(("Matrix has unsorted or duplicate row indices.\n")) ;
153.3233 +
153.3234 + PRINTF(("%s: number of duplicate or out-of-order row indices: %d\n",
153.3235 + method, i3)) ;
153.3236 +
153.3237 + PRINTF(("%s: last seen duplicate or out-of-order row index: %d\n",
153.3238 + method, INDEX (i2))) ;
153.3239 +
153.3240 + PRINTF(("%s: last seen in column: %d",
153.3241 + method, INDEX (i1))) ;
153.3242 +
153.3243 + /* no break - fall through to next case instead */
153.3244 +
153.3245 + case COLAMD_OK:
153.3246 +
153.3247 + PRINTF(("\n")) ;
153.3248 +
153.3249 + PRINTF(("%s: number of dense or empty rows ignored: %d\n",
153.3250 + method, stats [COLAMD_DENSE_ROW])) ;
153.3251 +
153.3252 + PRINTF(("%s: number of dense or empty columns ignored: %d\n",
153.3253 + method, stats [COLAMD_DENSE_COL])) ;
153.3254 +
153.3255 + PRINTF(("%s: number of garbage collections performed: %d\n",
153.3256 + method, stats [COLAMD_DEFRAG_COUNT])) ;
153.3257 + break ;
153.3258 +
153.3259 + case COLAMD_ERROR_A_not_present:
153.3260 +
153.3261 + PRINTF(("Array A (row indices of matrix) not present.\n")) ;
153.3262 + break ;
153.3263 +
153.3264 + case COLAMD_ERROR_p_not_present:
153.3265 +
153.3266 + PRINTF(("Array p (column pointers for matrix) not present.\n")) ;
153.3267 + break ;
153.3268 +
153.3269 + case COLAMD_ERROR_nrow_negative:
153.3270 +
153.3271 + PRINTF(("Invalid number of rows (%d).\n", i1)) ;
153.3272 + break ;
153.3273 +
153.3274 + case COLAMD_ERROR_ncol_negative:
153.3275 +
153.3276 + PRINTF(("Invalid number of columns (%d).\n", i1)) ;
153.3277 + break ;
153.3278 +
153.3279 + case COLAMD_ERROR_nnz_negative:
153.3280 +
153.3281 + PRINTF(("Invalid number of nonzero entries (%d).\n", i1)) ;
153.3282 + break ;
153.3283 +
153.3284 + case COLAMD_ERROR_p0_nonzero:
153.3285 +
153.3286 + PRINTF(("Invalid column pointer, p [0] = %d, must be zero.\n", i1));
153.3287 + break ;
153.3288 +
153.3289 + case COLAMD_ERROR_A_too_small:
153.3290 +
153.3291 + PRINTF(("Array A too small.\n")) ;
153.3292 + PRINTF((" Need Alen >= %d, but given only Alen = %d.\n",
153.3293 + i1, i2)) ;
153.3294 + break ;
153.3295 +
153.3296 + case COLAMD_ERROR_col_length_negative:
153.3297 +
153.3298 + PRINTF
153.3299 + (("Column %d has a negative number of nonzero entries (%d).\n",
153.3300 + INDEX (i1), i2)) ;
153.3301 + break ;
153.3302 +
153.3303 + case COLAMD_ERROR_row_index_out_of_bounds:
153.3304 +
153.3305 + PRINTF
153.3306 + (("Row index (row %d) out of bounds (%d to %d) in column %d.\n",
153.3307 + INDEX (i2), INDEX (0), INDEX (i3-1), INDEX (i1))) ;
153.3308 + break ;
153.3309 +
153.3310 + case COLAMD_ERROR_out_of_memory:
153.3311 +
153.3312 + PRINTF(("Out of memory.\n")) ;
153.3313 + break ;
153.3314 +
153.3315 + /* v2.4: internal-error case deleted */
153.3316 + }
153.3317 +}
153.3318 +
153.3319 +
153.3320 +
153.3321 +
153.3322 +/* ========================================================================== */
153.3323 +/* === colamd debugging routines ============================================ */
153.3324 +/* ========================================================================== */
153.3325 +
153.3326 +/* When debugging is disabled, the remainder of this file is ignored. */
153.3327 +
153.3328 +#ifndef NDEBUG
153.3329 +
153.3330 +
153.3331 +/* ========================================================================== */
153.3332 +/* === debug_structures ===================================================== */
153.3333 +/* ========================================================================== */
153.3334 +
153.3335 +/*
153.3336 + At this point, all empty rows and columns are dead. All live columns
153.3337 + are "clean" (containing no dead rows) and simplicial (no supercolumns
153.3338 + yet). Rows may contain dead columns, but all live rows contain at
153.3339 + least one live column.
153.3340 +*/
153.3341 +
153.3342 +PRIVATE void debug_structures
153.3343 +(
153.3344 + /* === Parameters ======================================================= */
153.3345 +
153.3346 + Int n_row,
153.3347 + Int n_col,
153.3348 + Colamd_Row Row [],
153.3349 + Colamd_Col Col [],
153.3350 + Int A [],
153.3351 + Int n_col2
153.3352 +)
153.3353 +{
153.3354 + /* === Local variables ================================================== */
153.3355 +
153.3356 + Int i ;
153.3357 + Int c ;
153.3358 + Int *cp ;
153.3359 + Int *cp_end ;
153.3360 + Int len ;
153.3361 + Int score ;
153.3362 + Int r ;
153.3363 + Int *rp ;
153.3364 + Int *rp_end ;
153.3365 + Int deg ;
153.3366 +
153.3367 + /* === Check A, Row, and Col ============================================ */
153.3368 +
153.3369 + for (c = 0 ; c < n_col ; c++)
153.3370 + {
153.3371 + if (COL_IS_ALIVE (c))
153.3372 + {
153.3373 + len = Col [c].length ;
153.3374 + score = Col [c].shared2.score ;
153.3375 + DEBUG4 (("initial live col %5d %5d %5d\n", c, len, score)) ;
153.3376 + ASSERT (len > 0) ;
153.3377 + ASSERT (score >= 0) ;
153.3378 + ASSERT (Col [c].shared1.thickness == 1) ;
153.3379 + cp = &A [Col [c].start] ;
153.3380 + cp_end = cp + len ;
153.3381 + while (cp < cp_end)
153.3382 + {
153.3383 + r = *cp++ ;
153.3384 + ASSERT (ROW_IS_ALIVE (r)) ;
153.3385 + }
153.3386 + }
153.3387 + else
153.3388 + {
153.3389 + i = Col [c].shared2.order ;
153.3390 + ASSERT (i >= n_col2 && i < n_col) ;
153.3391 + }
153.3392 + }
153.3393 +
153.3394 + for (r = 0 ; r < n_row ; r++)
153.3395 + {
153.3396 + if (ROW_IS_ALIVE (r))
153.3397 + {
153.3398 + i = 0 ;
153.3399 + len = Row [r].length ;
153.3400 + deg = Row [r].shared1.degree ;
153.3401 + ASSERT (len > 0) ;
153.3402 + ASSERT (deg > 0) ;
153.3403 + rp = &A [Row [r].start] ;
153.3404 + rp_end = rp + len ;
153.3405 + while (rp < rp_end)
153.3406 + {
153.3407 + c = *rp++ ;
153.3408 + if (COL_IS_ALIVE (c))
153.3409 + {
153.3410 + i++ ;
153.3411 + }
153.3412 + }
153.3413 + ASSERT (i > 0) ;
153.3414 + }
153.3415 + }
153.3416 +}
153.3417 +
153.3418 +
153.3419 +/* ========================================================================== */
153.3420 +/* === debug_deg_lists ====================================================== */
153.3421 +/* ========================================================================== */
153.3422 +
153.3423 +/*
153.3424 + Prints the contents of the degree lists. Counts the number of columns
153.3425 + in the degree list and compares it to the total it should have. Also
153.3426 + checks the row degrees.
153.3427 +*/
153.3428 +
153.3429 +PRIVATE void debug_deg_lists
153.3430 +(
153.3431 + /* === Parameters ======================================================= */
153.3432 +
153.3433 + Int n_row,
153.3434 + Int n_col,
153.3435 + Colamd_Row Row [],
153.3436 + Colamd_Col Col [],
153.3437 + Int head [],
153.3438 + Int min_score,
153.3439 + Int should,
153.3440 + Int max_deg
153.3441 +)
153.3442 +{
153.3443 + /* === Local variables ================================================== */
153.3444 +
153.3445 + Int deg ;
153.3446 + Int col ;
153.3447 + Int have ;
153.3448 + Int row ;
153.3449 +
153.3450 + /* === Check the degree lists =========================================== */
153.3451 +
153.3452 + if (n_col > 10000 && colamd_debug <= 0)
153.3453 + {
153.3454 + return ;
153.3455 + }
153.3456 + have = 0 ;
153.3457 + DEBUG4 (("Degree lists: %d\n", min_score)) ;
153.3458 + for (deg = 0 ; deg <= n_col ; deg++)
153.3459 + {
153.3460 + col = head [deg] ;
153.3461 + if (col == EMPTY)
153.3462 + {
153.3463 + continue ;
153.3464 + }
153.3465 + DEBUG4 (("%d:", deg)) ;
153.3466 + while (col != EMPTY)
153.3467 + {
153.3468 + DEBUG4 ((" %d", col)) ;
153.3469 + have += Col [col].shared1.thickness ;
153.3470 + ASSERT (COL_IS_ALIVE (col)) ;
153.3471 + col = Col [col].shared4.degree_next ;
153.3472 + }
153.3473 + DEBUG4 (("\n")) ;
153.3474 + }
153.3475 + DEBUG4 (("should %d have %d\n", should, have)) ;
153.3476 + ASSERT (should == have) ;
153.3477 +
153.3478 + /* === Check the row degrees ============================================ */
153.3479 +
153.3480 + if (n_row > 10000 && colamd_debug <= 0)
153.3481 + {
153.3482 + return ;
153.3483 + }
153.3484 + for (row = 0 ; row < n_row ; row++)
153.3485 + {
153.3486 + if (ROW_IS_ALIVE (row))
153.3487 + {
153.3488 + ASSERT (Row [row].shared1.degree <= max_deg) ;
153.3489 + }
153.3490 + }
153.3491 +}
153.3492 +
153.3493 +
153.3494 +/* ========================================================================== */
153.3495 +/* === debug_mark =========================================================== */
153.3496 +/* ========================================================================== */
153.3497 +
153.3498 +/*
153.3499 + Ensures that the tag_mark is less that the maximum and also ensures that
153.3500 + each entry in the mark array is less than the tag mark.
153.3501 +*/
153.3502 +
153.3503 +PRIVATE void debug_mark
153.3504 +(
153.3505 + /* === Parameters ======================================================= */
153.3506 +
153.3507 + Int n_row,
153.3508 + Colamd_Row Row [],
153.3509 + Int tag_mark,
153.3510 + Int max_mark
153.3511 +)
153.3512 +{
153.3513 + /* === Local variables ================================================== */
153.3514 +
153.3515 + Int r ;
153.3516 +
153.3517 + /* === Check the Row marks ============================================== */
153.3518 +
153.3519 + ASSERT (tag_mark > 0 && tag_mark <= max_mark) ;
153.3520 + if (n_row > 10000 && colamd_debug <= 0)
153.3521 + {
153.3522 + return ;
153.3523 + }
153.3524 + for (r = 0 ; r < n_row ; r++)
153.3525 + {
153.3526 + ASSERT (Row [r].shared2.mark < tag_mark) ;
153.3527 + }
153.3528 +}
153.3529 +
153.3530 +
153.3531 +/* ========================================================================== */
153.3532 +/* === debug_matrix ========================================================= */
153.3533 +/* ========================================================================== */
153.3534 +
153.3535 +/*
153.3536 + Prints out the contents of the columns and the rows.
153.3537 +*/
153.3538 +
153.3539 +PRIVATE void debug_matrix
153.3540 +(
153.3541 + /* === Parameters ======================================================= */
153.3542 +
153.3543 + Int n_row,
153.3544 + Int n_col,
153.3545 + Colamd_Row Row [],
153.3546 + Colamd_Col Col [],
153.3547 + Int A []
153.3548 +)
153.3549 +{
153.3550 + /* === Local variables ================================================== */
153.3551 +
153.3552 + Int r ;
153.3553 + Int c ;
153.3554 + Int *rp ;
153.3555 + Int *rp_end ;
153.3556 + Int *cp ;
153.3557 + Int *cp_end ;
153.3558 +
153.3559 + /* === Dump the rows and columns of the matrix ========================== */
153.3560 +
153.3561 + if (colamd_debug < 3)
153.3562 + {
153.3563 + return ;
153.3564 + }
153.3565 + DEBUG3 (("DUMP MATRIX:\n")) ;
153.3566 + for (r = 0 ; r < n_row ; r++)
153.3567 + {
153.3568 + DEBUG3 (("Row %d alive? %d\n", r, ROW_IS_ALIVE (r))) ;
153.3569 + if (ROW_IS_DEAD (r))
153.3570 + {
153.3571 + continue ;
153.3572 + }
153.3573 + DEBUG3 (("start %d length %d degree %d\n",
153.3574 + Row [r].start, Row [r].length, Row [r].shared1.degree)) ;
153.3575 + rp = &A [Row [r].start] ;
153.3576 + rp_end = rp + Row [r].length ;
153.3577 + while (rp < rp_end)
153.3578 + {
153.3579 + c = *rp++ ;
153.3580 + DEBUG4 ((" %d col %d\n", COL_IS_ALIVE (c), c)) ;
153.3581 + }
153.3582 + }
153.3583 +
153.3584 + for (c = 0 ; c < n_col ; c++)
153.3585 + {
153.3586 + DEBUG3 (("Col %d alive? %d\n", c, COL_IS_ALIVE (c))) ;
153.3587 + if (COL_IS_DEAD (c))
153.3588 + {
153.3589 + continue ;
153.3590 + }
153.3591 + DEBUG3 (("start %d length %d shared1 %d shared2 %d\n",
153.3592 + Col [c].start, Col [c].length,
153.3593 + Col [c].shared1.thickness, Col [c].shared2.score)) ;
153.3594 + cp = &A [Col [c].start] ;
153.3595 + cp_end = cp + Col [c].length ;
153.3596 + while (cp < cp_end)
153.3597 + {
153.3598 + r = *cp++ ;
153.3599 + DEBUG4 ((" %d row %d\n", ROW_IS_ALIVE (r), r)) ;
153.3600 + }
153.3601 + }
153.3602 +}
153.3603 +
153.3604 +PRIVATE void colamd_get_debug
153.3605 +(
153.3606 + char *method
153.3607 +)
153.3608 +{
153.3609 + FILE *f ;
153.3610 + colamd_debug = 0 ; /* no debug printing */
153.3611 + f = fopen ("debug", "r") ;
153.3612 + if (f == (FILE *) NULL)
153.3613 + {
153.3614 + colamd_debug = 0 ;
153.3615 + }
153.3616 + else
153.3617 + {
153.3618 + fscanf (f, "%d", &colamd_debug) ;
153.3619 + fclose (f) ;
153.3620 + }
153.3621 + DEBUG0 (("%s: debug version, D = %d (THIS WILL BE SLOW!)\n",
153.3622 + method, colamd_debug)) ;
153.3623 +}
153.3624 +
153.3625 +#endif /* NDEBUG */
154.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
154.2 +++ b/src/colamd/colamd.h Mon Dec 06 13:09:21 2010 +0100
154.3 @@ -0,0 +1,69 @@
154.4 +/* colamd.h */
154.5 +
154.6 +/* Written by Andrew Makhorin <mao@gnu.org>. */
154.7 +
154.8 +#ifndef COLAMD_H
154.9 +#define COLAMD_H
154.10 +
154.11 +#define _GLPSTD_STDIO
154.12 +#include "glpenv.h"
154.13 +
154.14 +#define COLAMD_DATE "Nov 1, 2007"
154.15 +#define COLAMD_VERSION_CODE(main, sub) ((main) * 1000 + (sub))
154.16 +#define COLAMD_MAIN_VERSION 2
154.17 +#define COLAMD_SUB_VERSION 7
154.18 +#define COLAMD_SUBSUB_VERSION 1
154.19 +#define COLAMD_VERSION \
154.20 + COLAMD_VERSION_CODE(COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION)
154.21 +
154.22 +#define COLAMD_KNOBS 20
154.23 +#define COLAMD_STATS 20
154.24 +#define COLAMD_DENSE_ROW 0
154.25 +#define COLAMD_DENSE_COL 1
154.26 +#define COLAMD_AGGRESSIVE 2
154.27 +#define COLAMD_DEFRAG_COUNT 2
154.28 +#define COLAMD_STATUS 3
154.29 +#define COLAMD_INFO1 4
154.30 +#define COLAMD_INFO2 5
154.31 +#define COLAMD_INFO3 6
154.32 +
154.33 +#define COLAMD_OK (0)
154.34 +#define COLAMD_OK_BUT_JUMBLED (1)
154.35 +#define COLAMD_ERROR_A_not_present (-1)
154.36 +#define COLAMD_ERROR_p_not_present (-2)
154.37 +#define COLAMD_ERROR_nrow_negative (-3)
154.38 +#define COLAMD_ERROR_ncol_negative (-4)
154.39 +#define COLAMD_ERROR_nnz_negative (-5)
154.40 +#define COLAMD_ERROR_p0_nonzero (-6)
154.41 +#define COLAMD_ERROR_A_too_small (-7)
154.42 +#define COLAMD_ERROR_col_length_negative (-8)
154.43 +#define COLAMD_ERROR_row_index_out_of_bounds (-9)
154.44 +#define COLAMD_ERROR_out_of_memory (-10)
154.45 +#define COLAMD_ERROR_internal_error (-999)
154.46 +
154.47 +#define colamd_recommended _glp_colamd_recommended
154.48 +size_t colamd_recommended(int nnz, int n_row, int n_col);
154.49 +
154.50 +#define colamd_set_defaults _glp_colamd_set_defaults
154.51 +void colamd_set_defaults(double knobs [COLAMD_KNOBS]);
154.52 +
154.53 +#define colamd _glp_colamd
154.54 +int colamd(int n_row, int n_col, int Alen, int A[], int p[],
154.55 + double knobs[COLAMD_KNOBS], int stats[COLAMD_STATS]);
154.56 +
154.57 +#define symamd _glp_symamd
154.58 +int symamd(int n, int A[], int p[], int perm[],
154.59 + double knobs[COLAMD_KNOBS], int stats[COLAMD_STATS],
154.60 + void *(*allocate)(size_t, size_t), void(*release)(void *));
154.61 +
154.62 +#define colamd_report _glp_colamd_report
154.63 +void colamd_report(int stats[COLAMD_STATS]);
154.64 +
154.65 +#define symamd_report _glp_symamd_report
154.66 +void symamd_report(int stats[COLAMD_STATS]);
154.67 +
154.68 +#define colamd_printf xprintf
154.69 +
154.70 +#endif
154.71 +
154.72 +/* eof */
155.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
155.2 +++ b/src/glpapi.h Mon Dec 06 13:09:21 2010 +0100
155.3 @@ -0,0 +1,314 @@
155.4 +/* glpapi.h (application program interface) */
155.5 +
155.6 +/***********************************************************************
155.7 +* This code is part of GLPK (GNU Linear Programming Kit).
155.8 +*
155.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
155.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
155.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
155.12 +* E-mail: <mao@gnu.org>.
155.13 +*
155.14 +* GLPK is free software: you can redistribute it and/or modify it
155.15 +* under the terms of the GNU General Public License as published by
155.16 +* the Free Software Foundation, either version 3 of the License, or
155.17 +* (at your option) any later version.
155.18 +*
155.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
155.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
155.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
155.22 +* License for more details.
155.23 +*
155.24 +* You should have received a copy of the GNU General Public License
155.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
155.26 +***********************************************************************/
155.27 +
155.28 +#ifndef GLPAPI_H
155.29 +#define GLPAPI_H
155.30 +
155.31 +#define GLP_PROB_DEFINED
155.32 +typedef struct glp_prob glp_prob;
155.33 +
155.34 +#include "glpk.h"
155.35 +#include "glpavl.h"
155.36 +#include "glpbfd.h"
155.37 +
155.38 +typedef struct GLPROW GLPROW;
155.39 +typedef struct GLPCOL GLPCOL;
155.40 +typedef struct GLPAIJ GLPAIJ;
155.41 +
155.42 +#define GLP_PROB_MAGIC 0xD7D9D6C2
155.43 +
155.44 +struct glp_prob
155.45 +{ /* LP/MIP problem object */
155.46 + int magic;
155.47 + /* magic value used for debugging */
155.48 + DMP *pool;
155.49 + /* memory pool to store problem object components */
155.50 + glp_tree *tree;
155.51 + /* pointer to the search tree; set by the MIP solver when this
155.52 + object is used in the tree as a core MIP object */
155.53 + void *parms;
155.54 + /* reserved for backward compatibility */
155.55 + /*--------------------------------------------------------------*/
155.56 + /* LP/MIP data */
155.57 + char *name;
155.58 + /* problem name (1 to 255 chars); NULL means no name is assigned
155.59 + to the problem */
155.60 + char *obj;
155.61 + /* objective function name (1 to 255 chars); NULL means no name
155.62 + is assigned to the objective function */
155.63 + int dir;
155.64 + /* optimization direction flag (objective "sense"):
155.65 + GLP_MIN - minimization
155.66 + GLP_MAX - maximization */
155.67 + double c0;
155.68 + /* constant term of the objective function ("shift") */
155.69 + int m_max;
155.70 + /* length of the array of rows (enlarged automatically) */
155.71 + int n_max;
155.72 + /* length of the array of columns (enlarged automatically) */
155.73 + int m;
155.74 + /* number of rows, 0 <= m <= m_max */
155.75 + int n;
155.76 + /* number of columns, 0 <= n <= n_max */
155.77 + int nnz;
155.78 + /* number of non-zero constraint coefficients, nnz >= 0 */
155.79 + GLPROW **row; /* GLPROW *row[1+m_max]; */
155.80 + /* row[i], 1 <= i <= m, is a pointer to i-th row */
155.81 + GLPCOL **col; /* GLPCOL *col[1+n_max]; */
155.82 + /* col[j], 1 <= j <= n, is a pointer to j-th column */
155.83 + AVL *r_tree;
155.84 + /* row index to find rows by their names; NULL means this index
155.85 + does not exist */
155.86 + AVL *c_tree;
155.87 + /* column index to find columns by their names; NULL means this
155.88 + index does not exist */
155.89 + /*--------------------------------------------------------------*/
155.90 + /* basis factorization (LP) */
155.91 + int valid;
155.92 + /* the factorization is valid only if this flag is set */
155.93 + int *head; /* int head[1+m_max]; */
155.94 + /* basis header (valid only if the factorization is valid);
155.95 + head[i] = k is the ordinal number of auxiliary (1 <= k <= m)
155.96 + or structural (m+1 <= k <= m+n) variable which corresponds to
155.97 + i-th basic variable xB[i], 1 <= i <= m */
155.98 + glp_bfcp *bfcp;
155.99 + /* basis factorization control parameters; may be NULL */
155.100 + BFD *bfd; /* BFD bfd[1:m,1:m]; */
155.101 + /* basis factorization driver; may be NULL */
155.102 + /*--------------------------------------------------------------*/
155.103 + /* basic solution (LP) */
155.104 + int pbs_stat;
155.105 + /* primal basic solution status:
155.106 + GLP_UNDEF - primal solution is undefined
155.107 + GLP_FEAS - primal solution is feasible
155.108 + GLP_INFEAS - primal solution is infeasible
155.109 + GLP_NOFEAS - no primal feasible solution exists */
155.110 + int dbs_stat;
155.111 + /* dual basic solution status:
155.112 + GLP_UNDEF - dual solution is undefined
155.113 + GLP_FEAS - dual solution is feasible
155.114 + GLP_INFEAS - dual solution is infeasible
155.115 + GLP_NOFEAS - no dual feasible solution exists */
155.116 + double obj_val;
155.117 + /* objective function value */
155.118 + int it_cnt;
155.119 + /* simplex method iteration count; increased by one on performing
155.120 + one simplex iteration */
155.121 + int some;
155.122 + /* ordinal number of some auxiliary or structural variable having
155.123 + certain property, 0 <= some <= m+n */
155.124 + /*--------------------------------------------------------------*/
155.125 + /* interior-point solution (LP) */
155.126 + int ipt_stat;
155.127 + /* interior-point solution status:
155.128 + GLP_UNDEF - interior solution is undefined
155.129 + GLP_OPT - interior solution is optimal
155.130 + GLP_INFEAS - interior solution is infeasible
155.131 + GLP_NOFEAS - no feasible solution exists */
155.132 + double ipt_obj;
155.133 + /* objective function value */
155.134 + /*--------------------------------------------------------------*/
155.135 + /* integer solution (MIP) */
155.136 + int mip_stat;
155.137 + /* integer solution status:
155.138 + GLP_UNDEF - integer solution is undefined
155.139 + GLP_OPT - integer solution is optimal
155.140 + GLP_FEAS - integer solution is feasible
155.141 + GLP_NOFEAS - no integer solution exists */
155.142 + double mip_obj;
155.143 + /* objective function value */
155.144 +};
155.145 +
155.146 +struct GLPROW
155.147 +{ /* LP/MIP row (auxiliary variable) */
155.148 + int i;
155.149 + /* ordinal number (1 to m) assigned to this row */
155.150 + char *name;
155.151 + /* row name (1 to 255 chars); NULL means no name is assigned to
155.152 + this row */
155.153 + AVLNODE *node;
155.154 + /* pointer to corresponding node in the row index; NULL means
155.155 + that either the row index does not exist or this row has no
155.156 + name assigned */
155.157 +#if 1 /* 20/IX-2008 */
155.158 + int level;
155.159 + unsigned char origin;
155.160 + unsigned char klass;
155.161 +#endif
155.162 + int type;
155.163 + /* type of the auxiliary variable:
155.164 + GLP_FR - free variable
155.165 + GLP_LO - variable with lower bound
155.166 + GLP_UP - variable with upper bound
155.167 + GLP_DB - double-bounded variable
155.168 + GLP_FX - fixed variable */
155.169 + double lb; /* non-scaled */
155.170 + /* lower bound; if the row has no lower bound, lb is zero */
155.171 + double ub; /* non-scaled */
155.172 + /* upper bound; if the row has no upper bound, ub is zero */
155.173 + /* if the row type is GLP_FX, ub is equal to lb */
155.174 + GLPAIJ *ptr; /* non-scaled */
155.175 + /* pointer to doubly linked list of constraint coefficients which
155.176 + are placed in this row */
155.177 + double rii;
155.178 + /* diagonal element r[i,i] of scaling matrix R for this row;
155.179 + if the scaling is not used, r[i,i] is 1 */
155.180 + int stat;
155.181 + /* status of the auxiliary variable:
155.182 + GLP_BS - basic variable
155.183 + GLP_NL - non-basic variable on lower bound
155.184 + GLP_NU - non-basic variable on upper bound
155.185 + GLP_NF - non-basic free variable
155.186 + GLP_NS - non-basic fixed variable */
155.187 + int bind;
155.188 + /* if the auxiliary variable is basic, head[bind] refers to this
155.189 + row, otherwise, bind is 0; this attribute is valid only if the
155.190 + basis factorization is valid */
155.191 + double prim; /* non-scaled */
155.192 + /* primal value of the auxiliary variable in basic solution */
155.193 + double dual; /* non-scaled */
155.194 + /* dual value of the auxiliary variable in basic solution */
155.195 + double pval; /* non-scaled */
155.196 + /* primal value of the auxiliary variable in interior solution */
155.197 + double dval; /* non-scaled */
155.198 + /* dual value of the auxiliary variable in interior solution */
155.199 + double mipx; /* non-scaled */
155.200 + /* primal value of the auxiliary variable in integer solution */
155.201 +};
155.202 +
155.203 +struct GLPCOL
155.204 +{ /* LP/MIP column (structural variable) */
155.205 + int j;
155.206 + /* ordinal number (1 to n) assigned to this column */
155.207 + char *name;
155.208 + /* column name (1 to 255 chars); NULL means no name is assigned
155.209 + to this column */
155.210 + AVLNODE *node;
155.211 + /* pointer to corresponding node in the column index; NULL means
155.212 + that either the column index does not exist or the column has
155.213 + no name assigned */
155.214 + int kind;
155.215 + /* kind of the structural variable:
155.216 + GLP_CV - continuous variable
155.217 + GLP_IV - integer or binary variable */
155.218 + int type;
155.219 + /* type of the structural variable:
155.220 + GLP_FR - free variable
155.221 + GLP_LO - variable with lower bound
155.222 + GLP_UP - variable with upper bound
155.223 + GLP_DB - double-bounded variable
155.224 + GLP_FX - fixed variable */
155.225 + double lb; /* non-scaled */
155.226 + /* lower bound; if the column has no lower bound, lb is zero */
155.227 + double ub; /* non-scaled */
155.228 + /* upper bound; if the column has no upper bound, ub is zero */
155.229 + /* if the column type is GLP_FX, ub is equal to lb */
155.230 + double coef; /* non-scaled */
155.231 + /* objective coefficient at the structural variable */
155.232 + GLPAIJ *ptr; /* non-scaled */
155.233 + /* pointer to doubly linked list of constraint coefficients which
155.234 + are placed in this column */
155.235 + double sjj;
155.236 + /* diagonal element s[j,j] of scaling matrix S for this column;
155.237 + if the scaling is not used, s[j,j] is 1 */
155.238 + int stat;
155.239 + /* status of the structural variable:
155.240 + GLP_BS - basic variable
155.241 + GLP_NL - non-basic variable on lower bound
155.242 + GLP_NU - non-basic variable on upper bound
155.243 + GLP_NF - non-basic free variable
155.244 + GLP_NS - non-basic fixed variable */
155.245 + int bind;
155.246 + /* if the structural variable is basic, head[bind] refers to
155.247 + this column; otherwise, bind is 0; this attribute is valid only
155.248 + if the basis factorization is valid */
155.249 + double prim; /* non-scaled */
155.250 + /* primal value of the structural variable in basic solution */
155.251 + double dual; /* non-scaled */
155.252 + /* dual value of the structural variable in basic solution */
155.253 + double pval; /* non-scaled */
155.254 + /* primal value of the structural variable in interior solution */
155.255 + double dval; /* non-scaled */
155.256 + /* dual value of the structural variable in interior solution */
155.257 + double mipx; /* non-scaled */
155.258 + /* primal value of the structural variable in integer solution */
155.259 +};
155.260 +
155.261 +struct GLPAIJ
155.262 +{ /* constraint coefficient a[i,j] */
155.263 + GLPROW *row;
155.264 + /* pointer to row, where this coefficient is placed */
155.265 + GLPCOL *col;
155.266 + /* pointer to column, where this coefficient is placed */
155.267 + double val;
155.268 + /* numeric (non-zero) value of this coefficient */
155.269 + GLPAIJ *r_prev;
155.270 + /* pointer to previous coefficient in the same row */
155.271 + GLPAIJ *r_next;
155.272 + /* pointer to next coefficient in the same row */
155.273 + GLPAIJ *c_prev;
155.274 + /* pointer to previous coefficient in the same column */
155.275 + GLPAIJ *c_next;
155.276 + /* pointer to next coefficient in the same column */
155.277 +};
155.278 +
155.279 +void _glp_check_kkt(glp_prob *P, int sol, int cond, double *ae_max,
155.280 + int *ae_ind, double *re_max, int *re_ind);
155.281 +/* check feasibility and optimality conditions */
155.282 +
155.283 +#define lpx_put_solution _glp_put_solution
155.284 +void lpx_put_solution(glp_prob *lp, int inval, const int *p_stat,
155.285 + const int *d_stat, const double *obj_val, const int r_stat[],
155.286 + const double r_prim[], const double r_dual[], const int c_stat[],
155.287 + const double c_prim[], const double c_dual[]);
155.288 +/* store basic solution components */
155.289 +
155.290 +#define lpx_put_mip_soln _glp_put_mip_soln
155.291 +void lpx_put_mip_soln(LPX *lp, int i_stat, double row_mipx[],
155.292 + double col_mipx[]);
155.293 +/* store mixed integer solution components */
155.294 +
155.295 +#if 1 /* 28/XI-2009 */
155.296 +int _glp_analyze_row(glp_prob *P, int len, const int ind[],
155.297 + const double val[], int type, double rhs, double eps, int *_piv,
155.298 + double *_x, double *_dx, double *_y, double *_dy, double *_dz);
155.299 +/* simulate one iteration of dual simplex method */
155.300 +#endif
155.301 +
155.302 +#if 1 /* 08/XII-2009 */
155.303 +void _glp_mpl_init_rand(glp_tran *tran, int seed);
155.304 +#endif
155.305 +
155.306 +#define glp_skpgen _glp_skpgen
155.307 +void glp_skpgen(int n, int r, int type, int v, int s, int a[],
155.308 + int *b, int c[]);
155.309 +/* Pisinger's 0-1 single knapsack problem generator */
155.310 +
155.311 +#if 1 /* 28/V-2010 */
155.312 +int _glp_intopt1(glp_prob *P, const glp_iocp *parm);
155.313 +#endif
155.314 +
155.315 +#endif
155.316 +
155.317 +/* eof */
156.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
156.2 +++ b/src/glpapi01.c Mon Dec 06 13:09:21 2010 +0100
156.3 @@ -0,0 +1,1570 @@
156.4 +/* glpapi01.c (problem creating and modifying routines) */
156.5 +
156.6 +/***********************************************************************
156.7 +* This code is part of GLPK (GNU Linear Programming Kit).
156.8 +*
156.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
156.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
156.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
156.12 +* E-mail: <mao@gnu.org>.
156.13 +*
156.14 +* GLPK is free software: you can redistribute it and/or modify it
156.15 +* under the terms of the GNU General Public License as published by
156.16 +* the Free Software Foundation, either version 3 of the License, or
156.17 +* (at your option) any later version.
156.18 +*
156.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
156.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
156.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
156.22 +* License for more details.
156.23 +*
156.24 +* You should have received a copy of the GNU General Public License
156.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
156.26 +***********************************************************************/
156.27 +
156.28 +#include "glpios.h"
156.29 +
156.30 +/* CAUTION: DO NOT CHANGE THE LIMITS BELOW */
156.31 +
156.32 +#define M_MAX 100000000 /* = 100*10^6 */
156.33 +/* maximal number of rows in the problem object */
156.34 +
156.35 +#define N_MAX 100000000 /* = 100*10^6 */
156.36 +/* maximal number of columns in the problem object */
156.37 +
156.38 +#define NNZ_MAX 500000000 /* = 500*10^6 */
156.39 +/* maximal number of constraint coefficients in the problem object */
156.40 +
156.41 +/***********************************************************************
156.42 +* NAME
156.43 +*
156.44 +* glp_create_prob - create problem object
156.45 +*
156.46 +* SYNOPSIS
156.47 +*
156.48 +* glp_prob *glp_create_prob(void);
156.49 +*
156.50 +* DESCRIPTION
156.51 +*
156.52 +* The routine glp_create_prob creates a new problem object, which is
156.53 +* initially "empty", i.e. has no rows and columns.
156.54 +*
156.55 +* RETURNS
156.56 +*
156.57 +* The routine returns a pointer to the object created, which should be
156.58 +* used in any subsequent operations on this object. */
156.59 +
156.60 +static void create_prob(glp_prob *lp)
156.61 +{ lp->magic = GLP_PROB_MAGIC;
156.62 + lp->pool = dmp_create_pool();
156.63 +#if 0 /* 17/XI-2009 */
156.64 + lp->cps = xmalloc(sizeof(struct LPXCPS));
156.65 + lpx_reset_parms(lp);
156.66 +#else
156.67 + lp->parms = NULL;
156.68 +#endif
156.69 + lp->tree = NULL;
156.70 +#if 0
156.71 + lp->lwa = 0;
156.72 + lp->cwa = NULL;
156.73 +#endif
156.74 + /* LP/MIP data */
156.75 + lp->name = NULL;
156.76 + lp->obj = NULL;
156.77 + lp->dir = GLP_MIN;
156.78 + lp->c0 = 0.0;
156.79 + lp->m_max = 100;
156.80 + lp->n_max = 200;
156.81 + lp->m = lp->n = 0;
156.82 + lp->nnz = 0;
156.83 + lp->row = xcalloc(1+lp->m_max, sizeof(GLPROW *));
156.84 + lp->col = xcalloc(1+lp->n_max, sizeof(GLPCOL *));
156.85 + lp->r_tree = lp->c_tree = NULL;
156.86 + /* basis factorization */
156.87 + lp->valid = 0;
156.88 + lp->head = xcalloc(1+lp->m_max, sizeof(int));
156.89 + lp->bfcp = NULL;
156.90 + lp->bfd = NULL;
156.91 + /* basic solution (LP) */
156.92 + lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
156.93 + lp->obj_val = 0.0;
156.94 + lp->it_cnt = 0;
156.95 + lp->some = 0;
156.96 + /* interior-point solution (LP) */
156.97 + lp->ipt_stat = GLP_UNDEF;
156.98 + lp->ipt_obj = 0.0;
156.99 + /* integer solution (MIP) */
156.100 + lp->mip_stat = GLP_UNDEF;
156.101 + lp->mip_obj = 0.0;
156.102 + return;
156.103 +}
156.104 +
156.105 +glp_prob *glp_create_prob(void)
156.106 +{ glp_prob *lp;
156.107 + lp = xmalloc(sizeof(glp_prob));
156.108 + create_prob(lp);
156.109 + return lp;
156.110 +}
156.111 +
156.112 +/***********************************************************************
156.113 +* NAME
156.114 +*
156.115 +* glp_set_prob_name - assign (change) problem name
156.116 +*
156.117 +* SYNOPSIS
156.118 +*
156.119 +* void glp_set_prob_name(glp_prob *lp, const char *name);
156.120 +*
156.121 +* DESCRIPTION
156.122 +*
156.123 +* The routine glp_set_prob_name assigns a given symbolic name (1 up to
156.124 +* 255 characters) to the specified problem object.
156.125 +*
156.126 +* If the parameter name is NULL or empty string, the routine erases an
156.127 +* existing symbolic name of the problem object. */
156.128 +
156.129 +void glp_set_prob_name(glp_prob *lp, const char *name)
156.130 +{ glp_tree *tree = lp->tree;
156.131 + if (tree != NULL && tree->reason != 0)
156.132 + xerror("glp_set_prob_name: operation not allowed\n");
156.133 + if (lp->name != NULL)
156.134 + { dmp_free_atom(lp->pool, lp->name, strlen(lp->name)+1);
156.135 + lp->name = NULL;
156.136 + }
156.137 + if (!(name == NULL || name[0] == '\0'))
156.138 + { int k;
156.139 + for (k = 0; name[k] != '\0'; k++)
156.140 + { if (k == 256)
156.141 + xerror("glp_set_prob_name: problem name too long\n");
156.142 + if (iscntrl((unsigned char)name[k]))
156.143 + xerror("glp_set_prob_name: problem name contains invalid"
156.144 + " character(s)\n");
156.145 + }
156.146 + lp->name = dmp_get_atom(lp->pool, strlen(name)+1);
156.147 + strcpy(lp->name, name);
156.148 + }
156.149 + return;
156.150 +}
156.151 +
156.152 +/***********************************************************************
156.153 +* NAME
156.154 +*
156.155 +* glp_set_obj_name - assign (change) objective function name
156.156 +*
156.157 +* SYNOPSIS
156.158 +*
156.159 +* void glp_set_obj_name(glp_prob *lp, const char *name);
156.160 +*
156.161 +* DESCRIPTION
156.162 +*
156.163 +* The routine glp_set_obj_name assigns a given symbolic name (1 up to
156.164 +* 255 characters) to the objective function of the specified problem
156.165 +* object.
156.166 +*
156.167 +* If the parameter name is NULL or empty string, the routine erases an
156.168 +* existing name of the objective function. */
156.169 +
156.170 +void glp_set_obj_name(glp_prob *lp, const char *name)
156.171 +{ glp_tree *tree = lp->tree;
156.172 + if (tree != NULL && tree->reason != 0)
156.173 + xerror("glp_set_obj_name: operation not allowed\n");
156.174 + if (lp->obj != NULL)
156.175 + { dmp_free_atom(lp->pool, lp->obj, strlen(lp->obj)+1);
156.176 + lp->obj = NULL;
156.177 + }
156.178 + if (!(name == NULL || name[0] == '\0'))
156.179 + { int k;
156.180 + for (k = 0; name[k] != '\0'; k++)
156.181 + { if (k == 256)
156.182 + xerror("glp_set_obj_name: objective name too long\n");
156.183 + if (iscntrl((unsigned char)name[k]))
156.184 + xerror("glp_set_obj_name: objective name contains invali"
156.185 + "d character(s)\n");
156.186 + }
156.187 + lp->obj = dmp_get_atom(lp->pool, strlen(name)+1);
156.188 + strcpy(lp->obj, name);
156.189 + }
156.190 + return;
156.191 +}
156.192 +
156.193 +/***********************************************************************
156.194 +* NAME
156.195 +*
156.196 +* glp_set_obj_dir - set (change) optimization direction flag
156.197 +*
156.198 +* SYNOPSIS
156.199 +*
156.200 +* void glp_set_obj_dir(glp_prob *lp, int dir);
156.201 +*
156.202 +* DESCRIPTION
156.203 +*
156.204 +* The routine glp_set_obj_dir sets (changes) optimization direction
156.205 +* flag (i.e. "sense" of the objective function) as specified by the
156.206 +* parameter dir:
156.207 +*
156.208 +* GLP_MIN - minimization;
156.209 +* GLP_MAX - maximization. */
156.210 +
156.211 +void glp_set_obj_dir(glp_prob *lp, int dir)
156.212 +{ glp_tree *tree = lp->tree;
156.213 + if (tree != NULL && tree->reason != 0)
156.214 + xerror("glp_set_obj_dir: operation not allowed\n");
156.215 + if (!(dir == GLP_MIN || dir == GLP_MAX))
156.216 + xerror("glp_set_obj_dir: dir = %d; invalid direction flag\n",
156.217 + dir);
156.218 + lp->dir = dir;
156.219 + return;
156.220 +}
156.221 +
156.222 +/***********************************************************************
156.223 +* NAME
156.224 +*
156.225 +* glp_add_rows - add new rows to problem object
156.226 +*
156.227 +* SYNOPSIS
156.228 +*
156.229 +* int glp_add_rows(glp_prob *lp, int nrs);
156.230 +*
156.231 +* DESCRIPTION
156.232 +*
156.233 +* The routine glp_add_rows adds nrs rows (constraints) to the specified
156.234 +* problem object. New rows are always added to the end of the row list,
156.235 +* so the ordinal numbers of existing rows remain unchanged.
156.236 +*
156.237 +* Being added each new row is initially free (unbounded) and has empty
156.238 +* list of the constraint coefficients.
156.239 +*
156.240 +* RETURNS
156.241 +*
156.242 +* The routine glp_add_rows returns the ordinal number of the first new
156.243 +* row added to the problem object. */
156.244 +
156.245 +int glp_add_rows(glp_prob *lp, int nrs)
156.246 +{ glp_tree *tree = lp->tree;
156.247 + GLPROW *row;
156.248 + int m_new, i;
156.249 + /* determine new number of rows */
156.250 + if (nrs < 1)
156.251 + xerror("glp_add_rows: nrs = %d; invalid number of rows\n",
156.252 + nrs);
156.253 + if (nrs > M_MAX - lp->m)
156.254 + xerror("glp_add_rows: nrs = %d; too many rows\n", nrs);
156.255 + m_new = lp->m + nrs;
156.256 + /* increase the room, if necessary */
156.257 + if (lp->m_max < m_new)
156.258 + { GLPROW **save = lp->row;
156.259 + while (lp->m_max < m_new)
156.260 + { lp->m_max += lp->m_max;
156.261 + xassert(lp->m_max > 0);
156.262 + }
156.263 + lp->row = xcalloc(1+lp->m_max, sizeof(GLPROW *));
156.264 + memcpy(&lp->row[1], &save[1], lp->m * sizeof(GLPROW *));
156.265 + xfree(save);
156.266 + /* do not forget about the basis header */
156.267 + xfree(lp->head);
156.268 + lp->head = xcalloc(1+lp->m_max, sizeof(int));
156.269 + }
156.270 + /* add new rows to the end of the row list */
156.271 + for (i = lp->m+1; i <= m_new; i++)
156.272 + { /* create row descriptor */
156.273 + lp->row[i] = row = dmp_get_atom(lp->pool, sizeof(GLPROW));
156.274 + row->i = i;
156.275 + row->name = NULL;
156.276 + row->node = NULL;
156.277 +#if 1 /* 20/IX-2008 */
156.278 + row->level = 0;
156.279 + row->origin = 0;
156.280 + row->klass = 0;
156.281 + if (tree != NULL)
156.282 + { switch (tree->reason)
156.283 + { case 0:
156.284 + break;
156.285 + case GLP_IROWGEN:
156.286 + xassert(tree->curr != NULL);
156.287 + row->level = tree->curr->level;
156.288 + row->origin = GLP_RF_LAZY;
156.289 + break;
156.290 + case GLP_ICUTGEN:
156.291 + xassert(tree->curr != NULL);
156.292 + row->level = tree->curr->level;
156.293 + row->origin = GLP_RF_CUT;
156.294 + break;
156.295 + default:
156.296 + xassert(tree != tree);
156.297 + }
156.298 + }
156.299 +#endif
156.300 + row->type = GLP_FR;
156.301 + row->lb = row->ub = 0.0;
156.302 + row->ptr = NULL;
156.303 + row->rii = 1.0;
156.304 + row->stat = GLP_BS;
156.305 +#if 0
156.306 + row->bind = -1;
156.307 +#else
156.308 + row->bind = 0;
156.309 +#endif
156.310 + row->prim = row->dual = 0.0;
156.311 + row->pval = row->dval = 0.0;
156.312 + row->mipx = 0.0;
156.313 + }
156.314 + /* set new number of rows */
156.315 + lp->m = m_new;
156.316 + /* invalidate the basis factorization */
156.317 + lp->valid = 0;
156.318 +#if 1
156.319 + if (tree != NULL && tree->reason != 0) tree->reopt = 1;
156.320 +#endif
156.321 + /* return the ordinal number of the first row added */
156.322 + return m_new - nrs + 1;
156.323 +}
156.324 +
156.325 +/***********************************************************************
156.326 +* NAME
156.327 +*
156.328 +* glp_add_cols - add new columns to problem object
156.329 +*
156.330 +* SYNOPSIS
156.331 +*
156.332 +* int glp_add_cols(glp_prob *lp, int ncs);
156.333 +*
156.334 +* DESCRIPTION
156.335 +*
156.336 +* The routine glp_add_cols adds ncs columns (structural variables) to
156.337 +* the specified problem object. New columns are always added to the end
156.338 +* of the column list, so the ordinal numbers of existing columns remain
156.339 +* unchanged.
156.340 +*
156.341 +* Being added each new column is initially fixed at zero and has empty
156.342 +* list of the constraint coefficients.
156.343 +*
156.344 +* RETURNS
156.345 +*
156.346 +* The routine glp_add_cols returns the ordinal number of the first new
156.347 +* column added to the problem object. */
156.348 +
156.349 +int glp_add_cols(glp_prob *lp, int ncs)
156.350 +{ glp_tree *tree = lp->tree;
156.351 + GLPCOL *col;
156.352 + int n_new, j;
156.353 + if (tree != NULL && tree->reason != 0)
156.354 + xerror("glp_add_cols: operation not allowed\n");
156.355 + /* determine new number of columns */
156.356 + if (ncs < 1)
156.357 + xerror("glp_add_cols: ncs = %d; invalid number of columns\n",
156.358 + ncs);
156.359 + if (ncs > N_MAX - lp->n)
156.360 + xerror("glp_add_cols: ncs = %d; too many columns\n", ncs);
156.361 + n_new = lp->n + ncs;
156.362 + /* increase the room, if necessary */
156.363 + if (lp->n_max < n_new)
156.364 + { GLPCOL **save = lp->col;
156.365 + while (lp->n_max < n_new)
156.366 + { lp->n_max += lp->n_max;
156.367 + xassert(lp->n_max > 0);
156.368 + }
156.369 + lp->col = xcalloc(1+lp->n_max, sizeof(GLPCOL *));
156.370 + memcpy(&lp->col[1], &save[1], lp->n * sizeof(GLPCOL *));
156.371 + xfree(save);
156.372 + }
156.373 + /* add new columns to the end of the column list */
156.374 + for (j = lp->n+1; j <= n_new; j++)
156.375 + { /* create column descriptor */
156.376 + lp->col[j] = col = dmp_get_atom(lp->pool, sizeof(GLPCOL));
156.377 + col->j = j;
156.378 + col->name = NULL;
156.379 + col->node = NULL;
156.380 + col->kind = GLP_CV;
156.381 + col->type = GLP_FX;
156.382 + col->lb = col->ub = 0.0;
156.383 + col->coef = 0.0;
156.384 + col->ptr = NULL;
156.385 + col->sjj = 1.0;
156.386 + col->stat = GLP_NS;
156.387 +#if 0
156.388 + col->bind = -1;
156.389 +#else
156.390 + col->bind = 0; /* the basis may remain valid */
156.391 +#endif
156.392 + col->prim = col->dual = 0.0;
156.393 + col->pval = col->dval = 0.0;
156.394 + col->mipx = 0.0;
156.395 + }
156.396 + /* set new number of columns */
156.397 + lp->n = n_new;
156.398 + /* return the ordinal number of the first column added */
156.399 + return n_new - ncs + 1;
156.400 +}
156.401 +
156.402 +/***********************************************************************
156.403 +* NAME
156.404 +*
156.405 +* glp_set_row_name - assign (change) row name
156.406 +*
156.407 +* SYNOPSIS
156.408 +*
156.409 +* void glp_set_row_name(glp_prob *lp, int i, const char *name);
156.410 +*
156.411 +* DESCRIPTION
156.412 +*
156.413 +* The routine glp_set_row_name assigns a given symbolic name (1 up to
156.414 +* 255 characters) to i-th row (auxiliary variable) of the specified
156.415 +* problem object.
156.416 +*
156.417 +* If the parameter name is NULL or empty string, the routine erases an
156.418 +* existing name of i-th row. */
156.419 +
156.420 +void glp_set_row_name(glp_prob *lp, int i, const char *name)
156.421 +{ glp_tree *tree = lp->tree;
156.422 + GLPROW *row;
156.423 + if (!(1 <= i && i <= lp->m))
156.424 + xerror("glp_set_row_name: i = %d; row number out of range\n",
156.425 + i);
156.426 + row = lp->row[i];
156.427 + if (tree != NULL && tree->reason != 0)
156.428 + { xassert(tree->curr != NULL);
156.429 + xassert(row->level == tree->curr->level);
156.430 + }
156.431 + if (row->name != NULL)
156.432 + { if (row->node != NULL)
156.433 + { xassert(lp->r_tree != NULL);
156.434 + avl_delete_node(lp->r_tree, row->node);
156.435 + row->node = NULL;
156.436 + }
156.437 + dmp_free_atom(lp->pool, row->name, strlen(row->name)+1);
156.438 + row->name = NULL;
156.439 + }
156.440 + if (!(name == NULL || name[0] == '\0'))
156.441 + { int k;
156.442 + for (k = 0; name[k] != '\0'; k++)
156.443 + { if (k == 256)
156.444 + xerror("glp_set_row_name: i = %d; row name too long\n",
156.445 + i);
156.446 + if (iscntrl((unsigned char)name[k]))
156.447 + xerror("glp_set_row_name: i = %d: row name contains inva"
156.448 + "lid character(s)\n", i);
156.449 + }
156.450 + row->name = dmp_get_atom(lp->pool, strlen(name)+1);
156.451 + strcpy(row->name, name);
156.452 + if (lp->r_tree != NULL)
156.453 + { xassert(row->node == NULL);
156.454 + row->node = avl_insert_node(lp->r_tree, row->name);
156.455 + avl_set_node_link(row->node, row);
156.456 + }
156.457 + }
156.458 + return;
156.459 +}
156.460 +
156.461 +/***********************************************************************
156.462 +* NAME
156.463 +*
156.464 +* glp_set_col_name - assign (change) column name
156.465 +*
156.466 +* SYNOPSIS
156.467 +*
156.468 +* void glp_set_col_name(glp_prob *lp, int j, const char *name);
156.469 +*
156.470 +* DESCRIPTION
156.471 +*
156.472 +* The routine glp_set_col_name assigns a given symbolic name (1 up to
156.473 +* 255 characters) to j-th column (structural variable) of the specified
156.474 +* problem object.
156.475 +*
156.476 +* If the parameter name is NULL or empty string, the routine erases an
156.477 +* existing name of j-th column. */
156.478 +
156.479 +void glp_set_col_name(glp_prob *lp, int j, const char *name)
156.480 +{ glp_tree *tree = lp->tree;
156.481 + GLPCOL *col;
156.482 + if (tree != NULL && tree->reason != 0)
156.483 + xerror("glp_set_col_name: operation not allowed\n");
156.484 + if (!(1 <= j && j <= lp->n))
156.485 + xerror("glp_set_col_name: j = %d; column number out of range\n"
156.486 + , j);
156.487 + col = lp->col[j];
156.488 + if (col->name != NULL)
156.489 + { if (col->node != NULL)
156.490 + { xassert(lp->c_tree != NULL);
156.491 + avl_delete_node(lp->c_tree, col->node);
156.492 + col->node = NULL;
156.493 + }
156.494 + dmp_free_atom(lp->pool, col->name, strlen(col->name)+1);
156.495 + col->name = NULL;
156.496 + }
156.497 + if (!(name == NULL || name[0] == '\0'))
156.498 + { int k;
156.499 + for (k = 0; name[k] != '\0'; k++)
156.500 + { if (k == 256)
156.501 + xerror("glp_set_col_name: j = %d; column name too long\n"
156.502 + , j);
156.503 + if (iscntrl((unsigned char)name[k]))
156.504 + xerror("glp_set_col_name: j = %d: column name contains i"
156.505 + "nvalid character(s)\n", j);
156.506 + }
156.507 + col->name = dmp_get_atom(lp->pool, strlen(name)+1);
156.508 + strcpy(col->name, name);
156.509 + if (lp->c_tree != NULL && col->name != NULL)
156.510 + { xassert(col->node == NULL);
156.511 + col->node = avl_insert_node(lp->c_tree, col->name);
156.512 + avl_set_node_link(col->node, col);
156.513 + }
156.514 + }
156.515 + return;
156.516 +}
156.517 +
156.518 +/***********************************************************************
156.519 +* NAME
156.520 +*
156.521 +* glp_set_row_bnds - set (change) row bounds
156.522 +*
156.523 +* SYNOPSIS
156.524 +*
156.525 +* void glp_set_row_bnds(glp_prob *lp, int i, int type, double lb,
156.526 +* double ub);
156.527 +*
156.528 +* DESCRIPTION
156.529 +*
156.530 +* The routine glp_set_row_bnds sets (changes) the type and bounds of
156.531 +* i-th row (auxiliary variable) of the specified problem object.
156.532 +*
156.533 +* Parameters type, lb, and ub specify the type, lower bound, and upper
156.534 +* bound, respectively, as follows:
156.535 +*
156.536 +* Type Bounds Comments
156.537 +* ------------------------------------------------------
156.538 +* GLP_FR -inf < x < +inf Free variable
156.539 +* GLP_LO lb <= x < +inf Variable with lower bound
156.540 +* GLP_UP -inf < x <= ub Variable with upper bound
156.541 +* GLP_DB lb <= x <= ub Double-bounded variable
156.542 +* GLP_FX x = lb Fixed variable
156.543 +*
156.544 +* where x is the auxiliary variable associated with i-th row.
156.545 +*
156.546 +* If the row has no lower bound, the parameter lb is ignored. If the
156.547 +* row has no upper bound, the parameter ub is ignored. If the row is
156.548 +* an equality constraint (i.e. the corresponding auxiliary variable is
156.549 +* of fixed type), only the parameter lb is used while the parameter ub
156.550 +* is ignored. */
156.551 +
156.552 +void glp_set_row_bnds(glp_prob *lp, int i, int type, double lb,
156.553 + double ub)
156.554 +{ GLPROW *row;
156.555 + if (!(1 <= i && i <= lp->m))
156.556 + xerror("glp_set_row_bnds: i = %d; row number out of range\n",
156.557 + i);
156.558 + row = lp->row[i];
156.559 + row->type = type;
156.560 + switch (type)
156.561 + { case GLP_FR:
156.562 + row->lb = row->ub = 0.0;
156.563 + if (row->stat != GLP_BS) row->stat = GLP_NF;
156.564 + break;
156.565 + case GLP_LO:
156.566 + row->lb = lb, row->ub = 0.0;
156.567 + if (row->stat != GLP_BS) row->stat = GLP_NL;
156.568 + break;
156.569 + case GLP_UP:
156.570 + row->lb = 0.0, row->ub = ub;
156.571 + if (row->stat != GLP_BS) row->stat = GLP_NU;
156.572 + break;
156.573 + case GLP_DB:
156.574 + row->lb = lb, row->ub = ub;
156.575 + if (!(row->stat == GLP_BS ||
156.576 + row->stat == GLP_NL || row->stat == GLP_NU))
156.577 + row->stat = (fabs(lb) <= fabs(ub) ? GLP_NL : GLP_NU);
156.578 + break;
156.579 + case GLP_FX:
156.580 + row->lb = row->ub = lb;
156.581 + if (row->stat != GLP_BS) row->stat = GLP_NS;
156.582 + break;
156.583 + default:
156.584 + xerror("glp_set_row_bnds: i = %d; type = %d; invalid row ty"
156.585 + "pe\n", i, type);
156.586 + }
156.587 + return;
156.588 +}
156.589 +
156.590 +/***********************************************************************
156.591 +* NAME
156.592 +*
156.593 +* glp_set_col_bnds - set (change) column bounds
156.594 +*
156.595 +* SYNOPSIS
156.596 +*
156.597 +* void glp_set_col_bnds(glp_prob *lp, int j, int type, double lb,
156.598 +* double ub);
156.599 +*
156.600 +* DESCRIPTION
156.601 +*
156.602 +* The routine glp_set_col_bnds sets (changes) the type and bounds of
156.603 +* j-th column (structural variable) of the specified problem object.
156.604 +*
156.605 +* Parameters type, lb, and ub specify the type, lower bound, and upper
156.606 +* bound, respectively, as follows:
156.607 +*
156.608 +* Type Bounds Comments
156.609 +* ------------------------------------------------------
156.610 +* GLP_FR -inf < x < +inf Free variable
156.611 +* GLP_LO lb <= x < +inf Variable with lower bound
156.612 +* GLP_UP -inf < x <= ub Variable with upper bound
156.613 +* GLP_DB lb <= x <= ub Double-bounded variable
156.614 +* GLP_FX x = lb Fixed variable
156.615 +*
156.616 +* where x is the structural variable associated with j-th column.
156.617 +*
156.618 +* If the column has no lower bound, the parameter lb is ignored. If the
156.619 +* column has no upper bound, the parameter ub is ignored. If the column
156.620 +* is of fixed type, only the parameter lb is used while the parameter
156.621 +* ub is ignored. */
156.622 +
156.623 +void glp_set_col_bnds(glp_prob *lp, int j, int type, double lb,
156.624 + double ub)
156.625 +{ GLPCOL *col;
156.626 + if (!(1 <= j && j <= lp->n))
156.627 + xerror("glp_set_col_bnds: j = %d; column number out of range\n"
156.628 + , j);
156.629 + col = lp->col[j];
156.630 + col->type = type;
156.631 + switch (type)
156.632 + { case GLP_FR:
156.633 + col->lb = col->ub = 0.0;
156.634 + if (col->stat != GLP_BS) col->stat = GLP_NF;
156.635 + break;
156.636 + case GLP_LO:
156.637 + col->lb = lb, col->ub = 0.0;
156.638 + if (col->stat != GLP_BS) col->stat = GLP_NL;
156.639 + break;
156.640 + case GLP_UP:
156.641 + col->lb = 0.0, col->ub = ub;
156.642 + if (col->stat != GLP_BS) col->stat = GLP_NU;
156.643 + break;
156.644 + case GLP_DB:
156.645 + col->lb = lb, col->ub = ub;
156.646 + if (!(col->stat == GLP_BS ||
156.647 + col->stat == GLP_NL || col->stat == GLP_NU))
156.648 + col->stat = (fabs(lb) <= fabs(ub) ? GLP_NL : GLP_NU);
156.649 + break;
156.650 + case GLP_FX:
156.651 + col->lb = col->ub = lb;
156.652 + if (col->stat != GLP_BS) col->stat = GLP_NS;
156.653 + break;
156.654 + default:
156.655 + xerror("glp_set_col_bnds: j = %d; type = %d; invalid column"
156.656 + " type\n", j, type);
156.657 + }
156.658 + return;
156.659 +}
156.660 +
156.661 +/***********************************************************************
156.662 +* NAME
156.663 +*
156.664 +* glp_set_obj_coef - set (change) obj. coefficient or constant term
156.665 +*
156.666 +* SYNOPSIS
156.667 +*
156.668 +* void glp_set_obj_coef(glp_prob *lp, int j, double coef);
156.669 +*
156.670 +* DESCRIPTION
156.671 +*
156.672 +* The routine glp_set_obj_coef sets (changes) objective coefficient at
156.673 +* j-th column (structural variable) of the specified problem object.
156.674 +*
156.675 +* If the parameter j is 0, the routine sets (changes) the constant term
156.676 +* ("shift") of the objective function. */
156.677 +
156.678 +void glp_set_obj_coef(glp_prob *lp, int j, double coef)
156.679 +{ glp_tree *tree = lp->tree;
156.680 + if (tree != NULL && tree->reason != 0)
156.681 + xerror("glp_set_obj_coef: operation not allowed\n");
156.682 + if (!(0 <= j && j <= lp->n))
156.683 + xerror("glp_set_obj_coef: j = %d; column number out of range\n"
156.684 + , j);
156.685 + if (j == 0)
156.686 + lp->c0 = coef;
156.687 + else
156.688 + lp->col[j]->coef = coef;
156.689 + return;
156.690 +}
156.691 +
156.692 +/***********************************************************************
156.693 +* NAME
156.694 +*
156.695 +* glp_set_mat_row - set (replace) row of the constraint matrix
156.696 +*
156.697 +* SYNOPSIS
156.698 +*
156.699 +* void glp_set_mat_row(glp_prob *lp, int i, int len, const int ind[],
156.700 +* const double val[]);
156.701 +*
156.702 +* DESCRIPTION
156.703 +*
156.704 +* The routine glp_set_mat_row stores (replaces) the contents of i-th
156.705 +* row of the constraint matrix of the specified problem object.
156.706 +*
156.707 +* Column indices and numeric values of new row elements must be placed
156.708 +* in locations ind[1], ..., ind[len] and val[1], ..., val[len], where
156.709 +* 0 <= len <= n is the new length of i-th row, n is the current number
156.710 +* of columns in the problem object. Elements with identical column
156.711 +* indices are not allowed. Zero elements are allowed, but they are not
156.712 +* stored in the constraint matrix.
156.713 +*
156.714 +* If the parameter len is zero, the parameters ind and/or val can be
156.715 +* specified as NULL. */
156.716 +
156.717 +void glp_set_mat_row(glp_prob *lp, int i, int len, const int ind[],
156.718 + const double val[])
156.719 +{ glp_tree *tree = lp->tree;
156.720 + GLPROW *row;
156.721 + GLPCOL *col;
156.722 + GLPAIJ *aij, *next;
156.723 + int j, k;
156.724 + /* obtain pointer to i-th row */
156.725 + if (!(1 <= i && i <= lp->m))
156.726 + xerror("glp_set_mat_row: i = %d; row number out of range\n",
156.727 + i);
156.728 + row = lp->row[i];
156.729 + if (tree != NULL && tree->reason != 0)
156.730 + { xassert(tree->curr != NULL);
156.731 + xassert(row->level == tree->curr->level);
156.732 + }
156.733 + /* remove all existing elements from i-th row */
156.734 + while (row->ptr != NULL)
156.735 + { /* take next element in the row */
156.736 + aij = row->ptr;
156.737 + /* remove the element from the row list */
156.738 + row->ptr = aij->r_next;
156.739 + /* obtain pointer to corresponding column */
156.740 + col = aij->col;
156.741 + /* remove the element from the column list */
156.742 + if (aij->c_prev == NULL)
156.743 + col->ptr = aij->c_next;
156.744 + else
156.745 + aij->c_prev->c_next = aij->c_next;
156.746 + if (aij->c_next == NULL)
156.747 + ;
156.748 + else
156.749 + aij->c_next->c_prev = aij->c_prev;
156.750 + /* return the element to the memory pool */
156.751 + dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
156.752 + /* if the corresponding column is basic, invalidate the basis
156.753 + factorization */
156.754 + if (col->stat == GLP_BS) lp->valid = 0;
156.755 + }
156.756 + /* store new contents of i-th row */
156.757 + if (!(0 <= len && len <= lp->n))
156.758 + xerror("glp_set_mat_row: i = %d; len = %d; invalid row length "
156.759 + "\n", i, len);
156.760 + if (len > NNZ_MAX - lp->nnz)
156.761 + xerror("glp_set_mat_row: i = %d; len = %d; too many constraint"
156.762 + " coefficients\n", i, len);
156.763 + for (k = 1; k <= len; k++)
156.764 + { /* take number j of corresponding column */
156.765 + j = ind[k];
156.766 + /* obtain pointer to j-th column */
156.767 + if (!(1 <= j && j <= lp->n))
156.768 + xerror("glp_set_mat_row: i = %d; ind[%d] = %d; column index"
156.769 + " out of range\n", i, k, j);
156.770 + col = lp->col[j];
156.771 + /* if there is element with the same column index, it can only
156.772 + be found in the beginning of j-th column list */
156.773 + if (col->ptr != NULL && col->ptr->row->i == i)
156.774 + xerror("glp_set_mat_row: i = %d; ind[%d] = %d; duplicate co"
156.775 + "lumn indices not allowed\n", i, k, j);
156.776 + /* create new element */
156.777 + aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++;
156.778 + aij->row = row;
156.779 + aij->col = col;
156.780 + aij->val = val[k];
156.781 + /* add the new element to the beginning of i-th row and j-th
156.782 + column lists */
156.783 + aij->r_prev = NULL;
156.784 + aij->r_next = row->ptr;
156.785 + aij->c_prev = NULL;
156.786 + aij->c_next = col->ptr;
156.787 + if (aij->r_next != NULL) aij->r_next->r_prev = aij;
156.788 + if (aij->c_next != NULL) aij->c_next->c_prev = aij;
156.789 + row->ptr = col->ptr = aij;
156.790 + /* if the corresponding column is basic, invalidate the basis
156.791 + factorization */
156.792 + if (col->stat == GLP_BS && aij->val != 0.0) lp->valid = 0;
156.793 + }
156.794 + /* remove zero elements from i-th row */
156.795 + for (aij = row->ptr; aij != NULL; aij = next)
156.796 + { next = aij->r_next;
156.797 + if (aij->val == 0.0)
156.798 + { /* remove the element from the row list */
156.799 + if (aij->r_prev == NULL)
156.800 + row->ptr = next;
156.801 + else
156.802 + aij->r_prev->r_next = next;
156.803 + if (next == NULL)
156.804 + ;
156.805 + else
156.806 + next->r_prev = aij->r_prev;
156.807 + /* remove the element from the column list */
156.808 + xassert(aij->c_prev == NULL);
156.809 + aij->col->ptr = aij->c_next;
156.810 + if (aij->c_next != NULL) aij->c_next->c_prev = NULL;
156.811 + /* return the element to the memory pool */
156.812 + dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
156.813 + }
156.814 + }
156.815 + return;
156.816 +}
156.817 +
156.818 +/***********************************************************************
156.819 +* NAME
156.820 +*
156.821 +* glp_set_mat_col - set (replace) column of the constraint matrix
156.822 +*
156.823 +* SYNOPSIS
156.824 +*
156.825 +* void glp_set_mat_col(glp_prob *lp, int j, int len, const int ind[],
156.826 +* const double val[]);
156.827 +*
156.828 +* DESCRIPTION
156.829 +*
156.830 +* The routine glp_set_mat_col stores (replaces) the contents of j-th
156.831 +* column of the constraint matrix of the specified problem object.
156.832 +*
156.833 +* Row indices and numeric values of new column elements must be placed
156.834 +* in locations ind[1], ..., ind[len] and val[1], ..., val[len], where
156.835 +* 0 <= len <= m is the new length of j-th column, m is the current
156.836 +* number of rows in the problem object. Elements with identical column
156.837 +* indices are not allowed. Zero elements are allowed, but they are not
156.838 +* stored in the constraint matrix.
156.839 +*
156.840 +* If the parameter len is zero, the parameters ind and/or val can be
156.841 +* specified as NULL. */
156.842 +
156.843 +void glp_set_mat_col(glp_prob *lp, int j, int len, const int ind[],
156.844 + const double val[])
156.845 +{ glp_tree *tree = lp->tree;
156.846 + GLPROW *row;
156.847 + GLPCOL *col;
156.848 + GLPAIJ *aij, *next;
156.849 + int i, k;
156.850 + if (tree != NULL && tree->reason != 0)
156.851 + xerror("glp_set_mat_col: operation not allowed\n");
156.852 + /* obtain pointer to j-th column */
156.853 + if (!(1 <= j && j <= lp->n))
156.854 + xerror("glp_set_mat_col: j = %d; column number out of range\n",
156.855 + j);
156.856 + col = lp->col[j];
156.857 + /* remove all existing elements from j-th column */
156.858 + while (col->ptr != NULL)
156.859 + { /* take next element in the column */
156.860 + aij = col->ptr;
156.861 + /* remove the element from the column list */
156.862 + col->ptr = aij->c_next;
156.863 + /* obtain pointer to corresponding row */
156.864 + row = aij->row;
156.865 + /* remove the element from the row list */
156.866 + if (aij->r_prev == NULL)
156.867 + row->ptr = aij->r_next;
156.868 + else
156.869 + aij->r_prev->r_next = aij->r_next;
156.870 + if (aij->r_next == NULL)
156.871 + ;
156.872 + else
156.873 + aij->r_next->r_prev = aij->r_prev;
156.874 + /* return the element to the memory pool */
156.875 + dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
156.876 + }
156.877 + /* store new contents of j-th column */
156.878 + if (!(0 <= len && len <= lp->m))
156.879 + xerror("glp_set_mat_col: j = %d; len = %d; invalid column leng"
156.880 + "th\n", j, len);
156.881 + if (len > NNZ_MAX - lp->nnz)
156.882 + xerror("glp_set_mat_col: j = %d; len = %d; too many constraint"
156.883 + " coefficients\n", j, len);
156.884 + for (k = 1; k <= len; k++)
156.885 + { /* take number i of corresponding row */
156.886 + i = ind[k];
156.887 + /* obtain pointer to i-th row */
156.888 + if (!(1 <= i && i <= lp->m))
156.889 + xerror("glp_set_mat_col: j = %d; ind[%d] = %d; row index ou"
156.890 + "t of range\n", j, k, i);
156.891 + row = lp->row[i];
156.892 + /* if there is element with the same row index, it can only be
156.893 + found in the beginning of i-th row list */
156.894 + if (row->ptr != NULL && row->ptr->col->j == j)
156.895 + xerror("glp_set_mat_col: j = %d; ind[%d] = %d; duplicate ro"
156.896 + "w indices not allowed\n", j, k, i);
156.897 + /* create new element */
156.898 + aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++;
156.899 + aij->row = row;
156.900 + aij->col = col;
156.901 + aij->val = val[k];
156.902 + /* add the new element to the beginning of i-th row and j-th
156.903 + column lists */
156.904 + aij->r_prev = NULL;
156.905 + aij->r_next = row->ptr;
156.906 + aij->c_prev = NULL;
156.907 + aij->c_next = col->ptr;
156.908 + if (aij->r_next != NULL) aij->r_next->r_prev = aij;
156.909 + if (aij->c_next != NULL) aij->c_next->c_prev = aij;
156.910 + row->ptr = col->ptr = aij;
156.911 + }
156.912 + /* remove zero elements from j-th column */
156.913 + for (aij = col->ptr; aij != NULL; aij = next)
156.914 + { next = aij->c_next;
156.915 + if (aij->val == 0.0)
156.916 + { /* remove the element from the row list */
156.917 + xassert(aij->r_prev == NULL);
156.918 + aij->row->ptr = aij->r_next;
156.919 + if (aij->r_next != NULL) aij->r_next->r_prev = NULL;
156.920 + /* remove the element from the column list */
156.921 + if (aij->c_prev == NULL)
156.922 + col->ptr = next;
156.923 + else
156.924 + aij->c_prev->c_next = next;
156.925 + if (next == NULL)
156.926 + ;
156.927 + else
156.928 + next->c_prev = aij->c_prev;
156.929 + /* return the element to the memory pool */
156.930 + dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
156.931 + }
156.932 + }
156.933 + /* if j-th column is basic, invalidate the basis factorization */
156.934 + if (col->stat == GLP_BS) lp->valid = 0;
156.935 + return;
156.936 +}
156.937 +
156.938 +/***********************************************************************
156.939 +* NAME
156.940 +*
156.941 +* glp_load_matrix - load (replace) the whole constraint matrix
156.942 +*
156.943 +* SYNOPSIS
156.944 +*
156.945 +* void glp_load_matrix(glp_prob *lp, int ne, const int ia[],
156.946 +* const int ja[], const double ar[]);
156.947 +*
156.948 +* DESCRIPTION
156.949 +*
156.950 +* The routine glp_load_matrix loads the constraint matrix passed in
156.951 +* the arrays ia, ja, and ar into the specified problem object. Before
156.952 +* loading the current contents of the constraint matrix is destroyed.
156.953 +*
156.954 +* Constraint coefficients (elements of the constraint matrix) must be
156.955 +* specified as triplets (ia[k], ja[k], ar[k]) for k = 1, ..., ne,
156.956 +* where ia[k] is the row index, ja[k] is the column index, ar[k] is a
156.957 +* numeric value of corresponding constraint coefficient. The parameter
156.958 +* ne specifies the total number of (non-zero) elements in the matrix
156.959 +* to be loaded. Coefficients with identical indices are not allowed.
156.960 +* Zero coefficients are allowed, however, they are not stored in the
156.961 +* constraint matrix.
156.962 +*
156.963 +* If the parameter ne is zero, the parameters ia, ja, and ar can be
156.964 +* specified as NULL. */
156.965 +
156.966 +void glp_load_matrix(glp_prob *lp, int ne, const int ia[],
156.967 + const int ja[], const double ar[])
156.968 +{ glp_tree *tree = lp->tree;
156.969 + GLPROW *row;
156.970 + GLPCOL *col;
156.971 + GLPAIJ *aij, *next;
156.972 + int i, j, k;
156.973 + if (tree != NULL && tree->reason != 0)
156.974 + xerror("glp_load_matrix: operation not allowed\n");
156.975 + /* clear the constraint matrix */
156.976 + for (i = 1; i <= lp->m; i++)
156.977 + { row = lp->row[i];
156.978 + while (row->ptr != NULL)
156.979 + { aij = row->ptr;
156.980 + row->ptr = aij->r_next;
156.981 + dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
156.982 + }
156.983 + }
156.984 + xassert(lp->nnz == 0);
156.985 + for (j = 1; j <= lp->n; j++) lp->col[j]->ptr = NULL;
156.986 + /* load the new contents of the constraint matrix and build its
156.987 + row lists */
156.988 + if (ne < 0)
156.989 + xerror("glp_load_matrix: ne = %d; invalid number of constraint"
156.990 + " coefficients\n", ne);
156.991 + if (ne > NNZ_MAX)
156.992 + xerror("glp_load_matrix: ne = %d; too many constraint coeffici"
156.993 + "ents\n", ne);
156.994 + for (k = 1; k <= ne; k++)
156.995 + { /* take indices of new element */
156.996 + i = ia[k], j = ja[k];
156.997 + /* obtain pointer to i-th row */
156.998 + if (!(1 <= i && i <= lp->m))
156.999 + xerror("glp_load_matrix: ia[%d] = %d; row index out of rang"
156.1000 + "e\n", k, i);
156.1001 + row = lp->row[i];
156.1002 + /* obtain pointer to j-th column */
156.1003 + if (!(1 <= j && j <= lp->n))
156.1004 + xerror("glp_load_matrix: ja[%d] = %d; column index out of r"
156.1005 + "ange\n", k, j);
156.1006 + col = lp->col[j];
156.1007 + /* create new element */
156.1008 + aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++;
156.1009 + aij->row = row;
156.1010 + aij->col = col;
156.1011 + aij->val = ar[k];
156.1012 + /* add the new element to the beginning of i-th row list */
156.1013 + aij->r_prev = NULL;
156.1014 + aij->r_next = row->ptr;
156.1015 + if (aij->r_next != NULL) aij->r_next->r_prev = aij;
156.1016 + row->ptr = aij;
156.1017 + }
156.1018 + xassert(lp->nnz == ne);
156.1019 + /* build column lists of the constraint matrix and check elements
156.1020 + with identical indices */
156.1021 + for (i = 1; i <= lp->m; i++)
156.1022 + { for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
156.1023 + { /* obtain pointer to corresponding column */
156.1024 + col = aij->col;
156.1025 + /* if there is element with identical indices, it can only
156.1026 + be found in the beginning of j-th column list */
156.1027 + if (col->ptr != NULL && col->ptr->row->i == i)
156.1028 + { for (k = 1; k <= ne; k++)
156.1029 + if (ia[k] == i && ja[k] == col->j) break;
156.1030 + xerror("glp_load_mat: ia[%d] = %d; ja[%d] = %d; duplicat"
156.1031 + "e indices not allowed\n", k, i, k, col->j);
156.1032 + }
156.1033 + /* add the element to the beginning of j-th column list */
156.1034 + aij->c_prev = NULL;
156.1035 + aij->c_next = col->ptr;
156.1036 + if (aij->c_next != NULL) aij->c_next->c_prev = aij;
156.1037 + col->ptr = aij;
156.1038 + }
156.1039 + }
156.1040 + /* remove zero elements from the constraint matrix */
156.1041 + for (i = 1; i <= lp->m; i++)
156.1042 + { row = lp->row[i];
156.1043 + for (aij = row->ptr; aij != NULL; aij = next)
156.1044 + { next = aij->r_next;
156.1045 + if (aij->val == 0.0)
156.1046 + { /* remove the element from the row list */
156.1047 + if (aij->r_prev == NULL)
156.1048 + row->ptr = next;
156.1049 + else
156.1050 + aij->r_prev->r_next = next;
156.1051 + if (next == NULL)
156.1052 + ;
156.1053 + else
156.1054 + next->r_prev = aij->r_prev;
156.1055 + /* remove the element from the column list */
156.1056 + if (aij->c_prev == NULL)
156.1057 + aij->col->ptr = aij->c_next;
156.1058 + else
156.1059 + aij->c_prev->c_next = aij->c_next;
156.1060 + if (aij->c_next == NULL)
156.1061 + ;
156.1062 + else
156.1063 + aij->c_next->c_prev = aij->c_prev;
156.1064 + /* return the element to the memory pool */
156.1065 + dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
156.1066 + }
156.1067 + }
156.1068 + }
156.1069 + /* invalidate the basis factorization */
156.1070 + lp->valid = 0;
156.1071 + return;
156.1072 +}
156.1073 +
156.1074 +/***********************************************************************
156.1075 +* NAME
156.1076 +*
156.1077 +* glp_check_dup - check for duplicate elements in sparse matrix
156.1078 +*
156.1079 +* SYNOPSIS
156.1080 +*
156.1081 +* int glp_check_dup(int m, int n, int ne, const int ia[],
156.1082 +* const int ja[]);
156.1083 +*
156.1084 +* DESCRIPTION
156.1085 +*
156.1086 +* The routine glp_check_dup checks for duplicate elements (that is,
156.1087 +* elements with identical indices) in a sparse matrix specified in the
156.1088 +* coordinate format.
156.1089 +*
156.1090 +* The parameters m and n specifies, respectively, the number of rows
156.1091 +* and columns in the matrix, m >= 0, n >= 0.
156.1092 +*
156.1093 +* The parameter ne specifies the number of (structurally) non-zero
156.1094 +* elements in the matrix, ne >= 0.
156.1095 +*
156.1096 +* Elements of the matrix are specified as doublets (ia[k],ja[k]) for
156.1097 +* k = 1,...,ne, where ia[k] is a row index, ja[k] is a column index.
156.1098 +*
156.1099 +* The routine glp_check_dup can be used prior to a call to the routine
156.1100 +* glp_load_matrix to check that the constraint matrix to be loaded has
156.1101 +* no duplicate elements.
156.1102 +*
156.1103 +* RETURNS
156.1104 +*
156.1105 +* The routine glp_check_dup returns one of the following values:
156.1106 +*
156.1107 +* 0 - the matrix has no duplicate elements;
156.1108 +*
156.1109 +* -k - indices ia[k] or/and ja[k] are out of range;
156.1110 +*
156.1111 +* +k - element (ia[k],ja[k]) is duplicate. */
156.1112 +
156.1113 +int glp_check_dup(int m, int n, int ne, const int ia[], const int ja[])
156.1114 +{ int i, j, k, *ptr, *next, ret;
156.1115 + char *flag;
156.1116 + if (m < 0)
156.1117 + xerror("glp_check_dup: m = %d; invalid parameter\n");
156.1118 + if (n < 0)
156.1119 + xerror("glp_check_dup: n = %d; invalid parameter\n");
156.1120 + if (ne < 0)
156.1121 + xerror("glp_check_dup: ne = %d; invalid parameter\n");
156.1122 + if (ne > 0 && ia == NULL)
156.1123 + xerror("glp_check_dup: ia = %p; invalid parameter\n", ia);
156.1124 + if (ne > 0 && ja == NULL)
156.1125 + xerror("glp_check_dup: ja = %p; invalid parameter\n", ja);
156.1126 + for (k = 1; k <= ne; k++)
156.1127 + { i = ia[k], j = ja[k];
156.1128 + if (!(1 <= i && i <= m && 1 <= j && j <= n))
156.1129 + { ret = -k;
156.1130 + goto done;
156.1131 + }
156.1132 + }
156.1133 + if (m == 0 || n == 0)
156.1134 + { ret = 0;
156.1135 + goto done;
156.1136 + }
156.1137 + /* allocate working arrays */
156.1138 + ptr = xcalloc(1+m, sizeof(int));
156.1139 + next = xcalloc(1+ne, sizeof(int));
156.1140 + flag = xcalloc(1+n, sizeof(char));
156.1141 + /* build row lists */
156.1142 + for (i = 1; i <= m; i++)
156.1143 + ptr[i] = 0;
156.1144 + for (k = 1; k <= ne; k++)
156.1145 + { i = ia[k];
156.1146 + next[k] = ptr[i];
156.1147 + ptr[i] = k;
156.1148 + }
156.1149 + /* clear column flags */
156.1150 + for (j = 1; j <= n; j++)
156.1151 + flag[j] = 0;
156.1152 + /* check for duplicate elements */
156.1153 + for (i = 1; i <= m; i++)
156.1154 + { for (k = ptr[i]; k != 0; k = next[k])
156.1155 + { j = ja[k];
156.1156 + if (flag[j])
156.1157 + { /* find first element (i,j) */
156.1158 + for (k = 1; k <= ne; k++)
156.1159 + if (ia[k] == i && ja[k] == j) break;
156.1160 + xassert(k <= ne);
156.1161 + /* find next (duplicate) element (i,j) */
156.1162 + for (k++; k <= ne; k++)
156.1163 + if (ia[k] == i && ja[k] == j) break;
156.1164 + xassert(k <= ne);
156.1165 + ret = +k;
156.1166 + goto skip;
156.1167 + }
156.1168 + flag[j] = 1;
156.1169 + }
156.1170 + /* clear column flags */
156.1171 + for (k = ptr[i]; k != 0; k = next[k])
156.1172 + flag[ja[k]] = 0;
156.1173 + }
156.1174 + /* no duplicate element found */
156.1175 + ret = 0;
156.1176 +skip: /* free working arrays */
156.1177 + xfree(ptr);
156.1178 + xfree(next);
156.1179 + xfree(flag);
156.1180 +done: return ret;
156.1181 +}
156.1182 +
156.1183 +/***********************************************************************
156.1184 +* NAME
156.1185 +*
156.1186 +* glp_sort_matrix - sort elements of the constraint matrix
156.1187 +*
156.1188 +* SYNOPSIS
156.1189 +*
156.1190 +* void glp_sort_matrix(glp_prob *P);
156.1191 +*
156.1192 +* DESCRIPTION
156.1193 +*
156.1194 +* The routine glp_sort_matrix sorts elements of the constraint matrix
156.1195 +* rebuilding its row and column linked lists. On exit from the routine
156.1196 +* the constraint matrix is not changed, however, elements in the row
156.1197 +* linked lists become ordered by ascending column indices, and the
156.1198 +* elements in the column linked lists become ordered by ascending row
156.1199 +* indices. */
156.1200 +
156.1201 +void glp_sort_matrix(glp_prob *P)
156.1202 +{ GLPAIJ *aij;
156.1203 + int i, j;
156.1204 + if (P == NULL || P->magic != GLP_PROB_MAGIC)
156.1205 + xerror("glp_sort_matrix: P = %p; invalid problem object\n",
156.1206 + P);
156.1207 + /* rebuild row linked lists */
156.1208 + for (i = P->m; i >= 1; i--)
156.1209 + P->row[i]->ptr = NULL;
156.1210 + for (j = P->n; j >= 1; j--)
156.1211 + { for (aij = P->col[j]->ptr; aij != NULL; aij = aij->c_next)
156.1212 + { i = aij->row->i;
156.1213 + aij->r_prev = NULL;
156.1214 + aij->r_next = P->row[i]->ptr;
156.1215 + if (aij->r_next != NULL) aij->r_next->r_prev = aij;
156.1216 + P->row[i]->ptr = aij;
156.1217 + }
156.1218 + }
156.1219 + /* rebuild column linked lists */
156.1220 + for (j = P->n; j >= 1; j--)
156.1221 + P->col[j]->ptr = NULL;
156.1222 + for (i = P->m; i >= 1; i--)
156.1223 + { for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next)
156.1224 + { j = aij->col->j;
156.1225 + aij->c_prev = NULL;
156.1226 + aij->c_next = P->col[j]->ptr;
156.1227 + if (aij->c_next != NULL) aij->c_next->c_prev = aij;
156.1228 + P->col[j]->ptr = aij;
156.1229 + }
156.1230 + }
156.1231 + return;
156.1232 +}
156.1233 +
156.1234 +/***********************************************************************
156.1235 +* NAME
156.1236 +*
156.1237 +* glp_del_rows - delete rows from problem object
156.1238 +*
156.1239 +* SYNOPSIS
156.1240 +*
156.1241 +* void glp_del_rows(glp_prob *lp, int nrs, const int num[]);
156.1242 +*
156.1243 +* DESCRIPTION
156.1244 +*
156.1245 +* The routine glp_del_rows deletes rows from the specified problem
156.1246 +* object. Ordinal numbers of rows to be deleted should be placed in
156.1247 +* locations num[1], ..., num[nrs], where nrs > 0.
156.1248 +*
156.1249 +* Note that deleting rows involves changing ordinal numbers of other
156.1250 +* rows remaining in the problem object. New ordinal numbers of the
156.1251 +* remaining rows are assigned under the assumption that the original
156.1252 +* order of rows is not changed. */
156.1253 +
156.1254 +void glp_del_rows(glp_prob *lp, int nrs, const int num[])
156.1255 +{ glp_tree *tree = lp->tree;
156.1256 + GLPROW *row;
156.1257 + int i, k, m_new;
156.1258 + /* mark rows to be deleted */
156.1259 + if (!(1 <= nrs && nrs <= lp->m))
156.1260 + xerror("glp_del_rows: nrs = %d; invalid number of rows\n",
156.1261 + nrs);
156.1262 + for (k = 1; k <= nrs; k++)
156.1263 + { /* take the number of row to be deleted */
156.1264 + i = num[k];
156.1265 + /* obtain pointer to i-th row */
156.1266 + if (!(1 <= i && i <= lp->m))
156.1267 + xerror("glp_del_rows: num[%d] = %d; row number out of range"
156.1268 + "\n", k, i);
156.1269 + row = lp->row[i];
156.1270 + if (tree != NULL && tree->reason != 0)
156.1271 + { if (!(tree->reason == GLP_IROWGEN ||
156.1272 + tree->reason == GLP_ICUTGEN))
156.1273 + xerror("glp_del_rows: operation not allowed\n");
156.1274 + xassert(tree->curr != NULL);
156.1275 + if (row->level != tree->curr->level)
156.1276 + xerror("glp_del_rows: num[%d] = %d; invalid attempt to d"
156.1277 + "elete row created not in current subproblem\n", k,i);
156.1278 + if (row->stat != GLP_BS)
156.1279 + xerror("glp_del_rows: num[%d] = %d; invalid attempt to d"
156.1280 + "elete active row (constraint)\n", k, i);
156.1281 + tree->reinv = 1;
156.1282 + }
156.1283 + /* check that the row is not marked yet */
156.1284 + if (row->i == 0)
156.1285 + xerror("glp_del_rows: num[%d] = %d; duplicate row numbers n"
156.1286 + "ot allowed\n", k, i);
156.1287 + /* erase symbolic name assigned to the row */
156.1288 + glp_set_row_name(lp, i, NULL);
156.1289 + xassert(row->node == NULL);
156.1290 + /* erase corresponding row of the constraint matrix */
156.1291 + glp_set_mat_row(lp, i, 0, NULL, NULL);
156.1292 + xassert(row->ptr == NULL);
156.1293 + /* mark the row to be deleted */
156.1294 + row->i = 0;
156.1295 + }
156.1296 + /* delete all marked rows from the row list */
156.1297 + m_new = 0;
156.1298 + for (i = 1; i <= lp->m; i++)
156.1299 + { /* obtain pointer to i-th row */
156.1300 + row = lp->row[i];
156.1301 + /* check if the row is marked */
156.1302 + if (row->i == 0)
156.1303 + { /* it is marked, delete it */
156.1304 + dmp_free_atom(lp->pool, row, sizeof(GLPROW));
156.1305 + }
156.1306 + else
156.1307 + { /* it is not marked; keep it */
156.1308 + row->i = ++m_new;
156.1309 + lp->row[row->i] = row;
156.1310 + }
156.1311 + }
156.1312 + /* set new number of rows */
156.1313 + lp->m = m_new;
156.1314 + /* invalidate the basis factorization */
156.1315 + lp->valid = 0;
156.1316 + return;
156.1317 +}
156.1318 +
156.1319 +/***********************************************************************
156.1320 +* NAME
156.1321 +*
156.1322 +* glp_del_cols - delete columns from problem object
156.1323 +*
156.1324 +* SYNOPSIS
156.1325 +*
156.1326 +* void glp_del_cols(glp_prob *lp, int ncs, const int num[]);
156.1327 +*
156.1328 +* DESCRIPTION
156.1329 +*
156.1330 +* The routine glp_del_cols deletes columns from the specified problem
156.1331 +* object. Ordinal numbers of columns to be deleted should be placed in
156.1332 +* locations num[1], ..., num[ncs], where ncs > 0.
156.1333 +*
156.1334 +* Note that deleting columns involves changing ordinal numbers of
156.1335 +* other columns remaining in the problem object. New ordinal numbers
156.1336 +* of the remaining columns are assigned under the assumption that the
156.1337 +* original order of columns is not changed. */
156.1338 +
156.1339 +void glp_del_cols(glp_prob *lp, int ncs, const int num[])
156.1340 +{ glp_tree *tree = lp->tree;
156.1341 + GLPCOL *col;
156.1342 + int j, k, n_new;
156.1343 + if (tree != NULL && tree->reason != 0)
156.1344 + xerror("glp_del_cols: operation not allowed\n");
156.1345 + /* mark columns to be deleted */
156.1346 + if (!(1 <= ncs && ncs <= lp->n))
156.1347 + xerror("glp_del_cols: ncs = %d; invalid number of columns\n",
156.1348 + ncs);
156.1349 + for (k = 1; k <= ncs; k++)
156.1350 + { /* take the number of column to be deleted */
156.1351 + j = num[k];
156.1352 + /* obtain pointer to j-th column */
156.1353 + if (!(1 <= j && j <= lp->n))
156.1354 + xerror("glp_del_cols: num[%d] = %d; column number out of ra"
156.1355 + "nge", k, j);
156.1356 + col = lp->col[j];
156.1357 + /* check that the column is not marked yet */
156.1358 + if (col->j == 0)
156.1359 + xerror("glp_del_cols: num[%d] = %d; duplicate column number"
156.1360 + "s not allowed\n", k, j);
156.1361 + /* erase symbolic name assigned to the column */
156.1362 + glp_set_col_name(lp, j, NULL);
156.1363 + xassert(col->node == NULL);
156.1364 + /* erase corresponding column of the constraint matrix */
156.1365 + glp_set_mat_col(lp, j, 0, NULL, NULL);
156.1366 + xassert(col->ptr == NULL);
156.1367 + /* mark the column to be deleted */
156.1368 + col->j = 0;
156.1369 + /* if it is basic, invalidate the basis factorization */
156.1370 + if (col->stat == GLP_BS) lp->valid = 0;
156.1371 + }
156.1372 + /* delete all marked columns from the column list */
156.1373 + n_new = 0;
156.1374 + for (j = 1; j <= lp->n; j++)
156.1375 + { /* obtain pointer to j-th column */
156.1376 + col = lp->col[j];
156.1377 + /* check if the column is marked */
156.1378 + if (col->j == 0)
156.1379 + { /* it is marked; delete it */
156.1380 + dmp_free_atom(lp->pool, col, sizeof(GLPCOL));
156.1381 + }
156.1382 + else
156.1383 + { /* it is not marked; keep it */
156.1384 + col->j = ++n_new;
156.1385 + lp->col[col->j] = col;
156.1386 + }
156.1387 + }
156.1388 + /* set new number of columns */
156.1389 + lp->n = n_new;
156.1390 + /* if the basis header is still valid, adjust it */
156.1391 + if (lp->valid)
156.1392 + { int m = lp->m;
156.1393 + int *head = lp->head;
156.1394 + for (j = 1; j <= n_new; j++)
156.1395 + { k = lp->col[j]->bind;
156.1396 + if (k != 0)
156.1397 + { xassert(1 <= k && k <= m);
156.1398 + head[k] = m + j;
156.1399 + }
156.1400 + }
156.1401 + }
156.1402 + return;
156.1403 +}
156.1404 +
156.1405 +/***********************************************************************
156.1406 +* NAME
156.1407 +*
156.1408 +* glp_copy_prob - copy problem object content
156.1409 +*
156.1410 +* SYNOPSIS
156.1411 +*
156.1412 +* void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names);
156.1413 +*
156.1414 +* DESCRIPTION
156.1415 +*
156.1416 +* The routine glp_copy_prob copies the content of the problem object
156.1417 +* prob to the problem object dest.
156.1418 +*
156.1419 +* The parameter names is a flag. If it is non-zero, the routine also
156.1420 +* copies all symbolic names; otherwise, if it is zero, symbolic names
156.1421 +* are not copied. */
156.1422 +
156.1423 +void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names)
156.1424 +{ glp_tree *tree = dest->tree;
156.1425 + glp_bfcp bfcp;
156.1426 + int i, j, len, *ind;
156.1427 + double *val;
156.1428 + if (tree != NULL && tree->reason != 0)
156.1429 + xerror("glp_copy_prob: operation not allowed\n");
156.1430 + if (dest == prob)
156.1431 + xerror("glp_copy_prob: copying problem object to itself not al"
156.1432 + "lowed\n");
156.1433 + if (!(names == GLP_ON || names == GLP_OFF))
156.1434 + xerror("glp_copy_prob: names = %d; invalid parameter\n",
156.1435 + names);
156.1436 + glp_erase_prob(dest);
156.1437 + if (names && prob->name != NULL)
156.1438 + glp_set_prob_name(dest, prob->name);
156.1439 + if (names && prob->obj != NULL)
156.1440 + glp_set_obj_name(dest, prob->obj);
156.1441 + dest->dir = prob->dir;
156.1442 + dest->c0 = prob->c0;
156.1443 + if (prob->m > 0)
156.1444 + glp_add_rows(dest, prob->m);
156.1445 + if (prob->n > 0)
156.1446 + glp_add_cols(dest, prob->n);
156.1447 + glp_get_bfcp(prob, &bfcp);
156.1448 + glp_set_bfcp(dest, &bfcp);
156.1449 + dest->pbs_stat = prob->pbs_stat;
156.1450 + dest->dbs_stat = prob->dbs_stat;
156.1451 + dest->obj_val = prob->obj_val;
156.1452 + dest->some = prob->some;
156.1453 + dest->ipt_stat = prob->ipt_stat;
156.1454 + dest->ipt_obj = prob->ipt_obj;
156.1455 + dest->mip_stat = prob->mip_stat;
156.1456 + dest->mip_obj = prob->mip_obj;
156.1457 + for (i = 1; i <= prob->m; i++)
156.1458 + { GLPROW *to = dest->row[i];
156.1459 + GLPROW *from = prob->row[i];
156.1460 + if (names && from->name != NULL)
156.1461 + glp_set_row_name(dest, i, from->name);
156.1462 + to->type = from->type;
156.1463 + to->lb = from->lb;
156.1464 + to->ub = from->ub;
156.1465 + to->rii = from->rii;
156.1466 + to->stat = from->stat;
156.1467 + to->prim = from->prim;
156.1468 + to->dual = from->dual;
156.1469 + to->pval = from->pval;
156.1470 + to->dval = from->dval;
156.1471 + to->mipx = from->mipx;
156.1472 + }
156.1473 + ind = xcalloc(1+prob->m, sizeof(int));
156.1474 + val = xcalloc(1+prob->m, sizeof(double));
156.1475 + for (j = 1; j <= prob->n; j++)
156.1476 + { GLPCOL *to = dest->col[j];
156.1477 + GLPCOL *from = prob->col[j];
156.1478 + if (names && from->name != NULL)
156.1479 + glp_set_col_name(dest, j, from->name);
156.1480 + to->kind = from->kind;
156.1481 + to->type = from->type;
156.1482 + to->lb = from->lb;
156.1483 + to->ub = from->ub;
156.1484 + to->coef = from->coef;
156.1485 + len = glp_get_mat_col(prob, j, ind, val);
156.1486 + glp_set_mat_col(dest, j, len, ind, val);
156.1487 + to->sjj = from->sjj;
156.1488 + to->stat = from->stat;
156.1489 + to->prim = from->prim;
156.1490 + to->dual = from->dual;
156.1491 + to->pval = from->pval;
156.1492 + to->dval = from->dval;
156.1493 + to->mipx = from->mipx;
156.1494 + }
156.1495 + xfree(ind);
156.1496 + xfree(val);
156.1497 + return;
156.1498 +}
156.1499 +
156.1500 +/***********************************************************************
156.1501 +* NAME
156.1502 +*
156.1503 +* glp_erase_prob - erase problem object content
156.1504 +*
156.1505 +* SYNOPSIS
156.1506 +*
156.1507 +* void glp_erase_prob(glp_prob *lp);
156.1508 +*
156.1509 +* DESCRIPTION
156.1510 +*
156.1511 +* The routine glp_erase_prob erases the content of the specified
156.1512 +* problem object. The effect of this operation is the same as if the
156.1513 +* problem object would be deleted with the routine glp_delete_prob and
156.1514 +* then created anew with the routine glp_create_prob, with exception
156.1515 +* that the handle (pointer) to the problem object remains valid. */
156.1516 +
156.1517 +static void delete_prob(glp_prob *lp);
156.1518 +
156.1519 +void glp_erase_prob(glp_prob *lp)
156.1520 +{ glp_tree *tree = lp->tree;
156.1521 + if (tree != NULL && tree->reason != 0)
156.1522 + xerror("glp_erase_prob: operation not allowed\n");
156.1523 + delete_prob(lp);
156.1524 + create_prob(lp);
156.1525 + return;
156.1526 +}
156.1527 +
156.1528 +/***********************************************************************
156.1529 +* NAME
156.1530 +*
156.1531 +* glp_delete_prob - delete problem object
156.1532 +*
156.1533 +* SYNOPSIS
156.1534 +*
156.1535 +* void glp_delete_prob(glp_prob *lp);
156.1536 +*
156.1537 +* DESCRIPTION
156.1538 +*
156.1539 +* The routine glp_delete_prob deletes the specified problem object and
156.1540 +* frees all the memory allocated to it. */
156.1541 +
156.1542 +static void delete_prob(glp_prob *lp)
156.1543 +{ lp->magic = 0x3F3F3F3F;
156.1544 + dmp_delete_pool(lp->pool);
156.1545 +#if 0 /* 17/XI-2009 */
156.1546 + xfree(lp->cps);
156.1547 +#else
156.1548 + if (lp->parms != NULL) xfree(lp->parms);
156.1549 +#endif
156.1550 + xassert(lp->tree == NULL);
156.1551 +#if 0
156.1552 + if (lp->cwa != NULL) xfree(lp->cwa);
156.1553 +#endif
156.1554 + xfree(lp->row);
156.1555 + xfree(lp->col);
156.1556 + if (lp->r_tree != NULL) avl_delete_tree(lp->r_tree);
156.1557 + if (lp->c_tree != NULL) avl_delete_tree(lp->c_tree);
156.1558 + xfree(lp->head);
156.1559 + if (lp->bfcp != NULL) xfree(lp->bfcp);
156.1560 + if (lp->bfd != NULL) bfd_delete_it(lp->bfd);
156.1561 + return;
156.1562 +}
156.1563 +
156.1564 +void glp_delete_prob(glp_prob *lp)
156.1565 +{ glp_tree *tree = lp->tree;
156.1566 + if (tree != NULL && tree->reason != 0)
156.1567 + xerror("glp_delete_prob: operation not allowed\n");
156.1568 + delete_prob(lp);
156.1569 + xfree(lp);
156.1570 + return;
156.1571 +}
156.1572 +
156.1573 +/* eof */
157.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
157.2 +++ b/src/glpapi02.c Mon Dec 06 13:09:21 2010 +0100
157.3 @@ -0,0 +1,491 @@
157.4 +/* glpapi02.c (problem retrieving routines) */
157.5 +
157.6 +/***********************************************************************
157.7 +* This code is part of GLPK (GNU Linear Programming Kit).
157.8 +*
157.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
157.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
157.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
157.12 +* E-mail: <mao@gnu.org>.
157.13 +*
157.14 +* GLPK is free software: you can redistribute it and/or modify it
157.15 +* under the terms of the GNU General Public License as published by
157.16 +* the Free Software Foundation, either version 3 of the License, or
157.17 +* (at your option) any later version.
157.18 +*
157.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
157.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
157.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
157.22 +* License for more details.
157.23 +*
157.24 +* You should have received a copy of the GNU General Public License
157.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
157.26 +***********************************************************************/
157.27 +
157.28 +#include "glpapi.h"
157.29 +
157.30 +/***********************************************************************
157.31 +* NAME
157.32 +*
157.33 +* glp_get_prob_name - retrieve problem name
157.34 +*
157.35 +* SYNOPSIS
157.36 +*
157.37 +* const char *glp_get_prob_name(glp_prob *lp);
157.38 +*
157.39 +* RETURNS
157.40 +*
157.41 +* The routine glp_get_prob_name returns a pointer to an internal
157.42 +* buffer, which contains symbolic name of the problem. However, if the
157.43 +* problem has no assigned name, the routine returns NULL. */
157.44 +
157.45 +const char *glp_get_prob_name(glp_prob *lp)
157.46 +{ char *name;
157.47 + name = lp->name;
157.48 + return name;
157.49 +}
157.50 +
157.51 +/***********************************************************************
157.52 +* NAME
157.53 +*
157.54 +* glp_get_obj_name - retrieve objective function name
157.55 +*
157.56 +* SYNOPSIS
157.57 +*
157.58 +* const char *glp_get_obj_name(glp_prob *lp);
157.59 +*
157.60 +* RETURNS
157.61 +*
157.62 +* The routine glp_get_obj_name returns a pointer to an internal
157.63 +* buffer, which contains a symbolic name of the objective function.
157.64 +* However, if the objective function has no assigned name, the routine
157.65 +* returns NULL. */
157.66 +
157.67 +const char *glp_get_obj_name(glp_prob *lp)
157.68 +{ char *name;
157.69 + name = lp->obj;
157.70 + return name;
157.71 +}
157.72 +
157.73 +/***********************************************************************
157.74 +* NAME
157.75 +*
157.76 +* glp_get_obj_dir - retrieve optimization direction flag
157.77 +*
157.78 +* SYNOPSIS
157.79 +*
157.80 +* int glp_get_obj_dir(glp_prob *lp);
157.81 +*
157.82 +* RETURNS
157.83 +*
157.84 +* The routine glp_get_obj_dir returns the optimization direction flag
157.85 +* (i.e. "sense" of the objective function):
157.86 +*
157.87 +* GLP_MIN - minimization;
157.88 +* GLP_MAX - maximization. */
157.89 +
157.90 +int glp_get_obj_dir(glp_prob *lp)
157.91 +{ int dir = lp->dir;
157.92 + return dir;
157.93 +}
157.94 +
157.95 +/***********************************************************************
157.96 +* NAME
157.97 +*
157.98 +* glp_get_num_rows - retrieve number of rows
157.99 +*
157.100 +* SYNOPSIS
157.101 +*
157.102 +* int glp_get_num_rows(glp_prob *lp);
157.103 +*
157.104 +* RETURNS
157.105 +*
157.106 +* The routine glp_get_num_rows returns the current number of rows in
157.107 +* the specified problem object. */
157.108 +
157.109 +int glp_get_num_rows(glp_prob *lp)
157.110 +{ int m = lp->m;
157.111 + return m;
157.112 +}
157.113 +
157.114 +/***********************************************************************
157.115 +* NAME
157.116 +*
157.117 +* glp_get_num_cols - retrieve number of columns
157.118 +*
157.119 +* SYNOPSIS
157.120 +*
157.121 +* int glp_get_num_cols(glp_prob *lp);
157.122 +*
157.123 +* RETURNS
157.124 +*
157.125 +* The routine glp_get_num_cols returns the current number of columns
157.126 +* in the specified problem object. */
157.127 +
157.128 +int glp_get_num_cols(glp_prob *lp)
157.129 +{ int n = lp->n;
157.130 + return n;
157.131 +}
157.132 +
157.133 +/***********************************************************************
157.134 +* NAME
157.135 +*
157.136 +* glp_get_row_name - retrieve row name
157.137 +*
157.138 +* SYNOPSIS
157.139 +*
157.140 +* const char *glp_get_row_name(glp_prob *lp, int i);
157.141 +*
157.142 +* RETURNS
157.143 +*
157.144 +* The routine glp_get_row_name returns a pointer to an internal
157.145 +* buffer, which contains symbolic name of i-th row. However, if i-th
157.146 +* row has no assigned name, the routine returns NULL. */
157.147 +
157.148 +const char *glp_get_row_name(glp_prob *lp, int i)
157.149 +{ char *name;
157.150 + if (!(1 <= i && i <= lp->m))
157.151 + xerror("glp_get_row_name: i = %d; row number out of range\n",
157.152 + i);
157.153 + name = lp->row[i]->name;
157.154 + return name;
157.155 +}
157.156 +
157.157 +/***********************************************************************
157.158 +* NAME
157.159 +*
157.160 +* glp_get_col_name - retrieve column name
157.161 +*
157.162 +* SYNOPSIS
157.163 +*
157.164 +* const char *glp_get_col_name(glp_prob *lp, int j);
157.165 +*
157.166 +* RETURNS
157.167 +*
157.168 +* The routine glp_get_col_name returns a pointer to an internal
157.169 +* buffer, which contains symbolic name of j-th column. However, if j-th
157.170 +* column has no assigned name, the routine returns NULL. */
157.171 +
157.172 +const char *glp_get_col_name(glp_prob *lp, int j)
157.173 +{ char *name;
157.174 + if (!(1 <= j && j <= lp->n))
157.175 + xerror("glp_get_col_name: j = %d; column number out of range\n"
157.176 + , j);
157.177 + name = lp->col[j]->name;
157.178 + return name;
157.179 +}
157.180 +
157.181 +/***********************************************************************
157.182 +* NAME
157.183 +*
157.184 +* glp_get_row_type - retrieve row type
157.185 +*
157.186 +* SYNOPSIS
157.187 +*
157.188 +* int glp_get_row_type(glp_prob *lp, int i);
157.189 +*
157.190 +* RETURNS
157.191 +*
157.192 +* The routine glp_get_row_type returns the type of i-th row, i.e. the
157.193 +* type of corresponding auxiliary variable, as follows:
157.194 +*
157.195 +* GLP_FR - free (unbounded) variable;
157.196 +* GLP_LO - variable with lower bound;
157.197 +* GLP_UP - variable with upper bound;
157.198 +* GLP_DB - double-bounded variable;
157.199 +* GLP_FX - fixed variable. */
157.200 +
157.201 +int glp_get_row_type(glp_prob *lp, int i)
157.202 +{ if (!(1 <= i && i <= lp->m))
157.203 + xerror("glp_get_row_type: i = %d; row number out of range\n",
157.204 + i);
157.205 + return lp->row[i]->type;
157.206 +}
157.207 +
157.208 +/***********************************************************************
157.209 +* NAME
157.210 +*
157.211 +* glp_get_row_lb - retrieve row lower bound
157.212 +*
157.213 +* SYNOPSIS
157.214 +*
157.215 +* double glp_get_row_lb(glp_prob *lp, int i);
157.216 +*
157.217 +* RETURNS
157.218 +*
157.219 +* The routine glp_get_row_lb returns the lower bound of i-th row, i.e.
157.220 +* the lower bound of corresponding auxiliary variable. However, if the
157.221 +* row has no lower bound, the routine returns -DBL_MAX. */
157.222 +
157.223 +double glp_get_row_lb(glp_prob *lp, int i)
157.224 +{ double lb;
157.225 + if (!(1 <= i && i <= lp->m))
157.226 + xerror("glp_get_row_lb: i = %d; row number out of range\n", i);
157.227 + switch (lp->row[i]->type)
157.228 + { case GLP_FR:
157.229 + case GLP_UP:
157.230 + lb = -DBL_MAX; break;
157.231 + case GLP_LO:
157.232 + case GLP_DB:
157.233 + case GLP_FX:
157.234 + lb = lp->row[i]->lb; break;
157.235 + default:
157.236 + xassert(lp != lp);
157.237 + }
157.238 + return lb;
157.239 +}
157.240 +
157.241 +/***********************************************************************
157.242 +* NAME
157.243 +*
157.244 +* glp_get_row_ub - retrieve row upper bound
157.245 +*
157.246 +* SYNOPSIS
157.247 +*
157.248 +* double glp_get_row_ub(glp_prob *lp, int i);
157.249 +*
157.250 +* RETURNS
157.251 +*
157.252 +* The routine glp_get_row_ub returns the upper bound of i-th row, i.e.
157.253 +* the upper bound of corresponding auxiliary variable. However, if the
157.254 +* row has no upper bound, the routine returns +DBL_MAX. */
157.255 +
157.256 +double glp_get_row_ub(glp_prob *lp, int i)
157.257 +{ double ub;
157.258 + if (!(1 <= i && i <= lp->m))
157.259 + xerror("glp_get_row_ub: i = %d; row number out of range\n", i);
157.260 + switch (lp->row[i]->type)
157.261 + { case GLP_FR:
157.262 + case GLP_LO:
157.263 + ub = +DBL_MAX; break;
157.264 + case GLP_UP:
157.265 + case GLP_DB:
157.266 + case GLP_FX:
157.267 + ub = lp->row[i]->ub; break;
157.268 + default:
157.269 + xassert(lp != lp);
157.270 + }
157.271 + return ub;
157.272 +}
157.273 +
157.274 +/***********************************************************************
157.275 +* NAME
157.276 +*
157.277 +* glp_get_col_type - retrieve column type
157.278 +*
157.279 +* SYNOPSIS
157.280 +*
157.281 +* int glp_get_col_type(glp_prob *lp, int j);
157.282 +*
157.283 +* RETURNS
157.284 +*
157.285 +* The routine glp_get_col_type returns the type of j-th column, i.e.
157.286 +* the type of corresponding structural variable, as follows:
157.287 +*
157.288 +* GLP_FR - free (unbounded) variable;
157.289 +* GLP_LO - variable with lower bound;
157.290 +* GLP_UP - variable with upper bound;
157.291 +* GLP_DB - double-bounded variable;
157.292 +* GLP_FX - fixed variable. */
157.293 +
157.294 +int glp_get_col_type(glp_prob *lp, int j)
157.295 +{ if (!(1 <= j && j <= lp->n))
157.296 + xerror("glp_get_col_type: j = %d; column number out of range\n"
157.297 + , j);
157.298 + return lp->col[j]->type;
157.299 +}
157.300 +
157.301 +/***********************************************************************
157.302 +* NAME
157.303 +*
157.304 +* glp_get_col_lb - retrieve column lower bound
157.305 +*
157.306 +* SYNOPSIS
157.307 +*
157.308 +* double glp_get_col_lb(glp_prob *lp, int j);
157.309 +*
157.310 +* RETURNS
157.311 +*
157.312 +* The routine glp_get_col_lb returns the lower bound of j-th column,
157.313 +* i.e. the lower bound of corresponding structural variable. However,
157.314 +* if the column has no lower bound, the routine returns -DBL_MAX. */
157.315 +
157.316 +double glp_get_col_lb(glp_prob *lp, int j)
157.317 +{ double lb;
157.318 + if (!(1 <= j && j <= lp->n))
157.319 + xerror("glp_get_col_lb: j = %d; column number out of range\n",
157.320 + j);
157.321 + switch (lp->col[j]->type)
157.322 + { case GLP_FR:
157.323 + case GLP_UP:
157.324 + lb = -DBL_MAX; break;
157.325 + case GLP_LO:
157.326 + case GLP_DB:
157.327 + case GLP_FX:
157.328 + lb = lp->col[j]->lb; break;
157.329 + default:
157.330 + xassert(lp != lp);
157.331 + }
157.332 + return lb;
157.333 +}
157.334 +
157.335 +/***********************************************************************
157.336 +* NAME
157.337 +*
157.338 +* glp_get_col_ub - retrieve column upper bound
157.339 +*
157.340 +* SYNOPSIS
157.341 +*
157.342 +* double glp_get_col_ub(glp_prob *lp, int j);
157.343 +*
157.344 +* RETURNS
157.345 +*
157.346 +* The routine glp_get_col_ub returns the upper bound of j-th column,
157.347 +* i.e. the upper bound of corresponding structural variable. However,
157.348 +* if the column has no upper bound, the routine returns +DBL_MAX. */
157.349 +
157.350 +double glp_get_col_ub(glp_prob *lp, int j)
157.351 +{ double ub;
157.352 + if (!(1 <= j && j <= lp->n))
157.353 + xerror("glp_get_col_ub: j = %d; column number out of range\n",
157.354 + j);
157.355 + switch (lp->col[j]->type)
157.356 + { case GLP_FR:
157.357 + case GLP_LO:
157.358 + ub = +DBL_MAX; break;
157.359 + case GLP_UP:
157.360 + case GLP_DB:
157.361 + case GLP_FX:
157.362 + ub = lp->col[j]->ub; break;
157.363 + default:
157.364 + xassert(lp != lp);
157.365 + }
157.366 + return ub;
157.367 +}
157.368 +
157.369 +/***********************************************************************
157.370 +* NAME
157.371 +*
157.372 +* glp_get_obj_coef - retrieve obj. coefficient or constant term
157.373 +*
157.374 +* SYNOPSIS
157.375 +*
157.376 +* double glp_get_obj_coef(glp_prob *lp, int j);
157.377 +*
157.378 +* RETURNS
157.379 +*
157.380 +* The routine glp_get_obj_coef returns the objective coefficient at
157.381 +* j-th structural variable (column) of the specified problem object.
157.382 +*
157.383 +* If the parameter j is zero, the routine returns the constant term
157.384 +* ("shift") of the objective function. */
157.385 +
157.386 +double glp_get_obj_coef(glp_prob *lp, int j)
157.387 +{ if (!(0 <= j && j <= lp->n))
157.388 + xerror("glp_get_obj_coef: j = %d; column number out of range\n"
157.389 + , j);
157.390 + return j == 0 ? lp->c0 : lp->col[j]->coef;
157.391 +}
157.392 +
157.393 +/***********************************************************************
157.394 +* NAME
157.395 +*
157.396 +* glp_get_num_nz - retrieve number of constraint coefficients
157.397 +*
157.398 +* SYNOPSIS
157.399 +*
157.400 +* int glp_get_num_nz(glp_prob *lp);
157.401 +*
157.402 +* RETURNS
157.403 +*
157.404 +* The routine glp_get_num_nz returns the number of (non-zero) elements
157.405 +* in the constraint matrix of the specified problem object. */
157.406 +
157.407 +int glp_get_num_nz(glp_prob *lp)
157.408 +{ int nnz = lp->nnz;
157.409 + return nnz;
157.410 +}
157.411 +
157.412 +/***********************************************************************
157.413 +* NAME
157.414 +*
157.415 +* glp_get_mat_row - retrieve row of the constraint matrix
157.416 +*
157.417 +* SYNOPSIS
157.418 +*
157.419 +* int glp_get_mat_row(glp_prob *lp, int i, int ind[], double val[]);
157.420 +*
157.421 +* DESCRIPTION
157.422 +*
157.423 +* The routine glp_get_mat_row scans (non-zero) elements of i-th row
157.424 +* of the constraint matrix of the specified problem object and stores
157.425 +* their column indices and numeric values to locations ind[1], ...,
157.426 +* ind[len] and val[1], ..., val[len], respectively, where 0 <= len <= n
157.427 +* is the number of elements in i-th row, n is the number of columns.
157.428 +*
157.429 +* The parameter ind and/or val can be specified as NULL, in which case
157.430 +* corresponding information is not stored.
157.431 +*
157.432 +* RETURNS
157.433 +*
157.434 +* The routine glp_get_mat_row returns the length len, i.e. the number
157.435 +* of (non-zero) elements in i-th row. */
157.436 +
157.437 +int glp_get_mat_row(glp_prob *lp, int i, int ind[], double val[])
157.438 +{ GLPAIJ *aij;
157.439 + int len;
157.440 + if (!(1 <= i && i <= lp->m))
157.441 + xerror("glp_get_mat_row: i = %d; row number out of range\n",
157.442 + i);
157.443 + len = 0;
157.444 + for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
157.445 + { len++;
157.446 + if (ind != NULL) ind[len] = aij->col->j;
157.447 + if (val != NULL) val[len] = aij->val;
157.448 + }
157.449 + xassert(len <= lp->n);
157.450 + return len;
157.451 +}
157.452 +
157.453 +/***********************************************************************
157.454 +* NAME
157.455 +*
157.456 +* glp_get_mat_col - retrieve column of the constraint matrix
157.457 +*
157.458 +* SYNOPSIS
157.459 +*
157.460 +* int glp_get_mat_col(glp_prob *lp, int j, int ind[], double val[]);
157.461 +*
157.462 +* DESCRIPTION
157.463 +*
157.464 +* The routine glp_get_mat_col scans (non-zero) elements of j-th column
157.465 +* of the constraint matrix of the specified problem object and stores
157.466 +* their row indices and numeric values to locations ind[1], ...,
157.467 +* ind[len] and val[1], ..., val[len], respectively, where 0 <= len <= m
157.468 +* is the number of elements in j-th column, m is the number of rows.
157.469 +*
157.470 +* The parameter ind or/and val can be specified as NULL, in which case
157.471 +* corresponding information is not stored.
157.472 +*
157.473 +* RETURNS
157.474 +*
157.475 +* The routine glp_get_mat_col returns the length len, i.e. the number
157.476 +* of (non-zero) elements in j-th column. */
157.477 +
157.478 +int glp_get_mat_col(glp_prob *lp, int j, int ind[], double val[])
157.479 +{ GLPAIJ *aij;
157.480 + int len;
157.481 + if (!(1 <= j && j <= lp->n))
157.482 + xerror("glp_get_mat_col: j = %d; column number out of range\n",
157.483 + j);
157.484 + len = 0;
157.485 + for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
157.486 + { len++;
157.487 + if (ind != NULL) ind[len] = aij->row->i;
157.488 + if (val != NULL) val[len] = aij->val;
157.489 + }
157.490 + xassert(len <= lp->m);
157.491 + return len;
157.492 +}
157.493 +
157.494 +/* eof */
158.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
158.2 +++ b/src/glpapi03.c Mon Dec 06 13:09:21 2010 +0100
158.3 @@ -0,0 +1,166 @@
158.4 +/* glpapi03.c (row and column searching routines) */
158.5 +
158.6 +/***********************************************************************
158.7 +* This code is part of GLPK (GNU Linear Programming Kit).
158.8 +*
158.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
158.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
158.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
158.12 +* E-mail: <mao@gnu.org>.
158.13 +*
158.14 +* GLPK is free software: you can redistribute it and/or modify it
158.15 +* under the terms of the GNU General Public License as published by
158.16 +* the Free Software Foundation, either version 3 of the License, or
158.17 +* (at your option) any later version.
158.18 +*
158.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
158.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
158.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
158.22 +* License for more details.
158.23 +*
158.24 +* You should have received a copy of the GNU General Public License
158.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
158.26 +***********************************************************************/
158.27 +
158.28 +#include "glpapi.h"
158.29 +
158.30 +/***********************************************************************
158.31 +* NAME
158.32 +*
158.33 +* glp_create_index - create the name index
158.34 +*
158.35 +* SYNOPSIS
158.36 +*
158.37 +* void glp_create_index(glp_prob *lp);
158.38 +*
158.39 +* DESCRIPTION
158.40 +*
158.41 +* The routine glp_create_index creates the name index for the
158.42 +* specified problem object. The name index is an auxiliary data
158.43 +* structure, which is intended to quickly (i.e. for logarithmic time)
158.44 +* find rows and columns by their names.
158.45 +*
158.46 +* This routine can be called at any time. If the name index already
158.47 +* exists, the routine does nothing. */
158.48 +
158.49 +void glp_create_index(glp_prob *lp)
158.50 +{ GLPROW *row;
158.51 + GLPCOL *col;
158.52 + int i, j;
158.53 + /* create row name index */
158.54 + if (lp->r_tree == NULL)
158.55 + { lp->r_tree = avl_create_tree(avl_strcmp, NULL);
158.56 + for (i = 1; i <= lp->m; i++)
158.57 + { row = lp->row[i];
158.58 + xassert(row->node == NULL);
158.59 + if (row->name != NULL)
158.60 + { row->node = avl_insert_node(lp->r_tree, row->name);
158.61 + avl_set_node_link(row->node, row);
158.62 + }
158.63 + }
158.64 + }
158.65 + /* create column name index */
158.66 + if (lp->c_tree == NULL)
158.67 + { lp->c_tree = avl_create_tree(avl_strcmp, NULL);
158.68 + for (j = 1; j <= lp->n; j++)
158.69 + { col = lp->col[j];
158.70 + xassert(col->node == NULL);
158.71 + if (col->name != NULL)
158.72 + { col->node = avl_insert_node(lp->c_tree, col->name);
158.73 + avl_set_node_link(col->node, col);
158.74 + }
158.75 + }
158.76 + }
158.77 + return;
158.78 +}
158.79 +
158.80 +/***********************************************************************
158.81 +* NAME
158.82 +*
158.83 +* glp_find_row - find row by its name
158.84 +*
158.85 +* SYNOPSIS
158.86 +*
158.87 +* int glp_find_row(glp_prob *lp, const char *name);
158.88 +*
158.89 +* RETURNS
158.90 +*
158.91 +* The routine glp_find_row returns the ordinal number of a row,
158.92 +* which is assigned (by the routine glp_set_row_name) the specified
158.93 +* symbolic name. If no such row exists, the routine returns 0. */
158.94 +
158.95 +int glp_find_row(glp_prob *lp, const char *name)
158.96 +{ AVLNODE *node;
158.97 + int i = 0;
158.98 + if (lp->r_tree == NULL)
158.99 + xerror("glp_find_row: row name index does not exist\n");
158.100 + if (!(name == NULL || name[0] == '\0' || strlen(name) > 255))
158.101 + { node = avl_find_node(lp->r_tree, name);
158.102 + if (node != NULL)
158.103 + i = ((GLPROW *)avl_get_node_link(node))->i;
158.104 + }
158.105 + return i;
158.106 +}
158.107 +
158.108 +/***********************************************************************
158.109 +* NAME
158.110 +*
158.111 +* glp_find_col - find column by its name
158.112 +*
158.113 +* SYNOPSIS
158.114 +*
158.115 +* int glp_find_col(glp_prob *lp, const char *name);
158.116 +*
158.117 +* RETURNS
158.118 +*
158.119 +* The routine glp_find_col returns the ordinal number of a column,
158.120 +* which is assigned (by the routine glp_set_col_name) the specified
158.121 +* symbolic name. If no such column exists, the routine returns 0. */
158.122 +
158.123 +int glp_find_col(glp_prob *lp, const char *name)
158.124 +{ AVLNODE *node;
158.125 + int j = 0;
158.126 + if (lp->c_tree == NULL)
158.127 + xerror("glp_find_col: column name index does not exist\n");
158.128 + if (!(name == NULL || name[0] == '\0' || strlen(name) > 255))
158.129 + { node = avl_find_node(lp->c_tree, name);
158.130 + if (node != NULL)
158.131 + j = ((GLPCOL *)avl_get_node_link(node))->j;
158.132 + }
158.133 + return j;
158.134 +}
158.135 +
158.136 +/***********************************************************************
158.137 +* NAME
158.138 +*
158.139 +* glp_delete_index - delete the name index
158.140 +*
158.141 +* SYNOPSIS
158.142 +*
158.143 +* void glp_delete_index(glp_prob *lp);
158.144 +*
158.145 +* DESCRIPTION
158.146 +*
158.147 +* The routine glp_delete_index deletes the name index previously
158.148 +* created by the routine glp_create_index and frees the memory
158.149 +* allocated to this auxiliary data structure.
158.150 +*
158.151 +* This routine can be called at any time. If the name index does not
158.152 +* exist, the routine does nothing. */
158.153 +
158.154 +void glp_delete_index(glp_prob *lp)
158.155 +{ int i, j;
158.156 + /* delete row name index */
158.157 + if (lp->r_tree != NULL)
158.158 + { for (i = 1; i <= lp->m; i++) lp->row[i]->node = NULL;
158.159 + avl_delete_tree(lp->r_tree), lp->r_tree = NULL;
158.160 + }
158.161 + /* delete column name index */
158.162 + if (lp->c_tree != NULL)
158.163 + { for (j = 1; j <= lp->n; j++) lp->col[j]->node = NULL;
158.164 + avl_delete_tree(lp->c_tree), lp->c_tree = NULL;
158.165 + }
158.166 + return;
158.167 +}
158.168 +
158.169 +/* eof */
159.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
159.2 +++ b/src/glpapi04.c Mon Dec 06 13:09:21 2010 +0100
159.3 @@ -0,0 +1,156 @@
159.4 +/* glpapi04.c (problem scaling routines) */
159.5 +
159.6 +/***********************************************************************
159.7 +* This code is part of GLPK (GNU Linear Programming Kit).
159.8 +*
159.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
159.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
159.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
159.12 +* E-mail: <mao@gnu.org>.
159.13 +*
159.14 +* GLPK is free software: you can redistribute it and/or modify it
159.15 +* under the terms of the GNU General Public License as published by
159.16 +* the Free Software Foundation, either version 3 of the License, or
159.17 +* (at your option) any later version.
159.18 +*
159.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
159.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
159.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
159.22 +* License for more details.
159.23 +*
159.24 +* You should have received a copy of the GNU General Public License
159.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
159.26 +***********************************************************************/
159.27 +
159.28 +#include "glpapi.h"
159.29 +
159.30 +/***********************************************************************
159.31 +* NAME
159.32 +*
159.33 +* glp_set_rii - set (change) row scale factor
159.34 +*
159.35 +* SYNOPSIS
159.36 +*
159.37 +* void glp_set_rii(glp_prob *lp, int i, double rii);
159.38 +*
159.39 +* DESCRIPTION
159.40 +*
159.41 +* The routine glp_set_rii sets (changes) the scale factor r[i,i] for
159.42 +* i-th row of the specified problem object. */
159.43 +
159.44 +void glp_set_rii(glp_prob *lp, int i, double rii)
159.45 +{ if (!(1 <= i && i <= lp->m))
159.46 + xerror("glp_set_rii: i = %d; row number out of range\n", i);
159.47 + if (rii <= 0.0)
159.48 + xerror("glp_set_rii: i = %d; rii = %g; invalid scale factor\n",
159.49 + i, rii);
159.50 + if (lp->valid && lp->row[i]->rii != rii)
159.51 + { GLPAIJ *aij;
159.52 + for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
159.53 + { if (aij->col->stat == GLP_BS)
159.54 + { /* invalidate the basis factorization */
159.55 + lp->valid = 0;
159.56 + break;
159.57 + }
159.58 + }
159.59 + }
159.60 + lp->row[i]->rii = rii;
159.61 + return;
159.62 +}
159.63 +
159.64 +/***********************************************************************
159.65 +* NAME
159.66 +*
159.67 +* glp_set sjj - set (change) column scale factor
159.68 +*
159.69 +* SYNOPSIS
159.70 +*
159.71 +* void glp_set_sjj(glp_prob *lp, int j, double sjj);
159.72 +*
159.73 +* DESCRIPTION
159.74 +*
159.75 +* The routine glp_set_sjj sets (changes) the scale factor s[j,j] for
159.76 +* j-th column of the specified problem object. */
159.77 +
159.78 +void glp_set_sjj(glp_prob *lp, int j, double sjj)
159.79 +{ if (!(1 <= j && j <= lp->n))
159.80 + xerror("glp_set_sjj: j = %d; column number out of range\n", j);
159.81 + if (sjj <= 0.0)
159.82 + xerror("glp_set_sjj: j = %d; sjj = %g; invalid scale factor\n",
159.83 + j, sjj);
159.84 + if (lp->valid && lp->col[j]->sjj != sjj && lp->col[j]->stat ==
159.85 + GLP_BS)
159.86 + { /* invalidate the basis factorization */
159.87 + lp->valid = 0;
159.88 + }
159.89 + lp->col[j]->sjj = sjj;
159.90 + return;
159.91 +}
159.92 +
159.93 +/***********************************************************************
159.94 +* NAME
159.95 +*
159.96 +* glp_get_rii - retrieve row scale factor
159.97 +*
159.98 +* SYNOPSIS
159.99 +*
159.100 +* double glp_get_rii(glp_prob *lp, int i);
159.101 +*
159.102 +* RETURNS
159.103 +*
159.104 +* The routine glp_get_rii returns current scale factor r[i,i] for i-th
159.105 +* row of the specified problem object. */
159.106 +
159.107 +double glp_get_rii(glp_prob *lp, int i)
159.108 +{ if (!(1 <= i && i <= lp->m))
159.109 + xerror("glp_get_rii: i = %d; row number out of range\n", i);
159.110 + return lp->row[i]->rii;
159.111 +}
159.112 +
159.113 +/***********************************************************************
159.114 +* NAME
159.115 +*
159.116 +* glp_get_sjj - retrieve column scale factor
159.117 +*
159.118 +* SYNOPSIS
159.119 +*
159.120 +* double glp_get_sjj(glp_prob *lp, int j);
159.121 +*
159.122 +* RETURNS
159.123 +*
159.124 +* The routine glp_get_sjj returns current scale factor s[j,j] for j-th
159.125 +* column of the specified problem object. */
159.126 +
159.127 +double glp_get_sjj(glp_prob *lp, int j)
159.128 +{ if (!(1 <= j && j <= lp->n))
159.129 + xerror("glp_get_sjj: j = %d; column number out of range\n", j);
159.130 + return lp->col[j]->sjj;
159.131 +}
159.132 +
159.133 +/***********************************************************************
159.134 +* NAME
159.135 +*
159.136 +* glp_unscale_prob - unscale problem data
159.137 +*
159.138 +* SYNOPSIS
159.139 +*
159.140 +* void glp_unscale_prob(glp_prob *lp);
159.141 +*
159.142 +* DESCRIPTION
159.143 +*
159.144 +* The routine glp_unscale_prob performs unscaling of problem data for
159.145 +* the specified problem object.
159.146 +*
159.147 +* "Unscaling" means replacing the current scaling matrices R and S by
159.148 +* unity matrices that cancels the scaling effect. */
159.149 +
159.150 +void glp_unscale_prob(glp_prob *lp)
159.151 +{ int m = glp_get_num_rows(lp);
159.152 + int n = glp_get_num_cols(lp);
159.153 + int i, j;
159.154 + for (i = 1; i <= m; i++) glp_set_rii(lp, i, 1.0);
159.155 + for (j = 1; j <= n; j++) glp_set_sjj(lp, j, 1.0);
159.156 + return;
159.157 +}
159.158 +
159.159 +/* eof */
160.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
160.2 +++ b/src/glpapi05.c Mon Dec 06 13:09:21 2010 +0100
160.3 @@ -0,0 +1,168 @@
160.4 +/* glpapi05.c (LP basis constructing routines) */
160.5 +
160.6 +/***********************************************************************
160.7 +* This code is part of GLPK (GNU Linear Programming Kit).
160.8 +*
160.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
160.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
160.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
160.12 +* E-mail: <mao@gnu.org>.
160.13 +*
160.14 +* GLPK is free software: you can redistribute it and/or modify it
160.15 +* under the terms of the GNU General Public License as published by
160.16 +* the Free Software Foundation, either version 3 of the License, or
160.17 +* (at your option) any later version.
160.18 +*
160.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
160.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
160.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
160.22 +* License for more details.
160.23 +*
160.24 +* You should have received a copy of the GNU General Public License
160.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
160.26 +***********************************************************************/
160.27 +
160.28 +#include "glpapi.h"
160.29 +
160.30 +/***********************************************************************
160.31 +* NAME
160.32 +*
160.33 +* glp_set_row_stat - set (change) row status
160.34 +*
160.35 +* SYNOPSIS
160.36 +*
160.37 +* void glp_set_row_stat(glp_prob *lp, int i, int stat);
160.38 +*
160.39 +* DESCRIPTION
160.40 +*
160.41 +* The routine glp_set_row_stat sets (changes) status of the auxiliary
160.42 +* variable associated with i-th row.
160.43 +*
160.44 +* The new status of the auxiliary variable should be specified by the
160.45 +* parameter stat as follows:
160.46 +*
160.47 +* GLP_BS - basic variable;
160.48 +* GLP_NL - non-basic variable;
160.49 +* GLP_NU - non-basic variable on its upper bound; if the variable is
160.50 +* not double-bounded, this means the same as GLP_NL (only in
160.51 +* case of this routine);
160.52 +* GLP_NF - the same as GLP_NL (only in case of this routine);
160.53 +* GLP_NS - the same as GLP_NL (only in case of this routine). */
160.54 +
160.55 +void glp_set_row_stat(glp_prob *lp, int i, int stat)
160.56 +{ GLPROW *row;
160.57 + if (!(1 <= i && i <= lp->m))
160.58 + xerror("glp_set_row_stat: i = %d; row number out of range\n",
160.59 + i);
160.60 + if (!(stat == GLP_BS || stat == GLP_NL || stat == GLP_NU ||
160.61 + stat == GLP_NF || stat == GLP_NS))
160.62 + xerror("glp_set_row_stat: i = %d; stat = %d; invalid status\n",
160.63 + i, stat);
160.64 + row = lp->row[i];
160.65 + if (stat != GLP_BS)
160.66 + { switch (row->type)
160.67 + { case GLP_FR: stat = GLP_NF; break;
160.68 + case GLP_LO: stat = GLP_NL; break;
160.69 + case GLP_UP: stat = GLP_NU; break;
160.70 + case GLP_DB: if (stat != GLP_NU) stat = GLP_NL; break;
160.71 + case GLP_FX: stat = GLP_NS; break;
160.72 + default: xassert(row != row);
160.73 + }
160.74 + }
160.75 + if (row->stat == GLP_BS && stat != GLP_BS ||
160.76 + row->stat != GLP_BS && stat == GLP_BS)
160.77 + { /* invalidate the basis factorization */
160.78 + lp->valid = 0;
160.79 + }
160.80 + row->stat = stat;
160.81 + return;
160.82 +}
160.83 +
160.84 +/***********************************************************************
160.85 +* NAME
160.86 +*
160.87 +* glp_set_col_stat - set (change) column status
160.88 +*
160.89 +* SYNOPSIS
160.90 +*
160.91 +* void glp_set_col_stat(glp_prob *lp, int j, int stat);
160.92 +*
160.93 +* DESCRIPTION
160.94 +*
160.95 +* The routine glp_set_col_stat sets (changes) status of the structural
160.96 +* variable associated with j-th column.
160.97 +*
160.98 +* The new status of the structural variable should be specified by the
160.99 +* parameter stat as follows:
160.100 +*
160.101 +* GLP_BS - basic variable;
160.102 +* GLP_NL - non-basic variable;
160.103 +* GLP_NU - non-basic variable on its upper bound; if the variable is
160.104 +* not double-bounded, this means the same as GLP_NL (only in
160.105 +* case of this routine);
160.106 +* GLP_NF - the same as GLP_NL (only in case of this routine);
160.107 +* GLP_NS - the same as GLP_NL (only in case of this routine). */
160.108 +
160.109 +void glp_set_col_stat(glp_prob *lp, int j, int stat)
160.110 +{ GLPCOL *col;
160.111 + if (!(1 <= j && j <= lp->n))
160.112 + xerror("glp_set_col_stat: j = %d; column number out of range\n"
160.113 + , j);
160.114 + if (!(stat == GLP_BS || stat == GLP_NL || stat == GLP_NU ||
160.115 + stat == GLP_NF || stat == GLP_NS))
160.116 + xerror("glp_set_col_stat: j = %d; stat = %d; invalid status\n",
160.117 + j, stat);
160.118 + col = lp->col[j];
160.119 + if (stat != GLP_BS)
160.120 + { switch (col->type)
160.121 + { case GLP_FR: stat = GLP_NF; break;
160.122 + case GLP_LO: stat = GLP_NL; break;
160.123 + case GLP_UP: stat = GLP_NU; break;
160.124 + case GLP_DB: if (stat != GLP_NU) stat = GLP_NL; break;
160.125 + case GLP_FX: stat = GLP_NS; break;
160.126 + default: xassert(col != col);
160.127 + }
160.128 + }
160.129 + if (col->stat == GLP_BS && stat != GLP_BS ||
160.130 + col->stat != GLP_BS && stat == GLP_BS)
160.131 + { /* invalidate the basis factorization */
160.132 + lp->valid = 0;
160.133 + }
160.134 + col->stat = stat;
160.135 + return;
160.136 +}
160.137 +
160.138 +/***********************************************************************
160.139 +* NAME
160.140 +*
160.141 +* glp_std_basis - construct standard initial LP basis
160.142 +*
160.143 +* SYNOPSIS
160.144 +*
160.145 +* void glp_std_basis(glp_prob *lp);
160.146 +*
160.147 +* DESCRIPTION
160.148 +*
160.149 +* The routine glp_std_basis builds the "standard" (trivial) initial
160.150 +* basis for the specified problem object.
160.151 +*
160.152 +* In the "standard" basis all auxiliary variables are basic, and all
160.153 +* structural variables are non-basic. */
160.154 +
160.155 +void glp_std_basis(glp_prob *lp)
160.156 +{ int i, j;
160.157 + /* make all auxiliary variables basic */
160.158 + for (i = 1; i <= lp->m; i++)
160.159 + glp_set_row_stat(lp, i, GLP_BS);
160.160 + /* make all structural variables non-basic */
160.161 + for (j = 1; j <= lp->n; j++)
160.162 + { GLPCOL *col = lp->col[j];
160.163 + if (col->type == GLP_DB && fabs(col->lb) > fabs(col->ub))
160.164 + glp_set_col_stat(lp, j, GLP_NU);
160.165 + else
160.166 + glp_set_col_stat(lp, j, GLP_NL);
160.167 + }
160.168 + return;
160.169 +}
160.170 +
160.171 +/* eof */
161.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
161.2 +++ b/src/glpapi06.c Mon Dec 06 13:09:21 2010 +0100
161.3 @@ -0,0 +1,806 @@
161.4 +/* glpapi06.c (simplex method routines) */
161.5 +
161.6 +/***********************************************************************
161.7 +* This code is part of GLPK (GNU Linear Programming Kit).
161.8 +*
161.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
161.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
161.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
161.12 +* E-mail: <mao@gnu.org>.
161.13 +*
161.14 +* GLPK is free software: you can redistribute it and/or modify it
161.15 +* under the terms of the GNU General Public License as published by
161.16 +* the Free Software Foundation, either version 3 of the License, or
161.17 +* (at your option) any later version.
161.18 +*
161.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
161.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
161.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
161.22 +* License for more details.
161.23 +*
161.24 +* You should have received a copy of the GNU General Public License
161.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
161.26 +***********************************************************************/
161.27 +
161.28 +#include "glpios.h"
161.29 +#include "glpnpp.h"
161.30 +#include "glpspx.h"
161.31 +
161.32 +/***********************************************************************
161.33 +* NAME
161.34 +*
161.35 +* glp_simplex - solve LP problem with the simplex method
161.36 +*
161.37 +* SYNOPSIS
161.38 +*
161.39 +* int glp_simplex(glp_prob *P, const glp_smcp *parm);
161.40 +*
161.41 +* DESCRIPTION
161.42 +*
161.43 +* The routine glp_simplex is a driver to the LP solver based on the
161.44 +* simplex method. This routine retrieves problem data from the
161.45 +* specified problem object, calls the solver to solve the problem
161.46 +* instance, and stores results of computations back into the problem
161.47 +* object.
161.48 +*
161.49 +* The simplex solver has a set of control parameters. Values of the
161.50 +* control parameters can be passed in a structure glp_smcp, which the
161.51 +* parameter parm points to.
161.52 +*
161.53 +* The parameter parm can be specified as NULL, in which case the LP
161.54 +* solver uses default settings.
161.55 +*
161.56 +* RETURNS
161.57 +*
161.58 +* 0 The LP problem instance has been successfully solved. This code
161.59 +* does not necessarily mean that the solver has found optimal
161.60 +* solution. It only means that the solution process was successful.
161.61 +*
161.62 +* GLP_EBADB
161.63 +* Unable to start the search, because the initial basis specified
161.64 +* in the problem object is invalid--the number of basic (auxiliary
161.65 +* and structural) variables is not the same as the number of rows in
161.66 +* the problem object.
161.67 +*
161.68 +* GLP_ESING
161.69 +* Unable to start the search, because the basis matrix correspodning
161.70 +* to the initial basis is singular within the working precision.
161.71 +*
161.72 +* GLP_ECOND
161.73 +* Unable to start the search, because the basis matrix correspodning
161.74 +* to the initial basis is ill-conditioned, i.e. its condition number
161.75 +* is too large.
161.76 +*
161.77 +* GLP_EBOUND
161.78 +* Unable to start the search, because some double-bounded variables
161.79 +* have incorrect bounds.
161.80 +*
161.81 +* GLP_EFAIL
161.82 +* The search was prematurely terminated due to the solver failure.
161.83 +*
161.84 +* GLP_EOBJLL
161.85 +* The search was prematurely terminated, because the objective
161.86 +* function being maximized has reached its lower limit and continues
161.87 +* decreasing (dual simplex only).
161.88 +*
161.89 +* GLP_EOBJUL
161.90 +* The search was prematurely terminated, because the objective
161.91 +* function being minimized has reached its upper limit and continues
161.92 +* increasing (dual simplex only).
161.93 +*
161.94 +* GLP_EITLIM
161.95 +* The search was prematurely terminated, because the simplex
161.96 +* iteration limit has been exceeded.
161.97 +*
161.98 +* GLP_ETMLIM
161.99 +* The search was prematurely terminated, because the time limit has
161.100 +* been exceeded.
161.101 +*
161.102 +* GLP_ENOPFS
161.103 +* The LP problem instance has no primal feasible solution (only if
161.104 +* the LP presolver is used).
161.105 +*
161.106 +* GLP_ENODFS
161.107 +* The LP problem instance has no dual feasible solution (only if the
161.108 +* LP presolver is used). */
161.109 +
161.110 +static void trivial_lp(glp_prob *P, const glp_smcp *parm)
161.111 +{ /* solve trivial LP which has empty constraint matrix */
161.112 + GLPROW *row;
161.113 + GLPCOL *col;
161.114 + int i, j;
161.115 + double p_infeas, d_infeas, zeta;
161.116 + P->valid = 0;
161.117 + P->pbs_stat = P->dbs_stat = GLP_FEAS;
161.118 + P->obj_val = P->c0;
161.119 + P->some = 0;
161.120 + p_infeas = d_infeas = 0.0;
161.121 + /* make all auxiliary variables basic */
161.122 + for (i = 1; i <= P->m; i++)
161.123 + { row = P->row[i];
161.124 + row->stat = GLP_BS;
161.125 + row->prim = row->dual = 0.0;
161.126 + /* check primal feasibility */
161.127 + if (row->type == GLP_LO || row->type == GLP_DB ||
161.128 + row->type == GLP_FX)
161.129 + { /* row has lower bound */
161.130 + if (row->lb > + parm->tol_bnd)
161.131 + { P->pbs_stat = GLP_NOFEAS;
161.132 + if (P->some == 0 && parm->meth != GLP_PRIMAL)
161.133 + P->some = i;
161.134 + }
161.135 + if (p_infeas < + row->lb)
161.136 + p_infeas = + row->lb;
161.137 + }
161.138 + if (row->type == GLP_UP || row->type == GLP_DB ||
161.139 + row->type == GLP_FX)
161.140 + { /* row has upper bound */
161.141 + if (row->ub < - parm->tol_bnd)
161.142 + { P->pbs_stat = GLP_NOFEAS;
161.143 + if (P->some == 0 && parm->meth != GLP_PRIMAL)
161.144 + P->some = i;
161.145 + }
161.146 + if (p_infeas < - row->ub)
161.147 + p_infeas = - row->ub;
161.148 + }
161.149 + }
161.150 + /* determine scale factor for the objective row */
161.151 + zeta = 1.0;
161.152 + for (j = 1; j <= P->n; j++)
161.153 + { col = P->col[j];
161.154 + if (zeta < fabs(col->coef)) zeta = fabs(col->coef);
161.155 + }
161.156 + zeta = (P->dir == GLP_MIN ? +1.0 : -1.0) / zeta;
161.157 + /* make all structural variables non-basic */
161.158 + for (j = 1; j <= P->n; j++)
161.159 + { col = P->col[j];
161.160 + if (col->type == GLP_FR)
161.161 + col->stat = GLP_NF, col->prim = 0.0;
161.162 + else if (col->type == GLP_LO)
161.163 +lo: col->stat = GLP_NL, col->prim = col->lb;
161.164 + else if (col->type == GLP_UP)
161.165 +up: col->stat = GLP_NU, col->prim = col->ub;
161.166 + else if (col->type == GLP_DB)
161.167 + { if (zeta * col->coef > 0.0)
161.168 + goto lo;
161.169 + else if (zeta * col->coef < 0.0)
161.170 + goto up;
161.171 + else if (fabs(col->lb) <= fabs(col->ub))
161.172 + goto lo;
161.173 + else
161.174 + goto up;
161.175 + }
161.176 + else if (col->type == GLP_FX)
161.177 + col->stat = GLP_NS, col->prim = col->lb;
161.178 + col->dual = col->coef;
161.179 + P->obj_val += col->coef * col->prim;
161.180 + /* check dual feasibility */
161.181 + if (col->type == GLP_FR || col->type == GLP_LO)
161.182 + { /* column has no upper bound */
161.183 + if (zeta * col->dual < - parm->tol_dj)
161.184 + { P->dbs_stat = GLP_NOFEAS;
161.185 + if (P->some == 0 && parm->meth == GLP_PRIMAL)
161.186 + P->some = P->m + j;
161.187 + }
161.188 + if (d_infeas < - zeta * col->dual)
161.189 + d_infeas = - zeta * col->dual;
161.190 + }
161.191 + if (col->type == GLP_FR || col->type == GLP_UP)
161.192 + { /* column has no lower bound */
161.193 + if (zeta * col->dual > + parm->tol_dj)
161.194 + { P->dbs_stat = GLP_NOFEAS;
161.195 + if (P->some == 0 && parm->meth == GLP_PRIMAL)
161.196 + P->some = P->m + j;
161.197 + }
161.198 + if (d_infeas < + zeta * col->dual)
161.199 + d_infeas = + zeta * col->dual;
161.200 + }
161.201 + }
161.202 + /* simulate the simplex solver output */
161.203 + if (parm->msg_lev >= GLP_MSG_ON && parm->out_dly == 0)
161.204 + { xprintf("~%6d: obj = %17.9e infeas = %10.3e\n", P->it_cnt,
161.205 + P->obj_val, parm->meth == GLP_PRIMAL ? p_infeas : d_infeas);
161.206 + }
161.207 + if (parm->msg_lev >= GLP_MSG_ALL && parm->out_dly == 0)
161.208 + { if (P->pbs_stat == GLP_FEAS && P->dbs_stat == GLP_FEAS)
161.209 + xprintf("OPTIMAL SOLUTION FOUND\n");
161.210 + else if (P->pbs_stat == GLP_NOFEAS)
161.211 + xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n");
161.212 + else if (parm->meth == GLP_PRIMAL)
161.213 + xprintf("PROBLEM HAS UNBOUNDED SOLUTION\n");
161.214 + else
161.215 + xprintf("PROBLEM HAS NO DUAL FEASIBLE SOLUTION\n");
161.216 + }
161.217 + return;
161.218 +}
161.219 +
161.220 +static int solve_lp(glp_prob *P, const glp_smcp *parm)
161.221 +{ /* solve LP directly without using the preprocessor */
161.222 + int ret;
161.223 + if (!glp_bf_exists(P))
161.224 + { ret = glp_factorize(P);
161.225 + if (ret == 0)
161.226 + ;
161.227 + else if (ret == GLP_EBADB)
161.228 + { if (parm->msg_lev >= GLP_MSG_ERR)
161.229 + xprintf("glp_simplex: initial basis is invalid\n");
161.230 + }
161.231 + else if (ret == GLP_ESING)
161.232 + { if (parm->msg_lev >= GLP_MSG_ERR)
161.233 + xprintf("glp_simplex: initial basis is singular\n");
161.234 + }
161.235 + else if (ret == GLP_ECOND)
161.236 + { if (parm->msg_lev >= GLP_MSG_ERR)
161.237 + xprintf(
161.238 + "glp_simplex: initial basis is ill-conditioned\n");
161.239 + }
161.240 + else
161.241 + xassert(ret != ret);
161.242 + if (ret != 0) goto done;
161.243 + }
161.244 + if (parm->meth == GLP_PRIMAL)
161.245 + ret = spx_primal(P, parm);
161.246 + else if (parm->meth == GLP_DUALP)
161.247 + { ret = spx_dual(P, parm);
161.248 + if (ret == GLP_EFAIL && P->valid)
161.249 + ret = spx_primal(P, parm);
161.250 + }
161.251 + else if (parm->meth == GLP_DUAL)
161.252 + ret = spx_dual(P, parm);
161.253 + else
161.254 + xassert(parm != parm);
161.255 +done: return ret;
161.256 +}
161.257 +
161.258 +static int preprocess_and_solve_lp(glp_prob *P, const glp_smcp *parm)
161.259 +{ /* solve LP using the preprocessor */
161.260 + NPP *npp;
161.261 + glp_prob *lp = NULL;
161.262 + glp_bfcp bfcp;
161.263 + int ret;
161.264 + if (parm->msg_lev >= GLP_MSG_ALL)
161.265 + xprintf("Preprocessing...\n");
161.266 + /* create preprocessor workspace */
161.267 + npp = npp_create_wksp();
161.268 + /* load original problem into the preprocessor workspace */
161.269 + npp_load_prob(npp, P, GLP_OFF, GLP_SOL, GLP_OFF);
161.270 + /* process LP prior to applying primal/dual simplex method */
161.271 + ret = npp_simplex(npp, parm);
161.272 + if (ret == 0)
161.273 + ;
161.274 + else if (ret == GLP_ENOPFS)
161.275 + { if (parm->msg_lev >= GLP_MSG_ALL)
161.276 + xprintf("PROBLEM HAS NO PRIMAL FEASIBLE SOLUTION\n");
161.277 + }
161.278 + else if (ret == GLP_ENODFS)
161.279 + { if (parm->msg_lev >= GLP_MSG_ALL)
161.280 + xprintf("PROBLEM HAS NO DUAL FEASIBLE SOLUTION\n");
161.281 + }
161.282 + else
161.283 + xassert(ret != ret);
161.284 + if (ret != 0) goto done;
161.285 + /* build transformed LP */
161.286 + lp = glp_create_prob();
161.287 + npp_build_prob(npp, lp);
161.288 + /* if the transformed LP is empty, it has empty solution, which
161.289 + is optimal */
161.290 + if (lp->m == 0 && lp->n == 0)
161.291 + { lp->pbs_stat = lp->dbs_stat = GLP_FEAS;
161.292 + lp->obj_val = lp->c0;
161.293 + if (parm->msg_lev >= GLP_MSG_ON && parm->out_dly == 0)
161.294 + { xprintf("~%6d: obj = %17.9e infeas = %10.3e\n", P->it_cnt,
161.295 + lp->obj_val, 0.0);
161.296 + }
161.297 + if (parm->msg_lev >= GLP_MSG_ALL)
161.298 + xprintf("OPTIMAL SOLUTION FOUND BY LP PREPROCESSOR\n");
161.299 + goto post;
161.300 + }
161.301 + if (parm->msg_lev >= GLP_MSG_ALL)
161.302 + { xprintf("%d row%s, %d column%s, %d non-zero%s\n",
161.303 + lp->m, lp->m == 1 ? "" : "s", lp->n, lp->n == 1 ? "" : "s",
161.304 + lp->nnz, lp->nnz == 1 ? "" : "s");
161.305 + }
161.306 + /* inherit basis factorization control parameters */
161.307 + glp_get_bfcp(P, &bfcp);
161.308 + glp_set_bfcp(lp, &bfcp);
161.309 + /* scale the transformed problem */
161.310 + { ENV *env = get_env_ptr();
161.311 + int term_out = env->term_out;
161.312 + if (!term_out || parm->msg_lev < GLP_MSG_ALL)
161.313 + env->term_out = GLP_OFF;
161.314 + else
161.315 + env->term_out = GLP_ON;
161.316 + glp_scale_prob(lp, GLP_SF_AUTO);
161.317 + env->term_out = term_out;
161.318 + }
161.319 + /* build advanced initial basis */
161.320 + { ENV *env = get_env_ptr();
161.321 + int term_out = env->term_out;
161.322 + if (!term_out || parm->msg_lev < GLP_MSG_ALL)
161.323 + env->term_out = GLP_OFF;
161.324 + else
161.325 + env->term_out = GLP_ON;
161.326 + glp_adv_basis(lp, 0);
161.327 + env->term_out = term_out;
161.328 + }
161.329 + /* solve the transformed LP */
161.330 + lp->it_cnt = P->it_cnt;
161.331 + ret = solve_lp(lp, parm);
161.332 + P->it_cnt = lp->it_cnt;
161.333 + /* only optimal solution can be postprocessed */
161.334 + if (!(ret == 0 && lp->pbs_stat == GLP_FEAS && lp->dbs_stat ==
161.335 + GLP_FEAS))
161.336 + { if (parm->msg_lev >= GLP_MSG_ERR)
161.337 + xprintf("glp_simplex: unable to recover undefined or non-op"
161.338 + "timal solution\n");
161.339 + if (ret == 0)
161.340 + { if (lp->pbs_stat == GLP_NOFEAS)
161.341 + ret = GLP_ENOPFS;
161.342 + else if (lp->dbs_stat == GLP_NOFEAS)
161.343 + ret = GLP_ENODFS;
161.344 + else
161.345 + xassert(lp != lp);
161.346 + }
161.347 + goto done;
161.348 + }
161.349 +post: /* postprocess solution from the transformed LP */
161.350 + npp_postprocess(npp, lp);
161.351 + /* the transformed LP is no longer needed */
161.352 + glp_delete_prob(lp), lp = NULL;
161.353 + /* store solution to the original problem */
161.354 + npp_unload_sol(npp, P);
161.355 + /* the original LP has been successfully solved */
161.356 + ret = 0;
161.357 +done: /* delete the transformed LP, if it exists */
161.358 + if (lp != NULL) glp_delete_prob(lp);
161.359 + /* delete preprocessor workspace */
161.360 + npp_delete_wksp(npp);
161.361 + return ret;
161.362 +}
161.363 +
161.364 +int glp_simplex(glp_prob *P, const glp_smcp *parm)
161.365 +{ /* solve LP problem with the simplex method */
161.366 + glp_smcp _parm;
161.367 + int i, j, ret;
161.368 + /* check problem object */
161.369 + if (P == NULL || P->magic != GLP_PROB_MAGIC)
161.370 + xerror("glp_simplex: P = %p; invalid problem object\n", P);
161.371 + if (P->tree != NULL && P->tree->reason != 0)
161.372 + xerror("glp_simplex: operation not allowed\n");
161.373 + /* check control parameters */
161.374 + if (parm == NULL)
161.375 + parm = &_parm, glp_init_smcp((glp_smcp *)parm);
161.376 + if (!(parm->msg_lev == GLP_MSG_OFF ||
161.377 + parm->msg_lev == GLP_MSG_ERR ||
161.378 + parm->msg_lev == GLP_MSG_ON ||
161.379 + parm->msg_lev == GLP_MSG_ALL ||
161.380 + parm->msg_lev == GLP_MSG_DBG))
161.381 + xerror("glp_simplex: msg_lev = %d; invalid parameter\n",
161.382 + parm->msg_lev);
161.383 + if (!(parm->meth == GLP_PRIMAL ||
161.384 + parm->meth == GLP_DUALP ||
161.385 + parm->meth == GLP_DUAL))
161.386 + xerror("glp_simplex: meth = %d; invalid parameter\n",
161.387 + parm->meth);
161.388 + if (!(parm->pricing == GLP_PT_STD ||
161.389 + parm->pricing == GLP_PT_PSE))
161.390 + xerror("glp_simplex: pricing = %d; invalid parameter\n",
161.391 + parm->pricing);
161.392 + if (!(parm->r_test == GLP_RT_STD ||
161.393 + parm->r_test == GLP_RT_HAR))
161.394 + xerror("glp_simplex: r_test = %d; invalid parameter\n",
161.395 + parm->r_test);
161.396 + if (!(0.0 < parm->tol_bnd && parm->tol_bnd < 1.0))
161.397 + xerror("glp_simplex: tol_bnd = %g; invalid parameter\n",
161.398 + parm->tol_bnd);
161.399 + if (!(0.0 < parm->tol_dj && parm->tol_dj < 1.0))
161.400 + xerror("glp_simplex: tol_dj = %g; invalid parameter\n",
161.401 + parm->tol_dj);
161.402 + if (!(0.0 < parm->tol_piv && parm->tol_piv < 1.0))
161.403 + xerror("glp_simplex: tol_piv = %g; invalid parameter\n",
161.404 + parm->tol_piv);
161.405 + if (parm->it_lim < 0)
161.406 + xerror("glp_simplex: it_lim = %d; invalid parameter\n",
161.407 + parm->it_lim);
161.408 + if (parm->tm_lim < 0)
161.409 + xerror("glp_simplex: tm_lim = %d; invalid parameter\n",
161.410 + parm->tm_lim);
161.411 + if (parm->out_frq < 1)
161.412 + xerror("glp_simplex: out_frq = %d; invalid parameter\n",
161.413 + parm->out_frq);
161.414 + if (parm->out_dly < 0)
161.415 + xerror("glp_simplex: out_dly = %d; invalid parameter\n",
161.416 + parm->out_dly);
161.417 + if (!(parm->presolve == GLP_ON || parm->presolve == GLP_OFF))
161.418 + xerror("glp_simplex: presolve = %d; invalid parameter\n",
161.419 + parm->presolve);
161.420 + /* basic solution is currently undefined */
161.421 + P->pbs_stat = P->dbs_stat = GLP_UNDEF;
161.422 + P->obj_val = 0.0;
161.423 + P->some = 0;
161.424 + /* check bounds of double-bounded variables */
161.425 + for (i = 1; i <= P->m; i++)
161.426 + { GLPROW *row = P->row[i];
161.427 + if (row->type == GLP_DB && row->lb >= row->ub)
161.428 + { if (parm->msg_lev >= GLP_MSG_ERR)
161.429 + xprintf("glp_simplex: row %d: lb = %g, ub = %g; incorrec"
161.430 + "t bounds\n", i, row->lb, row->ub);
161.431 + ret = GLP_EBOUND;
161.432 + goto done;
161.433 + }
161.434 + }
161.435 + for (j = 1; j <= P->n; j++)
161.436 + { GLPCOL *col = P->col[j];
161.437 + if (col->type == GLP_DB && col->lb >= col->ub)
161.438 + { if (parm->msg_lev >= GLP_MSG_ERR)
161.439 + xprintf("glp_simplex: column %d: lb = %g, ub = %g; incor"
161.440 + "rect bounds\n", j, col->lb, col->ub);
161.441 + ret = GLP_EBOUND;
161.442 + goto done;
161.443 + }
161.444 + }
161.445 + /* solve LP problem */
161.446 + if (parm->msg_lev >= GLP_MSG_ALL)
161.447 + { xprintf("GLPK Simplex Optimizer, v%s\n", glp_version());
161.448 + xprintf("%d row%s, %d column%s, %d non-zero%s\n",
161.449 + P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
161.450 + P->nnz, P->nnz == 1 ? "" : "s");
161.451 + }
161.452 + if (P->nnz == 0)
161.453 + trivial_lp(P, parm), ret = 0;
161.454 + else if (!parm->presolve)
161.455 + ret = solve_lp(P, parm);
161.456 + else
161.457 + ret = preprocess_and_solve_lp(P, parm);
161.458 +done: /* return to the application program */
161.459 + return ret;
161.460 +}
161.461 +
161.462 +/***********************************************************************
161.463 +* NAME
161.464 +*
161.465 +* glp_init_smcp - initialize simplex method control parameters
161.466 +*
161.467 +* SYNOPSIS
161.468 +*
161.469 +* void glp_init_smcp(glp_smcp *parm);
161.470 +*
161.471 +* DESCRIPTION
161.472 +*
161.473 +* The routine glp_init_smcp initializes control parameters, which are
161.474 +* used by the simplex solver, with default values.
161.475 +*
161.476 +* Default values of the control parameters are stored in a glp_smcp
161.477 +* structure, which the parameter parm points to. */
161.478 +
161.479 +void glp_init_smcp(glp_smcp *parm)
161.480 +{ parm->msg_lev = GLP_MSG_ALL;
161.481 + parm->meth = GLP_PRIMAL;
161.482 + parm->pricing = GLP_PT_PSE;
161.483 + parm->r_test = GLP_RT_HAR;
161.484 + parm->tol_bnd = 1e-7;
161.485 + parm->tol_dj = 1e-7;
161.486 + parm->tol_piv = 1e-10;
161.487 + parm->obj_ll = -DBL_MAX;
161.488 + parm->obj_ul = +DBL_MAX;
161.489 + parm->it_lim = INT_MAX;
161.490 + parm->tm_lim = INT_MAX;
161.491 + parm->out_frq = 500;
161.492 + parm->out_dly = 0;
161.493 + parm->presolve = GLP_OFF;
161.494 + return;
161.495 +}
161.496 +
161.497 +/***********************************************************************
161.498 +* NAME
161.499 +*
161.500 +* glp_get_status - retrieve generic status of basic solution
161.501 +*
161.502 +* SYNOPSIS
161.503 +*
161.504 +* int glp_get_status(glp_prob *lp);
161.505 +*
161.506 +* RETURNS
161.507 +*
161.508 +* The routine glp_get_status reports the generic status of the basic
161.509 +* solution for the specified problem object as follows:
161.510 +*
161.511 +* GLP_OPT - solution is optimal;
161.512 +* GLP_FEAS - solution is feasible;
161.513 +* GLP_INFEAS - solution is infeasible;
161.514 +* GLP_NOFEAS - problem has no feasible solution;
161.515 +* GLP_UNBND - problem has unbounded solution;
161.516 +* GLP_UNDEF - solution is undefined. */
161.517 +
161.518 +int glp_get_status(glp_prob *lp)
161.519 +{ int status;
161.520 + status = glp_get_prim_stat(lp);
161.521 + switch (status)
161.522 + { case GLP_FEAS:
161.523 + switch (glp_get_dual_stat(lp))
161.524 + { case GLP_FEAS:
161.525 + status = GLP_OPT;
161.526 + break;
161.527 + case GLP_NOFEAS:
161.528 + status = GLP_UNBND;
161.529 + break;
161.530 + case GLP_UNDEF:
161.531 + case GLP_INFEAS:
161.532 + status = status;
161.533 + break;
161.534 + default:
161.535 + xassert(lp != lp);
161.536 + }
161.537 + break;
161.538 + case GLP_UNDEF:
161.539 + case GLP_INFEAS:
161.540 + case GLP_NOFEAS:
161.541 + status = status;
161.542 + break;
161.543 + default:
161.544 + xassert(lp != lp);
161.545 + }
161.546 + return status;
161.547 +}
161.548 +
161.549 +/***********************************************************************
161.550 +* NAME
161.551 +*
161.552 +* glp_get_prim_stat - retrieve status of primal basic solution
161.553 +*
161.554 +* SYNOPSIS
161.555 +*
161.556 +* int glp_get_prim_stat(glp_prob *lp);
161.557 +*
161.558 +* RETURNS
161.559 +*
161.560 +* The routine glp_get_prim_stat reports the status of the primal basic
161.561 +* solution for the specified problem object as follows:
161.562 +*
161.563 +* GLP_UNDEF - primal solution is undefined;
161.564 +* GLP_FEAS - primal solution is feasible;
161.565 +* GLP_INFEAS - primal solution is infeasible;
161.566 +* GLP_NOFEAS - no primal feasible solution exists. */
161.567 +
161.568 +int glp_get_prim_stat(glp_prob *lp)
161.569 +{ int pbs_stat = lp->pbs_stat;
161.570 + return pbs_stat;
161.571 +}
161.572 +
161.573 +/***********************************************************************
161.574 +* NAME
161.575 +*
161.576 +* glp_get_dual_stat - retrieve status of dual basic solution
161.577 +*
161.578 +* SYNOPSIS
161.579 +*
161.580 +* int glp_get_dual_stat(glp_prob *lp);
161.581 +*
161.582 +* RETURNS
161.583 +*
161.584 +* The routine glp_get_dual_stat reports the status of the dual basic
161.585 +* solution for the specified problem object as follows:
161.586 +*
161.587 +* GLP_UNDEF - dual solution is undefined;
161.588 +* GLP_FEAS - dual solution is feasible;
161.589 +* GLP_INFEAS - dual solution is infeasible;
161.590 +* GLP_NOFEAS - no dual feasible solution exists. */
161.591 +
161.592 +int glp_get_dual_stat(glp_prob *lp)
161.593 +{ int dbs_stat = lp->dbs_stat;
161.594 + return dbs_stat;
161.595 +}
161.596 +
161.597 +/***********************************************************************
161.598 +* NAME
161.599 +*
161.600 +* glp_get_obj_val - retrieve objective value (basic solution)
161.601 +*
161.602 +* SYNOPSIS
161.603 +*
161.604 +* double glp_get_obj_val(glp_prob *lp);
161.605 +*
161.606 +* RETURNS
161.607 +*
161.608 +* The routine glp_get_obj_val returns value of the objective function
161.609 +* for basic solution. */
161.610 +
161.611 +double glp_get_obj_val(glp_prob *lp)
161.612 +{ /*struct LPXCPS *cps = lp->cps;*/
161.613 + double z;
161.614 + z = lp->obj_val;
161.615 + /*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/
161.616 + return z;
161.617 +}
161.618 +
161.619 +/***********************************************************************
161.620 +* NAME
161.621 +*
161.622 +* glp_get_row_stat - retrieve row status
161.623 +*
161.624 +* SYNOPSIS
161.625 +*
161.626 +* int glp_get_row_stat(glp_prob *lp, int i);
161.627 +*
161.628 +* RETURNS
161.629 +*
161.630 +* The routine glp_get_row_stat returns current status assigned to the
161.631 +* auxiliary variable associated with i-th row as follows:
161.632 +*
161.633 +* GLP_BS - basic variable;
161.634 +* GLP_NL - non-basic variable on its lower bound;
161.635 +* GLP_NU - non-basic variable on its upper bound;
161.636 +* GLP_NF - non-basic free (unbounded) variable;
161.637 +* GLP_NS - non-basic fixed variable. */
161.638 +
161.639 +int glp_get_row_stat(glp_prob *lp, int i)
161.640 +{ if (!(1 <= i && i <= lp->m))
161.641 + xerror("glp_get_row_stat: i = %d; row number out of range\n",
161.642 + i);
161.643 + return lp->row[i]->stat;
161.644 +}
161.645 +
161.646 +/***********************************************************************
161.647 +* NAME
161.648 +*
161.649 +* glp_get_row_prim - retrieve row primal value (basic solution)
161.650 +*
161.651 +* SYNOPSIS
161.652 +*
161.653 +* double glp_get_row_prim(glp_prob *lp, int i);
161.654 +*
161.655 +* RETURNS
161.656 +*
161.657 +* The routine glp_get_row_prim returns primal value of the auxiliary
161.658 +* variable associated with i-th row. */
161.659 +
161.660 +double glp_get_row_prim(glp_prob *lp, int i)
161.661 +{ /*struct LPXCPS *cps = lp->cps;*/
161.662 + double prim;
161.663 + if (!(1 <= i && i <= lp->m))
161.664 + xerror("glp_get_row_prim: i = %d; row number out of range\n",
161.665 + i);
161.666 + prim = lp->row[i]->prim;
161.667 + /*if (cps->round && fabs(prim) < 1e-9) prim = 0.0;*/
161.668 + return prim;
161.669 +}
161.670 +
161.671 +/***********************************************************************
161.672 +* NAME
161.673 +*
161.674 +* glp_get_row_dual - retrieve row dual value (basic solution)
161.675 +*
161.676 +* SYNOPSIS
161.677 +*
161.678 +* double glp_get_row_dual(glp_prob *lp, int i);
161.679 +*
161.680 +* RETURNS
161.681 +*
161.682 +* The routine glp_get_row_dual returns dual value (i.e. reduced cost)
161.683 +* of the auxiliary variable associated with i-th row. */
161.684 +
161.685 +double glp_get_row_dual(glp_prob *lp, int i)
161.686 +{ /*struct LPXCPS *cps = lp->cps;*/
161.687 + double dual;
161.688 + if (!(1 <= i && i <= lp->m))
161.689 + xerror("glp_get_row_dual: i = %d; row number out of range\n",
161.690 + i);
161.691 + dual = lp->row[i]->dual;
161.692 + /*if (cps->round && fabs(dual) < 1e-9) dual = 0.0;*/
161.693 + return dual;
161.694 +}
161.695 +
161.696 +/***********************************************************************
161.697 +* NAME
161.698 +*
161.699 +* glp_get_col_stat - retrieve column status
161.700 +*
161.701 +* SYNOPSIS
161.702 +*
161.703 +* int glp_get_col_stat(glp_prob *lp, int j);
161.704 +*
161.705 +* RETURNS
161.706 +*
161.707 +* The routine glp_get_col_stat returns current status assigned to the
161.708 +* structural variable associated with j-th column as follows:
161.709 +*
161.710 +* GLP_BS - basic variable;
161.711 +* GLP_NL - non-basic variable on its lower bound;
161.712 +* GLP_NU - non-basic variable on its upper bound;
161.713 +* GLP_NF - non-basic free (unbounded) variable;
161.714 +* GLP_NS - non-basic fixed variable. */
161.715 +
161.716 +int glp_get_col_stat(glp_prob *lp, int j)
161.717 +{ if (!(1 <= j && j <= lp->n))
161.718 + xerror("glp_get_col_stat: j = %d; column number out of range\n"
161.719 + , j);
161.720 + return lp->col[j]->stat;
161.721 +}
161.722 +
161.723 +/***********************************************************************
161.724 +* NAME
161.725 +*
161.726 +* glp_get_col_prim - retrieve column primal value (basic solution)
161.727 +*
161.728 +* SYNOPSIS
161.729 +*
161.730 +* double glp_get_col_prim(glp_prob *lp, int j);
161.731 +*
161.732 +* RETURNS
161.733 +*
161.734 +* The routine glp_get_col_prim returns primal value of the structural
161.735 +* variable associated with j-th column. */
161.736 +
161.737 +double glp_get_col_prim(glp_prob *lp, int j)
161.738 +{ /*struct LPXCPS *cps = lp->cps;*/
161.739 + double prim;
161.740 + if (!(1 <= j && j <= lp->n))
161.741 + xerror("glp_get_col_prim: j = %d; column number out of range\n"
161.742 + , j);
161.743 + prim = lp->col[j]->prim;
161.744 + /*if (cps->round && fabs(prim) < 1e-9) prim = 0.0;*/
161.745 + return prim;
161.746 +}
161.747 +
161.748 +/***********************************************************************
161.749 +* NAME
161.750 +*
161.751 +* glp_get_col_dual - retrieve column dual value (basic solution)
161.752 +*
161.753 +* SYNOPSIS
161.754 +*
161.755 +* double glp_get_col_dual(glp_prob *lp, int j);
161.756 +*
161.757 +* RETURNS
161.758 +*
161.759 +* The routine glp_get_col_dual returns dual value (i.e. reduced cost)
161.760 +* of the structural variable associated with j-th column. */
161.761 +
161.762 +double glp_get_col_dual(glp_prob *lp, int j)
161.763 +{ /*struct LPXCPS *cps = lp->cps;*/
161.764 + double dual;
161.765 + if (!(1 <= j && j <= lp->n))
161.766 + xerror("glp_get_col_dual: j = %d; column number out of range\n"
161.767 + , j);
161.768 + dual = lp->col[j]->dual;
161.769 + /*if (cps->round && fabs(dual) < 1e-9) dual = 0.0;*/
161.770 + return dual;
161.771 +}
161.772 +
161.773 +/***********************************************************************
161.774 +* NAME
161.775 +*
161.776 +* glp_get_unbnd_ray - determine variable causing unboundedness
161.777 +*
161.778 +* SYNOPSIS
161.779 +*
161.780 +* int glp_get_unbnd_ray(glp_prob *lp);
161.781 +*
161.782 +* RETURNS
161.783 +*
161.784 +* The routine glp_get_unbnd_ray returns the number k of a variable,
161.785 +* which causes primal or dual unboundedness. If 1 <= k <= m, it is
161.786 +* k-th auxiliary variable, and if m+1 <= k <= m+n, it is (k-m)-th
161.787 +* structural variable, where m is the number of rows, n is the number
161.788 +* of columns in the problem object. If such variable is not defined,
161.789 +* the routine returns 0.
161.790 +*
161.791 +* COMMENTS
161.792 +*
161.793 +* If it is not exactly known which version of the simplex solver
161.794 +* detected unboundedness, i.e. whether the unboundedness is primal or
161.795 +* dual, it is sufficient to check the status of the variable reported
161.796 +* with the routine glp_get_row_stat or glp_get_col_stat. If the
161.797 +* variable is non-basic, the unboundedness is primal, otherwise, if
161.798 +* the variable is basic, the unboundedness is dual (the latter case
161.799 +* means that the problem has no primal feasible dolution). */
161.800 +
161.801 +int glp_get_unbnd_ray(glp_prob *lp)
161.802 +{ int k;
161.803 + k = lp->some;
161.804 + xassert(k >= 0);
161.805 + if (k > lp->m + lp->n) k = 0;
161.806 + return k;
161.807 +}
161.808 +
161.809 +/* eof */
162.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
162.2 +++ b/src/glpapi07.c Mon Dec 06 13:09:21 2010 +0100
162.3 @@ -0,0 +1,451 @@
162.4 +/* glpapi07.c (exact simplex solver) */
162.5 +
162.6 +/***********************************************************************
162.7 +* This code is part of GLPK (GNU Linear Programming Kit).
162.8 +*
162.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
162.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
162.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
162.12 +* E-mail: <mao@gnu.org>.
162.13 +*
162.14 +* GLPK is free software: you can redistribute it and/or modify it
162.15 +* under the terms of the GNU General Public License as published by
162.16 +* the Free Software Foundation, either version 3 of the License, or
162.17 +* (at your option) any later version.
162.18 +*
162.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
162.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
162.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
162.22 +* License for more details.
162.23 +*
162.24 +* You should have received a copy of the GNU General Public License
162.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
162.26 +***********************************************************************/
162.27 +
162.28 +#include "glpapi.h"
162.29 +#include "glpssx.h"
162.30 +
162.31 +/***********************************************************************
162.32 +* NAME
162.33 +*
162.34 +* glp_exact - solve LP problem in exact arithmetic
162.35 +*
162.36 +* SYNOPSIS
162.37 +*
162.38 +* int glp_exact(glp_prob *lp, const glp_smcp *parm);
162.39 +*
162.40 +* DESCRIPTION
162.41 +*
162.42 +* The routine glp_exact is a tentative implementation of the primal
162.43 +* two-phase simplex method based on exact (rational) arithmetic. It is
162.44 +* similar to the routine glp_simplex, however, for all internal
162.45 +* computations it uses arithmetic of rational numbers, which is exact
162.46 +* in mathematical sense, i.e. free of round-off errors unlike floating
162.47 +* point arithmetic.
162.48 +*
162.49 +* Note that the routine glp_exact uses inly two control parameters
162.50 +* passed in the structure glp_smcp, namely, it_lim and tm_lim.
162.51 +*
162.52 +* RETURNS
162.53 +*
162.54 +* 0 The LP problem instance has been successfully solved. This code
162.55 +* does not necessarily mean that the solver has found optimal
162.56 +* solution. It only means that the solution process was successful.
162.57 +*
162.58 +* GLP_EBADB
162.59 +* Unable to start the search, because the initial basis specified
162.60 +* in the problem object is invalid--the number of basic (auxiliary
162.61 +* and structural) variables is not the same as the number of rows in
162.62 +* the problem object.
162.63 +*
162.64 +* GLP_ESING
162.65 +* Unable to start the search, because the basis matrix correspodning
162.66 +* to the initial basis is exactly singular.
162.67 +*
162.68 +* GLP_EBOUND
162.69 +* Unable to start the search, because some double-bounded variables
162.70 +* have incorrect bounds.
162.71 +*
162.72 +* GLP_EFAIL
162.73 +* The problem has no rows/columns.
162.74 +*
162.75 +* GLP_EITLIM
162.76 +* The search was prematurely terminated, because the simplex
162.77 +* iteration limit has been exceeded.
162.78 +*
162.79 +* GLP_ETMLIM
162.80 +* The search was prematurely terminated, because the time limit has
162.81 +* been exceeded. */
162.82 +
162.83 +static void set_d_eps(mpq_t x, double val)
162.84 +{ /* convert double val to rational x obtaining a more adequate
162.85 + fraction than provided by mpq_set_d due to allowing a small
162.86 + approximation error specified by a given relative tolerance;
162.87 + for example, mpq_set_d would give the following
162.88 + 1/3 ~= 0.333333333333333314829616256247391... ->
162.89 + -> 6004799503160661/18014398509481984
162.90 + while this routine gives exactly 1/3 */
162.91 + int s, n, j;
162.92 + double f, p, q, eps = 1e-9;
162.93 + mpq_t temp;
162.94 + xassert(-DBL_MAX <= val && val <= +DBL_MAX);
162.95 +#if 1 /* 30/VII-2008 */
162.96 + if (val == floor(val))
162.97 + { /* if val is integral, do not approximate */
162.98 + mpq_set_d(x, val);
162.99 + goto done;
162.100 + }
162.101 +#endif
162.102 + if (val > 0.0)
162.103 + s = +1;
162.104 + else if (val < 0.0)
162.105 + s = -1;
162.106 + else
162.107 + { mpq_set_si(x, 0, 1);
162.108 + goto done;
162.109 + }
162.110 + f = frexp(fabs(val), &n);
162.111 + /* |val| = f * 2^n, where 0.5 <= f < 1.0 */
162.112 + fp2rat(f, 0.1 * eps, &p, &q);
162.113 + /* f ~= p / q, where p and q are integers */
162.114 + mpq_init(temp);
162.115 + mpq_set_d(x, p);
162.116 + mpq_set_d(temp, q);
162.117 + mpq_div(x, x, temp);
162.118 + mpq_set_si(temp, 1, 1);
162.119 + for (j = 1; j <= abs(n); j++)
162.120 + mpq_add(temp, temp, temp);
162.121 + if (n > 0)
162.122 + mpq_mul(x, x, temp);
162.123 + else if (n < 0)
162.124 + mpq_div(x, x, temp);
162.125 + mpq_clear(temp);
162.126 + if (s < 0) mpq_neg(x, x);
162.127 + /* check that the desired tolerance has been attained */
162.128 + xassert(fabs(val - mpq_get_d(x)) <= eps * (1.0 + fabs(val)));
162.129 +done: return;
162.130 +}
162.131 +
162.132 +static void load_data(SSX *ssx, LPX *lp)
162.133 +{ /* load LP problem data into simplex solver workspace */
162.134 + int m = ssx->m;
162.135 + int n = ssx->n;
162.136 + int nnz = ssx->A_ptr[n+1]-1;
162.137 + int j, k, type, loc, len, *ind;
162.138 + double lb, ub, coef, *val;
162.139 + xassert(lpx_get_num_rows(lp) == m);
162.140 + xassert(lpx_get_num_cols(lp) == n);
162.141 + xassert(lpx_get_num_nz(lp) == nnz);
162.142 + /* types and bounds of rows and columns */
162.143 + for (k = 1; k <= m+n; k++)
162.144 + { if (k <= m)
162.145 + { type = lpx_get_row_type(lp, k);
162.146 + lb = lpx_get_row_lb(lp, k);
162.147 + ub = lpx_get_row_ub(lp, k);
162.148 + }
162.149 + else
162.150 + { type = lpx_get_col_type(lp, k-m);
162.151 + lb = lpx_get_col_lb(lp, k-m);
162.152 + ub = lpx_get_col_ub(lp, k-m);
162.153 + }
162.154 + switch (type)
162.155 + { case LPX_FR: type = SSX_FR; break;
162.156 + case LPX_LO: type = SSX_LO; break;
162.157 + case LPX_UP: type = SSX_UP; break;
162.158 + case LPX_DB: type = SSX_DB; break;
162.159 + case LPX_FX: type = SSX_FX; break;
162.160 + default: xassert(type != type);
162.161 + }
162.162 + ssx->type[k] = type;
162.163 + set_d_eps(ssx->lb[k], lb);
162.164 + set_d_eps(ssx->ub[k], ub);
162.165 + }
162.166 + /* optimization direction */
162.167 + switch (lpx_get_obj_dir(lp))
162.168 + { case LPX_MIN: ssx->dir = SSX_MIN; break;
162.169 + case LPX_MAX: ssx->dir = SSX_MAX; break;
162.170 + default: xassert(lp != lp);
162.171 + }
162.172 + /* objective coefficients */
162.173 + for (k = 0; k <= m+n; k++)
162.174 + { if (k == 0)
162.175 + coef = lpx_get_obj_coef(lp, 0);
162.176 + else if (k <= m)
162.177 + coef = 0.0;
162.178 + else
162.179 + coef = lpx_get_obj_coef(lp, k-m);
162.180 + set_d_eps(ssx->coef[k], coef);
162.181 + }
162.182 + /* constraint coefficients */
162.183 + ind = xcalloc(1+m, sizeof(int));
162.184 + val = xcalloc(1+m, sizeof(double));
162.185 + loc = 0;
162.186 + for (j = 1; j <= n; j++)
162.187 + { ssx->A_ptr[j] = loc+1;
162.188 + len = lpx_get_mat_col(lp, j, ind, val);
162.189 + for (k = 1; k <= len; k++)
162.190 + { loc++;
162.191 + ssx->A_ind[loc] = ind[k];
162.192 + set_d_eps(ssx->A_val[loc], val[k]);
162.193 + }
162.194 + }
162.195 + xassert(loc == nnz);
162.196 + xfree(ind);
162.197 + xfree(val);
162.198 + return;
162.199 +}
162.200 +
162.201 +static int load_basis(SSX *ssx, LPX *lp)
162.202 +{ /* load current LP basis into simplex solver workspace */
162.203 + int m = ssx->m;
162.204 + int n = ssx->n;
162.205 + int *type = ssx->type;
162.206 + int *stat = ssx->stat;
162.207 + int *Q_row = ssx->Q_row;
162.208 + int *Q_col = ssx->Q_col;
162.209 + int i, j, k;
162.210 + xassert(lpx_get_num_rows(lp) == m);
162.211 + xassert(lpx_get_num_cols(lp) == n);
162.212 + /* statuses of rows and columns */
162.213 + for (k = 1; k <= m+n; k++)
162.214 + { if (k <= m)
162.215 + stat[k] = lpx_get_row_stat(lp, k);
162.216 + else
162.217 + stat[k] = lpx_get_col_stat(lp, k-m);
162.218 + switch (stat[k])
162.219 + { case LPX_BS:
162.220 + stat[k] = SSX_BS;
162.221 + break;
162.222 + case LPX_NL:
162.223 + stat[k] = SSX_NL;
162.224 + xassert(type[k] == SSX_LO || type[k] == SSX_DB);
162.225 + break;
162.226 + case LPX_NU:
162.227 + stat[k] = SSX_NU;
162.228 + xassert(type[k] == SSX_UP || type[k] == SSX_DB);
162.229 + break;
162.230 + case LPX_NF:
162.231 + stat[k] = SSX_NF;
162.232 + xassert(type[k] == SSX_FR);
162.233 + break;
162.234 + case LPX_NS:
162.235 + stat[k] = SSX_NS;
162.236 + xassert(type[k] == SSX_FX);
162.237 + break;
162.238 + default:
162.239 + xassert(stat != stat);
162.240 + }
162.241 + }
162.242 + /* build permutation matix Q */
162.243 + i = j = 0;
162.244 + for (k = 1; k <= m+n; k++)
162.245 + { if (stat[k] == SSX_BS)
162.246 + { i++;
162.247 + if (i > m) return 1;
162.248 + Q_row[k] = i, Q_col[i] = k;
162.249 + }
162.250 + else
162.251 + { j++;
162.252 + if (j > n) return 1;
162.253 + Q_row[k] = m+j, Q_col[m+j] = k;
162.254 + }
162.255 + }
162.256 + xassert(i == m && j == n);
162.257 + return 0;
162.258 +}
162.259 +
162.260 +int glp_exact(glp_prob *lp, const glp_smcp *parm)
162.261 +{ glp_smcp _parm;
162.262 + SSX *ssx;
162.263 + int m = lpx_get_num_rows(lp);
162.264 + int n = lpx_get_num_cols(lp);
162.265 + int nnz = lpx_get_num_nz(lp);
162.266 + int i, j, k, type, pst, dst, ret, *stat;
162.267 + double lb, ub, *prim, *dual, sum;
162.268 + if (parm == NULL)
162.269 + parm = &_parm, glp_init_smcp((glp_smcp *)parm);
162.270 + /* check control parameters */
162.271 + if (parm->it_lim < 0)
162.272 + xerror("glp_exact: it_lim = %d; invalid parameter\n",
162.273 + parm->it_lim);
162.274 + if (parm->tm_lim < 0)
162.275 + xerror("glp_exact: tm_lim = %d; invalid parameter\n",
162.276 + parm->tm_lim);
162.277 + /* the problem must have at least one row and one column */
162.278 + if (!(m > 0 && n > 0))
162.279 + { xprintf("glp_exact: problem has no rows/columns\n");
162.280 + return GLP_EFAIL;
162.281 + }
162.282 +#if 1
162.283 + /* basic solution is currently undefined */
162.284 + lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
162.285 + lp->obj_val = 0.0;
162.286 + lp->some = 0;
162.287 +#endif
162.288 + /* check that all double-bounded variables have correct bounds */
162.289 + for (k = 1; k <= m+n; k++)
162.290 + { if (k <= m)
162.291 + { type = lpx_get_row_type(lp, k);
162.292 + lb = lpx_get_row_lb(lp, k);
162.293 + ub = lpx_get_row_ub(lp, k);
162.294 + }
162.295 + else
162.296 + { type = lpx_get_col_type(lp, k-m);
162.297 + lb = lpx_get_col_lb(lp, k-m);
162.298 + ub = lpx_get_col_ub(lp, k-m);
162.299 + }
162.300 + if (type == LPX_DB && lb >= ub)
162.301 + { xprintf("glp_exact: %s %d has invalid bounds\n",
162.302 + k <= m ? "row" : "column", k <= m ? k : k-m);
162.303 + return GLP_EBOUND;
162.304 + }
162.305 + }
162.306 + /* create the simplex solver workspace */
162.307 + xprintf("glp_exact: %d rows, %d columns, %d non-zeros\n",
162.308 + m, n, nnz);
162.309 +#ifdef HAVE_GMP
162.310 + xprintf("GNU MP bignum library is being used\n");
162.311 +#else
162.312 + xprintf("GLPK bignum module is being used\n");
162.313 + xprintf("(Consider installing GNU MP to attain a much better perf"
162.314 + "ormance.)\n");
162.315 +#endif
162.316 + ssx = ssx_create(m, n, nnz);
162.317 + /* load LP problem data into the workspace */
162.318 + load_data(ssx, lp);
162.319 + /* load current LP basis into the workspace */
162.320 + if (load_basis(ssx, lp))
162.321 + { xprintf("glp_exact: initial LP basis is invalid\n");
162.322 + ret = GLP_EBADB;
162.323 + goto done;
162.324 + }
162.325 + /* inherit some control parameters from the LP object */
162.326 +#if 0
162.327 + ssx->it_lim = lpx_get_int_parm(lp, LPX_K_ITLIM);
162.328 + ssx->it_cnt = lpx_get_int_parm(lp, LPX_K_ITCNT);
162.329 + ssx->tm_lim = lpx_get_real_parm(lp, LPX_K_TMLIM);
162.330 +#else
162.331 + ssx->it_lim = parm->it_lim;
162.332 + ssx->it_cnt = lp->it_cnt;
162.333 + ssx->tm_lim = (double)parm->tm_lim / 1000.0;
162.334 +#endif
162.335 + ssx->out_frq = 5.0;
162.336 + ssx->tm_beg = xtime();
162.337 + ssx->tm_lag = xlset(0);
162.338 + /* solve LP */
162.339 + ret = ssx_driver(ssx);
162.340 + /* copy back some statistics to the LP object */
162.341 +#if 0
162.342 + lpx_set_int_parm(lp, LPX_K_ITLIM, ssx->it_lim);
162.343 + lpx_set_int_parm(lp, LPX_K_ITCNT, ssx->it_cnt);
162.344 + lpx_set_real_parm(lp, LPX_K_TMLIM, ssx->tm_lim);
162.345 +#else
162.346 + lp->it_cnt = ssx->it_cnt;
162.347 +#endif
162.348 + /* analyze the return code */
162.349 + switch (ret)
162.350 + { case 0:
162.351 + /* optimal solution found */
162.352 + ret = 0;
162.353 + pst = LPX_P_FEAS, dst = LPX_D_FEAS;
162.354 + break;
162.355 + case 1:
162.356 + /* problem has no feasible solution */
162.357 + ret = 0;
162.358 + pst = LPX_P_NOFEAS, dst = LPX_D_INFEAS;
162.359 + break;
162.360 + case 2:
162.361 + /* problem has unbounded solution */
162.362 + ret = 0;
162.363 + pst = LPX_P_FEAS, dst = LPX_D_NOFEAS;
162.364 +#if 1
162.365 + xassert(1 <= ssx->q && ssx->q <= n);
162.366 + lp->some = ssx->Q_col[m + ssx->q];
162.367 + xassert(1 <= lp->some && lp->some <= m+n);
162.368 +#endif
162.369 + break;
162.370 + case 3:
162.371 + /* iteration limit exceeded (phase I) */
162.372 + ret = GLP_EITLIM;
162.373 + pst = LPX_P_INFEAS, dst = LPX_D_INFEAS;
162.374 + break;
162.375 + case 4:
162.376 + /* iteration limit exceeded (phase II) */
162.377 + ret = GLP_EITLIM;
162.378 + pst = LPX_P_FEAS, dst = LPX_D_INFEAS;
162.379 + break;
162.380 + case 5:
162.381 + /* time limit exceeded (phase I) */
162.382 + ret = GLP_ETMLIM;
162.383 + pst = LPX_P_INFEAS, dst = LPX_D_INFEAS;
162.384 + break;
162.385 + case 6:
162.386 + /* time limit exceeded (phase II) */
162.387 + ret = GLP_ETMLIM;
162.388 + pst = LPX_P_FEAS, dst = LPX_D_INFEAS;
162.389 + break;
162.390 + case 7:
162.391 + /* initial basis matrix is singular */
162.392 + ret = GLP_ESING;
162.393 + goto done;
162.394 + default:
162.395 + xassert(ret != ret);
162.396 + }
162.397 + /* obtain final basic solution components */
162.398 + stat = xcalloc(1+m+n, sizeof(int));
162.399 + prim = xcalloc(1+m+n, sizeof(double));
162.400 + dual = xcalloc(1+m+n, sizeof(double));
162.401 + for (k = 1; k <= m+n; k++)
162.402 + { if (ssx->stat[k] == SSX_BS)
162.403 + { i = ssx->Q_row[k]; /* x[k] = xB[i] */
162.404 + xassert(1 <= i && i <= m);
162.405 + stat[k] = LPX_BS;
162.406 + prim[k] = mpq_get_d(ssx->bbar[i]);
162.407 + dual[k] = 0.0;
162.408 + }
162.409 + else
162.410 + { j = ssx->Q_row[k] - m; /* x[k] = xN[j] */
162.411 + xassert(1 <= j && j <= n);
162.412 + switch (ssx->stat[k])
162.413 + { case SSX_NF:
162.414 + stat[k] = LPX_NF;
162.415 + prim[k] = 0.0;
162.416 + break;
162.417 + case SSX_NL:
162.418 + stat[k] = LPX_NL;
162.419 + prim[k] = mpq_get_d(ssx->lb[k]);
162.420 + break;
162.421 + case SSX_NU:
162.422 + stat[k] = LPX_NU;
162.423 + prim[k] = mpq_get_d(ssx->ub[k]);
162.424 + break;
162.425 + case SSX_NS:
162.426 + stat[k] = LPX_NS;
162.427 + prim[k] = mpq_get_d(ssx->lb[k]);
162.428 + break;
162.429 + default:
162.430 + xassert(ssx != ssx);
162.431 + }
162.432 + dual[k] = mpq_get_d(ssx->cbar[j]);
162.433 + }
162.434 + }
162.435 + /* and store them into the LP object */
162.436 + pst = pst - LPX_P_UNDEF + GLP_UNDEF;
162.437 + dst = dst - LPX_D_UNDEF + GLP_UNDEF;
162.438 + for (k = 1; k <= m+n; k++)
162.439 + stat[k] = stat[k] - LPX_BS + GLP_BS;
162.440 + sum = lpx_get_obj_coef(lp, 0);
162.441 + for (j = 1; j <= n; j++)
162.442 + sum += lpx_get_obj_coef(lp, j) * prim[m+j];
162.443 + lpx_put_solution(lp, 1, &pst, &dst, &sum,
162.444 + &stat[0], &prim[0], &dual[0], &stat[m], &prim[m], &dual[m]);
162.445 + xfree(stat);
162.446 + xfree(prim);
162.447 + xfree(dual);
162.448 +done: /* delete the simplex solver workspace */
162.449 + ssx_delete(ssx);
162.450 + /* return to the application program */
162.451 + return ret;
162.452 +}
162.453 +
162.454 +/* eof */
163.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
163.2 +++ b/src/glpapi08.c Mon Dec 06 13:09:21 2010 +0100
163.3 @@ -0,0 +1,389 @@
163.4 +/* glpapi08.c (interior-point method routines) */
163.5 +
163.6 +/***********************************************************************
163.7 +* This code is part of GLPK (GNU Linear Programming Kit).
163.8 +*
163.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
163.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
163.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
163.12 +* E-mail: <mao@gnu.org>.
163.13 +*
163.14 +* GLPK is free software: you can redistribute it and/or modify it
163.15 +* under the terms of the GNU General Public License as published by
163.16 +* the Free Software Foundation, either version 3 of the License, or
163.17 +* (at your option) any later version.
163.18 +*
163.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
163.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
163.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
163.22 +* License for more details.
163.23 +*
163.24 +* You should have received a copy of the GNU General Public License
163.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
163.26 +***********************************************************************/
163.27 +
163.28 +#include "glpapi.h"
163.29 +#include "glpipm.h"
163.30 +#include "glpnpp.h"
163.31 +
163.32 +/***********************************************************************
163.33 +* NAME
163.34 +*
163.35 +* glp_interior - solve LP problem with the interior-point method
163.36 +*
163.37 +* SYNOPSIS
163.38 +*
163.39 +* int glp_interior(glp_prob *P, const glp_iptcp *parm);
163.40 +*
163.41 +* The routine glp_interior is a driver to the LP solver based on the
163.42 +* interior-point method.
163.43 +*
163.44 +* The interior-point solver has a set of control parameters. Values of
163.45 +* the control parameters can be passed in a structure glp_iptcp, which
163.46 +* the parameter parm points to.
163.47 +*
163.48 +* Currently this routine implements an easy variant of the primal-dual
163.49 +* interior-point method based on Mehrotra's technique.
163.50 +*
163.51 +* This routine transforms the original LP problem to an equivalent LP
163.52 +* problem in the standard formulation (all constraints are equalities,
163.53 +* all variables are non-negative), calls the routine ipm_main to solve
163.54 +* the transformed problem, and then transforms an obtained solution to
163.55 +* the solution of the original problem.
163.56 +*
163.57 +* RETURNS
163.58 +*
163.59 +* 0 The LP problem instance has been successfully solved. This code
163.60 +* does not necessarily mean that the solver has found optimal
163.61 +* solution. It only means that the solution process was successful.
163.62 +*
163.63 +* GLP_EFAIL
163.64 +* The problem has no rows/columns.
163.65 +*
163.66 +* GLP_ENOCVG
163.67 +* Very slow convergence or divergence.
163.68 +*
163.69 +* GLP_EITLIM
163.70 +* Iteration limit exceeded.
163.71 +*
163.72 +* GLP_EINSTAB
163.73 +* Numerical instability on solving Newtonian system. */
163.74 +
163.75 +static void transform(NPP *npp)
163.76 +{ /* transform LP to the standard formulation */
163.77 + NPPROW *row, *prev_row;
163.78 + NPPCOL *col, *prev_col;
163.79 + for (row = npp->r_tail; row != NULL; row = prev_row)
163.80 + { prev_row = row->prev;
163.81 + if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
163.82 + npp_free_row(npp, row);
163.83 + else if (row->lb == -DBL_MAX)
163.84 + npp_leq_row(npp, row);
163.85 + else if (row->ub == +DBL_MAX)
163.86 + npp_geq_row(npp, row);
163.87 + else if (row->lb != row->ub)
163.88 + { if (fabs(row->lb) < fabs(row->ub))
163.89 + npp_geq_row(npp, row);
163.90 + else
163.91 + npp_leq_row(npp, row);
163.92 + }
163.93 + }
163.94 + for (col = npp->c_tail; col != NULL; col = prev_col)
163.95 + { prev_col = col->prev;
163.96 + if (col->lb == -DBL_MAX && col->ub == +DBL_MAX)
163.97 + npp_free_col(npp, col);
163.98 + else if (col->lb == -DBL_MAX)
163.99 + npp_ubnd_col(npp, col);
163.100 + else if (col->ub == +DBL_MAX)
163.101 + { if (col->lb != 0.0)
163.102 + npp_lbnd_col(npp, col);
163.103 + }
163.104 + else if (col->lb != col->ub)
163.105 + { if (fabs(col->lb) < fabs(col->ub))
163.106 + { if (col->lb != 0.0)
163.107 + npp_lbnd_col(npp, col);
163.108 + }
163.109 + else
163.110 + npp_ubnd_col(npp, col);
163.111 + npp_dbnd_col(npp, col);
163.112 + }
163.113 + else
163.114 + npp_fixed_col(npp, col);
163.115 + }
163.116 + for (row = npp->r_head; row != NULL; row = row->next)
163.117 + xassert(row->lb == row->ub);
163.118 + for (col = npp->c_head; col != NULL; col = col->next)
163.119 + xassert(col->lb == 0.0 && col->ub == +DBL_MAX);
163.120 + return;
163.121 +}
163.122 +
163.123 +int glp_interior(glp_prob *P, const glp_iptcp *parm)
163.124 +{ glp_iptcp _parm;
163.125 + GLPROW *row;
163.126 + GLPCOL *col;
163.127 + NPP *npp = NULL;
163.128 + glp_prob *prob = NULL;
163.129 + int i, j, ret;
163.130 + /* check control parameters */
163.131 + if (parm == NULL)
163.132 + glp_init_iptcp(&_parm), parm = &_parm;
163.133 + if (!(parm->msg_lev == GLP_MSG_OFF ||
163.134 + parm->msg_lev == GLP_MSG_ERR ||
163.135 + parm->msg_lev == GLP_MSG_ON ||
163.136 + parm->msg_lev == GLP_MSG_ALL))
163.137 + xerror("glp_interior: msg_lev = %d; invalid parameter\n",
163.138 + parm->msg_lev);
163.139 + if (!(parm->ord_alg == GLP_ORD_NONE ||
163.140 + parm->ord_alg == GLP_ORD_QMD ||
163.141 + parm->ord_alg == GLP_ORD_AMD ||
163.142 + parm->ord_alg == GLP_ORD_SYMAMD))
163.143 + xerror("glp_interior: ord_alg = %d; invalid parameter\n",
163.144 + parm->ord_alg);
163.145 + /* interior-point solution is currently undefined */
163.146 + P->ipt_stat = GLP_UNDEF;
163.147 + P->ipt_obj = 0.0;
163.148 + /* check bounds of double-bounded variables */
163.149 + for (i = 1; i <= P->m; i++)
163.150 + { row = P->row[i];
163.151 + if (row->type == GLP_DB && row->lb >= row->ub)
163.152 + { if (parm->msg_lev >= GLP_MSG_ERR)
163.153 + xprintf("glp_interior: row %d: lb = %g, ub = %g; incorre"
163.154 + "ct bounds\n", i, row->lb, row->ub);
163.155 + ret = GLP_EBOUND;
163.156 + goto done;
163.157 + }
163.158 + }
163.159 + for (j = 1; j <= P->n; j++)
163.160 + { col = P->col[j];
163.161 + if (col->type == GLP_DB && col->lb >= col->ub)
163.162 + { if (parm->msg_lev >= GLP_MSG_ERR)
163.163 + xprintf("glp_interior: column %d: lb = %g, ub = %g; inco"
163.164 + "rrect bounds\n", j, col->lb, col->ub);
163.165 + ret = GLP_EBOUND;
163.166 + goto done;
163.167 + }
163.168 + }
163.169 + /* transform LP to the standard formulation */
163.170 + if (parm->msg_lev >= GLP_MSG_ALL)
163.171 + xprintf("Original LP has %d row(s), %d column(s), and %d non-z"
163.172 + "ero(s)\n", P->m, P->n, P->nnz);
163.173 + npp = npp_create_wksp();
163.174 + npp_load_prob(npp, P, GLP_OFF, GLP_IPT, GLP_ON);
163.175 + transform(npp);
163.176 + prob = glp_create_prob();
163.177 + npp_build_prob(npp, prob);
163.178 + if (parm->msg_lev >= GLP_MSG_ALL)
163.179 + xprintf("Working LP has %d row(s), %d column(s), and %d non-ze"
163.180 + "ro(s)\n", prob->m, prob->n, prob->nnz);
163.181 +#if 1
163.182 + /* currently empty problem cannot be solved */
163.183 + if (!(prob->m > 0 && prob->n > 0))
163.184 + { if (parm->msg_lev >= GLP_MSG_ERR)
163.185 + xprintf("glp_interior: unable to solve empty problem\n");
163.186 + ret = GLP_EFAIL;
163.187 + goto done;
163.188 + }
163.189 +#endif
163.190 + /* scale the resultant LP */
163.191 + { ENV *env = get_env_ptr();
163.192 + int term_out = env->term_out;
163.193 + env->term_out = GLP_OFF;
163.194 + glp_scale_prob(prob, GLP_SF_EQ);
163.195 + env->term_out = term_out;
163.196 + }
163.197 + /* warn about dense columns */
163.198 + if (parm->msg_lev >= GLP_MSG_ON && prob->m >= 200)
163.199 + { int len, cnt = 0;
163.200 + for (j = 1; j <= prob->n; j++)
163.201 + { len = glp_get_mat_col(prob, j, NULL, NULL);
163.202 + if ((double)len >= 0.20 * (double)prob->m) cnt++;
163.203 + }
163.204 + if (cnt == 1)
163.205 + xprintf("WARNING: PROBLEM HAS ONE DENSE COLUMN\n");
163.206 + else if (cnt > 0)
163.207 + xprintf("WARNING: PROBLEM HAS %d DENSE COLUMNS\n", cnt);
163.208 + }
163.209 + /* solve the transformed LP */
163.210 + ret = ipm_solve(prob, parm);
163.211 + /* postprocess solution from the transformed LP */
163.212 + npp_postprocess(npp, prob);
163.213 + /* and store solution to the original LP */
163.214 + npp_unload_sol(npp, P);
163.215 +done: /* free working program objects */
163.216 + if (npp != NULL) npp_delete_wksp(npp);
163.217 + if (prob != NULL) glp_delete_prob(prob);
163.218 + /* return to the application program */
163.219 + return ret;
163.220 +}
163.221 +
163.222 +/***********************************************************************
163.223 +* NAME
163.224 +*
163.225 +* glp_init_iptcp - initialize interior-point solver control parameters
163.226 +*
163.227 +* SYNOPSIS
163.228 +*
163.229 +* void glp_init_iptcp(glp_iptcp *parm);
163.230 +*
163.231 +* DESCRIPTION
163.232 +*
163.233 +* The routine glp_init_iptcp initializes control parameters, which are
163.234 +* used by the interior-point solver, with default values.
163.235 +*
163.236 +* Default values of the control parameters are stored in the glp_iptcp
163.237 +* structure, which the parameter parm points to. */
163.238 +
163.239 +void glp_init_iptcp(glp_iptcp *parm)
163.240 +{ parm->msg_lev = GLP_MSG_ALL;
163.241 + parm->ord_alg = GLP_ORD_AMD;
163.242 + return;
163.243 +}
163.244 +
163.245 +/***********************************************************************
163.246 +* NAME
163.247 +*
163.248 +* glp_ipt_status - retrieve status of interior-point solution
163.249 +*
163.250 +* SYNOPSIS
163.251 +*
163.252 +* int glp_ipt_status(glp_prob *lp);
163.253 +*
163.254 +* RETURNS
163.255 +*
163.256 +* The routine glp_ipt_status reports the status of solution found by
163.257 +* the interior-point solver as follows:
163.258 +*
163.259 +* GLP_UNDEF - interior-point solution is undefined;
163.260 +* GLP_OPT - interior-point solution is optimal;
163.261 +* GLP_INFEAS - interior-point solution is infeasible;
163.262 +* GLP_NOFEAS - no feasible solution exists. */
163.263 +
163.264 +int glp_ipt_status(glp_prob *lp)
163.265 +{ int ipt_stat = lp->ipt_stat;
163.266 + return ipt_stat;
163.267 +}
163.268 +
163.269 +/***********************************************************************
163.270 +* NAME
163.271 +*
163.272 +* glp_ipt_obj_val - retrieve objective value (interior point)
163.273 +*
163.274 +* SYNOPSIS
163.275 +*
163.276 +* double glp_ipt_obj_val(glp_prob *lp);
163.277 +*
163.278 +* RETURNS
163.279 +*
163.280 +* The routine glp_ipt_obj_val returns value of the objective function
163.281 +* for interior-point solution. */
163.282 +
163.283 +double glp_ipt_obj_val(glp_prob *lp)
163.284 +{ /*struct LPXCPS *cps = lp->cps;*/
163.285 + double z;
163.286 + z = lp->ipt_obj;
163.287 + /*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/
163.288 + return z;
163.289 +}
163.290 +
163.291 +/***********************************************************************
163.292 +* NAME
163.293 +*
163.294 +* glp_ipt_row_prim - retrieve row primal value (interior point)
163.295 +*
163.296 +* SYNOPSIS
163.297 +*
163.298 +* double glp_ipt_row_prim(glp_prob *lp, int i);
163.299 +*
163.300 +* RETURNS
163.301 +*
163.302 +* The routine glp_ipt_row_prim returns primal value of the auxiliary
163.303 +* variable associated with i-th row. */
163.304 +
163.305 +double glp_ipt_row_prim(glp_prob *lp, int i)
163.306 +{ /*struct LPXCPS *cps = lp->cps;*/
163.307 + double pval;
163.308 + if (!(1 <= i && i <= lp->m))
163.309 + xerror("glp_ipt_row_prim: i = %d; row number out of range\n",
163.310 + i);
163.311 + pval = lp->row[i]->pval;
163.312 + /*if (cps->round && fabs(pval) < 1e-9) pval = 0.0;*/
163.313 + return pval;
163.314 +}
163.315 +
163.316 +/***********************************************************************
163.317 +* NAME
163.318 +*
163.319 +* glp_ipt_row_dual - retrieve row dual value (interior point)
163.320 +*
163.321 +* SYNOPSIS
163.322 +*
163.323 +* double glp_ipt_row_dual(glp_prob *lp, int i);
163.324 +*
163.325 +* RETURNS
163.326 +*
163.327 +* The routine glp_ipt_row_dual returns dual value (i.e. reduced cost)
163.328 +* of the auxiliary variable associated with i-th row. */
163.329 +
163.330 +double glp_ipt_row_dual(glp_prob *lp, int i)
163.331 +{ /*struct LPXCPS *cps = lp->cps;*/
163.332 + double dval;
163.333 + if (!(1 <= i && i <= lp->m))
163.334 + xerror("glp_ipt_row_dual: i = %d; row number out of range\n",
163.335 + i);
163.336 + dval = lp->row[i]->dval;
163.337 + /*if (cps->round && fabs(dval) < 1e-9) dval = 0.0;*/
163.338 + return dval;
163.339 +}
163.340 +
163.341 +/***********************************************************************
163.342 +* NAME
163.343 +*
163.344 +* glp_ipt_col_prim - retrieve column primal value (interior point)
163.345 +*
163.346 +* SYNOPSIS
163.347 +*
163.348 +* double glp_ipt_col_prim(glp_prob *lp, int j);
163.349 +*
163.350 +* RETURNS
163.351 +*
163.352 +* The routine glp_ipt_col_prim returns primal value of the structural
163.353 +* variable associated with j-th column. */
163.354 +
163.355 +double glp_ipt_col_prim(glp_prob *lp, int j)
163.356 +{ /*struct LPXCPS *cps = lp->cps;*/
163.357 + double pval;
163.358 + if (!(1 <= j && j <= lp->n))
163.359 + xerror("glp_ipt_col_prim: j = %d; column number out of range\n"
163.360 + , j);
163.361 + pval = lp->col[j]->pval;
163.362 + /*if (cps->round && fabs(pval) < 1e-9) pval = 0.0;*/
163.363 + return pval;
163.364 +}
163.365 +
163.366 +/***********************************************************************
163.367 +* NAME
163.368 +*
163.369 +* glp_ipt_col_dual - retrieve column dual value (interior point)
163.370 +*
163.371 +* SYNOPSIS
163.372 +*
163.373 +* #include "glplpx.h"
163.374 +* double glp_ipt_col_dual(glp_prob *lp, int j);
163.375 +*
163.376 +* RETURNS
163.377 +*
163.378 +* The routine glp_ipt_col_dual returns dual value (i.e. reduced cost)
163.379 +* of the structural variable associated with j-th column. */
163.380 +
163.381 +double glp_ipt_col_dual(glp_prob *lp, int j)
163.382 +{ /*struct LPXCPS *cps = lp->cps;*/
163.383 + double dval;
163.384 + if (!(1 <= j && j <= lp->n))
163.385 + xerror("glp_ipt_col_dual: j = %d; column number out of range\n"
163.386 + , j);
163.387 + dval = lp->col[j]->dval;
163.388 + /*if (cps->round && fabs(dval) < 1e-9) dval = 0.0;*/
163.389 + return dval;
163.390 +}
163.391 +
163.392 +/* eof */
164.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
164.2 +++ b/src/glpapi09.c Mon Dec 06 13:09:21 2010 +0100
164.3 @@ -0,0 +1,741 @@
164.4 +/* glpapi09.c (mixed integer programming routines) */
164.5 +
164.6 +/***********************************************************************
164.7 +* This code is part of GLPK (GNU Linear Programming Kit).
164.8 +*
164.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
164.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
164.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
164.12 +* E-mail: <mao@gnu.org>.
164.13 +*
164.14 +* GLPK is free software: you can redistribute it and/or modify it
164.15 +* under the terms of the GNU General Public License as published by
164.16 +* the Free Software Foundation, either version 3 of the License, or
164.17 +* (at your option) any later version.
164.18 +*
164.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
164.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
164.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
164.22 +* License for more details.
164.23 +*
164.24 +* You should have received a copy of the GNU General Public License
164.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
164.26 +***********************************************************************/
164.27 +
164.28 +#include "glpios.h"
164.29 +#include "glpnpp.h"
164.30 +
164.31 +/***********************************************************************
164.32 +* NAME
164.33 +*
164.34 +* glp_set_col_kind - set (change) column kind
164.35 +*
164.36 +* SYNOPSIS
164.37 +*
164.38 +* void glp_set_col_kind(glp_prob *mip, int j, int kind);
164.39 +*
164.40 +* DESCRIPTION
164.41 +*
164.42 +* The routine glp_set_col_kind sets (changes) the kind of j-th column
164.43 +* (structural variable) as specified by the parameter kind:
164.44 +*
164.45 +* GLP_CV - continuous variable;
164.46 +* GLP_IV - integer variable;
164.47 +* GLP_BV - binary variable. */
164.48 +
164.49 +void glp_set_col_kind(glp_prob *mip, int j, int kind)
164.50 +{ GLPCOL *col;
164.51 + if (!(1 <= j && j <= mip->n))
164.52 + xerror("glp_set_col_kind: j = %d; column number out of range\n"
164.53 + , j);
164.54 + col = mip->col[j];
164.55 + switch (kind)
164.56 + { case GLP_CV:
164.57 + col->kind = GLP_CV;
164.58 + break;
164.59 + case GLP_IV:
164.60 + col->kind = GLP_IV;
164.61 + break;
164.62 + case GLP_BV:
164.63 + col->kind = GLP_IV;
164.64 + if (!(col->type == GLP_DB && col->lb == 0.0 && col->ub ==
164.65 + 1.0)) glp_set_col_bnds(mip, j, GLP_DB, 0.0, 1.0);
164.66 + break;
164.67 + default:
164.68 + xerror("glp_set_col_kind: j = %d; kind = %d; invalid column"
164.69 + " kind\n", j, kind);
164.70 + }
164.71 + return;
164.72 +}
164.73 +
164.74 +/***********************************************************************
164.75 +* NAME
164.76 +*
164.77 +* glp_get_col_kind - retrieve column kind
164.78 +*
164.79 +* SYNOPSIS
164.80 +*
164.81 +* int glp_get_col_kind(glp_prob *mip, int j);
164.82 +*
164.83 +* RETURNS
164.84 +*
164.85 +* The routine glp_get_col_kind returns the kind of j-th column, i.e.
164.86 +* the kind of corresponding structural variable, as follows:
164.87 +*
164.88 +* GLP_CV - continuous variable;
164.89 +* GLP_IV - integer variable;
164.90 +* GLP_BV - binary variable */
164.91 +
164.92 +int glp_get_col_kind(glp_prob *mip, int j)
164.93 +{ GLPCOL *col;
164.94 + int kind;
164.95 + if (!(1 <= j && j <= mip->n))
164.96 + xerror("glp_get_col_kind: j = %d; column number out of range\n"
164.97 + , j);
164.98 + col = mip->col[j];
164.99 + kind = col->kind;
164.100 + switch (kind)
164.101 + { case GLP_CV:
164.102 + break;
164.103 + case GLP_IV:
164.104 + if (col->type == GLP_DB && col->lb == 0.0 && col->ub == 1.0)
164.105 + kind = GLP_BV;
164.106 + break;
164.107 + default:
164.108 + xassert(kind != kind);
164.109 + }
164.110 + return kind;
164.111 +}
164.112 +
164.113 +/***********************************************************************
164.114 +* NAME
164.115 +*
164.116 +* glp_get_num_int - retrieve number of integer columns
164.117 +*
164.118 +* SYNOPSIS
164.119 +*
164.120 +* int glp_get_num_int(glp_prob *mip);
164.121 +*
164.122 +* RETURNS
164.123 +*
164.124 +* The routine glp_get_num_int returns the current number of columns,
164.125 +* which are marked as integer. */
164.126 +
164.127 +int glp_get_num_int(glp_prob *mip)
164.128 +{ GLPCOL *col;
164.129 + int j, count = 0;
164.130 + for (j = 1; j <= mip->n; j++)
164.131 + { col = mip->col[j];
164.132 + if (col->kind == GLP_IV) count++;
164.133 + }
164.134 + return count;
164.135 +}
164.136 +
164.137 +/***********************************************************************
164.138 +* NAME
164.139 +*
164.140 +* glp_get_num_bin - retrieve number of binary columns
164.141 +*
164.142 +* SYNOPSIS
164.143 +*
164.144 +* int glp_get_num_bin(glp_prob *mip);
164.145 +*
164.146 +* RETURNS
164.147 +*
164.148 +* The routine glp_get_num_bin returns the current number of columns,
164.149 +* which are marked as binary. */
164.150 +
164.151 +int glp_get_num_bin(glp_prob *mip)
164.152 +{ GLPCOL *col;
164.153 + int j, count = 0;
164.154 + for (j = 1; j <= mip->n; j++)
164.155 + { col = mip->col[j];
164.156 + if (col->kind == GLP_IV && col->type == GLP_DB && col->lb ==
164.157 + 0.0 && col->ub == 1.0) count++;
164.158 + }
164.159 + return count;
164.160 +}
164.161 +
164.162 +/***********************************************************************
164.163 +* NAME
164.164 +*
164.165 +* glp_intopt - solve MIP problem with the branch-and-bound method
164.166 +*
164.167 +* SYNOPSIS
164.168 +*
164.169 +* int glp_intopt(glp_prob *P, const glp_iocp *parm);
164.170 +*
164.171 +* DESCRIPTION
164.172 +*
164.173 +* The routine glp_intopt is a driver to the MIP solver based on the
164.174 +* branch-and-bound method.
164.175 +*
164.176 +* On entry the problem object should contain optimal solution to LP
164.177 +* relaxation (which can be obtained with the routine glp_simplex).
164.178 +*
164.179 +* The MIP solver has a set of control parameters. Values of the control
164.180 +* parameters can be passed in a structure glp_iocp, which the parameter
164.181 +* parm points to.
164.182 +*
164.183 +* The parameter parm can be specified as NULL, in which case the MIP
164.184 +* solver uses default settings.
164.185 +*
164.186 +* RETURNS
164.187 +*
164.188 +* 0 The MIP problem instance has been successfully solved. This code
164.189 +* does not necessarily mean that the solver has found optimal
164.190 +* solution. It only means that the solution process was successful.
164.191 +*
164.192 +* GLP_EBOUND
164.193 +* Unable to start the search, because some double-bounded variables
164.194 +* have incorrect bounds or some integer variables have non-integer
164.195 +* (fractional) bounds.
164.196 +*
164.197 +* GLP_EROOT
164.198 +* Unable to start the search, because optimal basis for initial LP
164.199 +* relaxation is not provided.
164.200 +*
164.201 +* GLP_EFAIL
164.202 +* The search was prematurely terminated due to the solver failure.
164.203 +*
164.204 +* GLP_EMIPGAP
164.205 +* The search was prematurely terminated, because the relative mip
164.206 +* gap tolerance has been reached.
164.207 +*
164.208 +* GLP_ETMLIM
164.209 +* The search was prematurely terminated, because the time limit has
164.210 +* been exceeded.
164.211 +*
164.212 +* GLP_ENOPFS
164.213 +* The MIP problem instance has no primal feasible solution (only if
164.214 +* the MIP presolver is used).
164.215 +*
164.216 +* GLP_ENODFS
164.217 +* LP relaxation of the MIP problem instance has no dual feasible
164.218 +* solution (only if the MIP presolver is used).
164.219 +*
164.220 +* GLP_ESTOP
164.221 +* The search was prematurely terminated by application. */
164.222 +
164.223 +static int solve_mip(glp_prob *P, const glp_iocp *parm)
164.224 +{ /* solve MIP directly without using the preprocessor */
164.225 + glp_tree *T;
164.226 + int ret;
164.227 + /* optimal basis to LP relaxation must be provided */
164.228 + if (glp_get_status(P) != GLP_OPT)
164.229 + { if (parm->msg_lev >= GLP_MSG_ERR)
164.230 + xprintf("glp_intopt: optimal basis to initial LP relaxation"
164.231 + " not provided\n");
164.232 + ret = GLP_EROOT;
164.233 + goto done;
164.234 + }
164.235 + /* it seems all is ok */
164.236 + if (parm->msg_lev >= GLP_MSG_ALL)
164.237 + xprintf("Integer optimization begins...\n");
164.238 + /* create the branch-and-bound tree */
164.239 + T = ios_create_tree(P, parm);
164.240 + /* solve the problem instance */
164.241 + ret = ios_driver(T);
164.242 + /* delete the branch-and-bound tree */
164.243 + ios_delete_tree(T);
164.244 + /* analyze exit code reported by the mip driver */
164.245 + if (ret == 0)
164.246 + { if (P->mip_stat == GLP_FEAS)
164.247 + { if (parm->msg_lev >= GLP_MSG_ALL)
164.248 + xprintf("INTEGER OPTIMAL SOLUTION FOUND\n");
164.249 + P->mip_stat = GLP_OPT;
164.250 + }
164.251 + else
164.252 + { if (parm->msg_lev >= GLP_MSG_ALL)
164.253 + xprintf("PROBLEM HAS NO INTEGER FEASIBLE SOLUTION\n");
164.254 + P->mip_stat = GLP_NOFEAS;
164.255 + }
164.256 + }
164.257 + else if (ret == GLP_EMIPGAP)
164.258 + { if (parm->msg_lev >= GLP_MSG_ALL)
164.259 + xprintf("RELATIVE MIP GAP TOLERANCE REACHED; SEARCH TERMINA"
164.260 + "TED\n");
164.261 + }
164.262 + else if (ret == GLP_ETMLIM)
164.263 + { if (parm->msg_lev >= GLP_MSG_ALL)
164.264 + xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
164.265 + }
164.266 + else if (ret == GLP_EFAIL)
164.267 + { if (parm->msg_lev >= GLP_MSG_ERR)
164.268 + xprintf("glp_intopt: cannot solve current LP relaxation\n");
164.269 + }
164.270 + else if (ret == GLP_ESTOP)
164.271 + { if (parm->msg_lev >= GLP_MSG_ALL)
164.272 + xprintf("SEARCH TERMINATED BY APPLICATION\n");
164.273 + }
164.274 + else
164.275 + xassert(ret != ret);
164.276 +done: return ret;
164.277 +}
164.278 +
164.279 +static int preprocess_and_solve_mip(glp_prob *P, const glp_iocp *parm)
164.280 +{ /* solve MIP using the preprocessor */
164.281 + ENV *env = get_env_ptr();
164.282 + int term_out = env->term_out;
164.283 + NPP *npp;
164.284 + glp_prob *mip = NULL;
164.285 + glp_bfcp bfcp;
164.286 + glp_smcp smcp;
164.287 + int ret;
164.288 + if (parm->msg_lev >= GLP_MSG_ALL)
164.289 + xprintf("Preprocessing...\n");
164.290 + /* create preprocessor workspace */
164.291 + npp = npp_create_wksp();
164.292 + /* load original problem into the preprocessor workspace */
164.293 + npp_load_prob(npp, P, GLP_OFF, GLP_MIP, GLP_OFF);
164.294 + /* process MIP prior to applying the branch-and-bound method */
164.295 + if (!term_out || parm->msg_lev < GLP_MSG_ALL)
164.296 + env->term_out = GLP_OFF;
164.297 + else
164.298 + env->term_out = GLP_ON;
164.299 + ret = npp_integer(npp, parm);
164.300 + env->term_out = term_out;
164.301 + if (ret == 0)
164.302 + ;
164.303 + else if (ret == GLP_ENOPFS)
164.304 + { if (parm->msg_lev >= GLP_MSG_ALL)
164.305 + xprintf("PROBLEM HAS NO PRIMAL FEASIBLE SOLUTION\n");
164.306 + }
164.307 + else if (ret == GLP_ENODFS)
164.308 + { if (parm->msg_lev >= GLP_MSG_ALL)
164.309 + xprintf("LP RELAXATION HAS NO DUAL FEASIBLE SOLUTION\n");
164.310 + }
164.311 + else
164.312 + xassert(ret != ret);
164.313 + if (ret != 0) goto done;
164.314 + /* build transformed MIP */
164.315 + mip = glp_create_prob();
164.316 + npp_build_prob(npp, mip);
164.317 + /* if the transformed MIP is empty, it has empty solution, which
164.318 + is optimal */
164.319 + if (mip->m == 0 && mip->n == 0)
164.320 + { mip->mip_stat = GLP_OPT;
164.321 + mip->mip_obj = mip->c0;
164.322 + if (parm->msg_lev >= GLP_MSG_ALL)
164.323 + { xprintf("Objective value = %17.9e\n", mip->mip_obj);
164.324 + xprintf("INTEGER OPTIMAL SOLUTION FOUND BY MIP PREPROCESSOR"
164.325 + "\n");
164.326 + }
164.327 + goto post;
164.328 + }
164.329 + /* display some statistics */
164.330 + if (parm->msg_lev >= GLP_MSG_ALL)
164.331 + { int ni = glp_get_num_int(mip);
164.332 + int nb = glp_get_num_bin(mip);
164.333 + char s[50];
164.334 + xprintf("%d row%s, %d column%s, %d non-zero%s\n",
164.335 + mip->m, mip->m == 1 ? "" : "s", mip->n, mip->n == 1 ? "" :
164.336 + "s", mip->nnz, mip->nnz == 1 ? "" : "s");
164.337 + if (nb == 0)
164.338 + strcpy(s, "none of");
164.339 + else if (ni == 1 && nb == 1)
164.340 + strcpy(s, "");
164.341 + else if (nb == 1)
164.342 + strcpy(s, "one of");
164.343 + else if (nb == ni)
164.344 + strcpy(s, "all of");
164.345 + else
164.346 + sprintf(s, "%d of", nb);
164.347 + xprintf("%d integer variable%s, %s which %s binary\n",
164.348 + ni, ni == 1 ? "" : "s", s, nb == 1 ? "is" : "are");
164.349 + }
164.350 + /* inherit basis factorization control parameters */
164.351 + glp_get_bfcp(P, &bfcp);
164.352 + glp_set_bfcp(mip, &bfcp);
164.353 + /* scale the transformed problem */
164.354 + if (!term_out || parm->msg_lev < GLP_MSG_ALL)
164.355 + env->term_out = GLP_OFF;
164.356 + else
164.357 + env->term_out = GLP_ON;
164.358 + glp_scale_prob(mip,
164.359 + GLP_SF_GM | GLP_SF_EQ | GLP_SF_2N | GLP_SF_SKIP);
164.360 + env->term_out = term_out;
164.361 + /* build advanced initial basis */
164.362 + if (!term_out || parm->msg_lev < GLP_MSG_ALL)
164.363 + env->term_out = GLP_OFF;
164.364 + else
164.365 + env->term_out = GLP_ON;
164.366 + glp_adv_basis(mip, 0);
164.367 + env->term_out = term_out;
164.368 + /* solve initial LP relaxation */
164.369 + if (parm->msg_lev >= GLP_MSG_ALL)
164.370 + xprintf("Solving LP relaxation...\n");
164.371 + glp_init_smcp(&smcp);
164.372 + smcp.msg_lev = parm->msg_lev;
164.373 + mip->it_cnt = P->it_cnt;
164.374 + ret = glp_simplex(mip, &smcp);
164.375 + P->it_cnt = mip->it_cnt;
164.376 + if (ret != 0)
164.377 + { if (parm->msg_lev >= GLP_MSG_ERR)
164.378 + xprintf("glp_intopt: cannot solve LP relaxation\n");
164.379 + ret = GLP_EFAIL;
164.380 + goto done;
164.381 + }
164.382 + /* check status of the basic solution */
164.383 + ret = glp_get_status(mip);
164.384 + if (ret == GLP_OPT)
164.385 + ret = 0;
164.386 + else if (ret == GLP_NOFEAS)
164.387 + ret = GLP_ENOPFS;
164.388 + else if (ret == GLP_UNBND)
164.389 + ret = GLP_ENODFS;
164.390 + else
164.391 + xassert(ret != ret);
164.392 + if (ret != 0) goto done;
164.393 + /* solve the transformed MIP */
164.394 + mip->it_cnt = P->it_cnt;
164.395 + ret = solve_mip(mip, parm);
164.396 + P->it_cnt = mip->it_cnt;
164.397 + /* only integer feasible solution can be postprocessed */
164.398 + if (!(mip->mip_stat == GLP_OPT || mip->mip_stat == GLP_FEAS))
164.399 + { P->mip_stat = mip->mip_stat;
164.400 + goto done;
164.401 + }
164.402 + /* postprocess solution from the transformed MIP */
164.403 +post: npp_postprocess(npp, mip);
164.404 + /* the transformed MIP is no longer needed */
164.405 + glp_delete_prob(mip), mip = NULL;
164.406 + /* store solution to the original problem */
164.407 + npp_unload_sol(npp, P);
164.408 +done: /* delete the transformed MIP, if it exists */
164.409 + if (mip != NULL) glp_delete_prob(mip);
164.410 + /* delete preprocessor workspace */
164.411 + npp_delete_wksp(npp);
164.412 + return ret;
164.413 +}
164.414 +
164.415 +#ifndef HAVE_ALIEN_SOLVER /* 28/V-2010 */
164.416 +int _glp_intopt1(glp_prob *P, const glp_iocp *parm)
164.417 +{ xassert(P == P);
164.418 + xassert(parm == parm);
164.419 + xprintf("glp_intopt: no alien solver is available\n");
164.420 + return GLP_EFAIL;
164.421 +}
164.422 +#endif
164.423 +
164.424 +int glp_intopt(glp_prob *P, const glp_iocp *parm)
164.425 +{ /* solve MIP problem with the branch-and-bound method */
164.426 + glp_iocp _parm;
164.427 + int i, j, ret;
164.428 + /* check problem object */
164.429 + if (P == NULL || P->magic != GLP_PROB_MAGIC)
164.430 + xerror("glp_intopt: P = %p; invalid problem object\n", P);
164.431 + if (P->tree != NULL)
164.432 + xerror("glp_intopt: operation not allowed\n");
164.433 + /* check control parameters */
164.434 + if (parm == NULL)
164.435 + parm = &_parm, glp_init_iocp((glp_iocp *)parm);
164.436 + if (!(parm->msg_lev == GLP_MSG_OFF ||
164.437 + parm->msg_lev == GLP_MSG_ERR ||
164.438 + parm->msg_lev == GLP_MSG_ON ||
164.439 + parm->msg_lev == GLP_MSG_ALL ||
164.440 + parm->msg_lev == GLP_MSG_DBG))
164.441 + xerror("glp_intopt: msg_lev = %d; invalid parameter\n",
164.442 + parm->msg_lev);
164.443 + if (!(parm->br_tech == GLP_BR_FFV ||
164.444 + parm->br_tech == GLP_BR_LFV ||
164.445 + parm->br_tech == GLP_BR_MFV ||
164.446 + parm->br_tech == GLP_BR_DTH ||
164.447 + parm->br_tech == GLP_BR_PCH))
164.448 + xerror("glp_intopt: br_tech = %d; invalid parameter\n",
164.449 + parm->br_tech);
164.450 + if (!(parm->bt_tech == GLP_BT_DFS ||
164.451 + parm->bt_tech == GLP_BT_BFS ||
164.452 + parm->bt_tech == GLP_BT_BLB ||
164.453 + parm->bt_tech == GLP_BT_BPH))
164.454 + xerror("glp_intopt: bt_tech = %d; invalid parameter\n",
164.455 + parm->bt_tech);
164.456 + if (!(0.0 < parm->tol_int && parm->tol_int < 1.0))
164.457 + xerror("glp_intopt: tol_int = %g; invalid parameter\n",
164.458 + parm->tol_int);
164.459 + if (!(0.0 < parm->tol_obj && parm->tol_obj < 1.0))
164.460 + xerror("glp_intopt: tol_obj = %g; invalid parameter\n",
164.461 + parm->tol_obj);
164.462 + if (parm->tm_lim < 0)
164.463 + xerror("glp_intopt: tm_lim = %d; invalid parameter\n",
164.464 + parm->tm_lim);
164.465 + if (parm->out_frq < 0)
164.466 + xerror("glp_intopt: out_frq = %d; invalid parameter\n",
164.467 + parm->out_frq);
164.468 + if (parm->out_dly < 0)
164.469 + xerror("glp_intopt: out_dly = %d; invalid parameter\n",
164.470 + parm->out_dly);
164.471 + if (!(0 <= parm->cb_size && parm->cb_size <= 256))
164.472 + xerror("glp_intopt: cb_size = %d; invalid parameter\n",
164.473 + parm->cb_size);
164.474 + if (!(parm->pp_tech == GLP_PP_NONE ||
164.475 + parm->pp_tech == GLP_PP_ROOT ||
164.476 + parm->pp_tech == GLP_PP_ALL))
164.477 + xerror("glp_intopt: pp_tech = %d; invalid parameter\n",
164.478 + parm->pp_tech);
164.479 + if (parm->mip_gap < 0.0)
164.480 + xerror("glp_intopt: mip_gap = %g; invalid parameter\n",
164.481 + parm->mip_gap);
164.482 + if (!(parm->mir_cuts == GLP_ON || parm->mir_cuts == GLP_OFF))
164.483 + xerror("glp_intopt: mir_cuts = %d; invalid parameter\n",
164.484 + parm->mir_cuts);
164.485 + if (!(parm->gmi_cuts == GLP_ON || parm->gmi_cuts == GLP_OFF))
164.486 + xerror("glp_intopt: gmi_cuts = %d; invalid parameter\n",
164.487 + parm->gmi_cuts);
164.488 + if (!(parm->cov_cuts == GLP_ON || parm->cov_cuts == GLP_OFF))
164.489 + xerror("glp_intopt: cov_cuts = %d; invalid parameter\n",
164.490 + parm->cov_cuts);
164.491 + if (!(parm->clq_cuts == GLP_ON || parm->clq_cuts == GLP_OFF))
164.492 + xerror("glp_intopt: clq_cuts = %d; invalid parameter\n",
164.493 + parm->clq_cuts);
164.494 + if (!(parm->presolve == GLP_ON || parm->presolve == GLP_OFF))
164.495 + xerror("glp_intopt: presolve = %d; invalid parameter\n",
164.496 + parm->presolve);
164.497 + if (!(parm->binarize == GLP_ON || parm->binarize == GLP_OFF))
164.498 + xerror("glp_intopt: binarize = %d; invalid parameter\n",
164.499 + parm->binarize);
164.500 + if (!(parm->fp_heur == GLP_ON || parm->fp_heur == GLP_OFF))
164.501 + xerror("glp_intopt: fp_heur = %d; invalid parameter\n",
164.502 + parm->fp_heur);
164.503 +#if 1 /* 28/V-2010 */
164.504 + if (!(parm->alien == GLP_ON || parm->alien == GLP_OFF))
164.505 + xerror("glp_intopt: alien = %d; invalid parameter\n",
164.506 + parm->alien);
164.507 +#endif
164.508 + /* integer solution is currently undefined */
164.509 + P->mip_stat = GLP_UNDEF;
164.510 + P->mip_obj = 0.0;
164.511 + /* check bounds of double-bounded variables */
164.512 + for (i = 1; i <= P->m; i++)
164.513 + { GLPROW *row = P->row[i];
164.514 + if (row->type == GLP_DB && row->lb >= row->ub)
164.515 + { if (parm->msg_lev >= GLP_MSG_ERR)
164.516 + xprintf("glp_intopt: row %d: lb = %g, ub = %g; incorrect"
164.517 + " bounds\n", i, row->lb, row->ub);
164.518 + ret = GLP_EBOUND;
164.519 + goto done;
164.520 + }
164.521 + }
164.522 + for (j = 1; j <= P->n; j++)
164.523 + { GLPCOL *col = P->col[j];
164.524 + if (col->type == GLP_DB && col->lb >= col->ub)
164.525 + { if (parm->msg_lev >= GLP_MSG_ERR)
164.526 + xprintf("glp_intopt: column %d: lb = %g, ub = %g; incorr"
164.527 + "ect bounds\n", j, col->lb, col->ub);
164.528 + ret = GLP_EBOUND;
164.529 + goto done;
164.530 + }
164.531 + }
164.532 + /* bounds of all integer variables must be integral */
164.533 + for (j = 1; j <= P->n; j++)
164.534 + { GLPCOL *col = P->col[j];
164.535 + if (col->kind != GLP_IV) continue;
164.536 + if (col->type == GLP_LO || col->type == GLP_DB)
164.537 + { if (col->lb != floor(col->lb))
164.538 + { if (parm->msg_lev >= GLP_MSG_ERR)
164.539 + xprintf("glp_intopt: integer column %d has non-intege"
164.540 + "r lower bound %g\n", j, col->lb);
164.541 + ret = GLP_EBOUND;
164.542 + goto done;
164.543 + }
164.544 + }
164.545 + if (col->type == GLP_UP || col->type == GLP_DB)
164.546 + { if (col->ub != floor(col->ub))
164.547 + { if (parm->msg_lev >= GLP_MSG_ERR)
164.548 + xprintf("glp_intopt: integer column %d has non-intege"
164.549 + "r upper bound %g\n", j, col->ub);
164.550 + ret = GLP_EBOUND;
164.551 + goto done;
164.552 + }
164.553 + }
164.554 + if (col->type == GLP_FX)
164.555 + { if (col->lb != floor(col->lb))
164.556 + { if (parm->msg_lev >= GLP_MSG_ERR)
164.557 + xprintf("glp_intopt: integer column %d has non-intege"
164.558 + "r fixed value %g\n", j, col->lb);
164.559 + ret = GLP_EBOUND;
164.560 + goto done;
164.561 + }
164.562 + }
164.563 + }
164.564 + /* solve MIP problem */
164.565 + if (parm->msg_lev >= GLP_MSG_ALL)
164.566 + { int ni = glp_get_num_int(P);
164.567 + int nb = glp_get_num_bin(P);
164.568 + char s[50];
164.569 + xprintf("GLPK Integer Optimizer, v%s\n", glp_version());
164.570 + xprintf("%d row%s, %d column%s, %d non-zero%s\n",
164.571 + P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
164.572 + P->nnz, P->nnz == 1 ? "" : "s");
164.573 + if (nb == 0)
164.574 + strcpy(s, "none of");
164.575 + else if (ni == 1 && nb == 1)
164.576 + strcpy(s, "");
164.577 + else if (nb == 1)
164.578 + strcpy(s, "one of");
164.579 + else if (nb == ni)
164.580 + strcpy(s, "all of");
164.581 + else
164.582 + sprintf(s, "%d of", nb);
164.583 + xprintf("%d integer variable%s, %s which %s binary\n",
164.584 + ni, ni == 1 ? "" : "s", s, nb == 1 ? "is" : "are");
164.585 + }
164.586 +#if 1 /* 28/V-2010 */
164.587 + if (parm->alien)
164.588 + { /* use alien integer optimizer */
164.589 + ret = _glp_intopt1(P, parm);
164.590 + goto done;
164.591 + }
164.592 +#endif
164.593 + if (!parm->presolve)
164.594 + ret = solve_mip(P, parm);
164.595 + else
164.596 + ret = preprocess_and_solve_mip(P, parm);
164.597 +done: /* return to the application program */
164.598 + return ret;
164.599 +}
164.600 +
164.601 +/***********************************************************************
164.602 +* NAME
164.603 +*
164.604 +* glp_init_iocp - initialize integer optimizer control parameters
164.605 +*
164.606 +* SYNOPSIS
164.607 +*
164.608 +* void glp_init_iocp(glp_iocp *parm);
164.609 +*
164.610 +* DESCRIPTION
164.611 +*
164.612 +* The routine glp_init_iocp initializes control parameters, which are
164.613 +* used by the integer optimizer, with default values.
164.614 +*
164.615 +* Default values of the control parameters are stored in a glp_iocp
164.616 +* structure, which the parameter parm points to. */
164.617 +
164.618 +void glp_init_iocp(glp_iocp *parm)
164.619 +{ parm->msg_lev = GLP_MSG_ALL;
164.620 + parm->br_tech = GLP_BR_DTH;
164.621 + parm->bt_tech = GLP_BT_BLB;
164.622 + parm->tol_int = 1e-5;
164.623 + parm->tol_obj = 1e-7;
164.624 + parm->tm_lim = INT_MAX;
164.625 + parm->out_frq = 5000;
164.626 + parm->out_dly = 10000;
164.627 + parm->cb_func = NULL;
164.628 + parm->cb_info = NULL;
164.629 + parm->cb_size = 0;
164.630 + parm->pp_tech = GLP_PP_ALL;
164.631 + parm->mip_gap = 0.0;
164.632 + parm->mir_cuts = GLP_OFF;
164.633 + parm->gmi_cuts = GLP_OFF;
164.634 + parm->cov_cuts = GLP_OFF;
164.635 + parm->clq_cuts = GLP_OFF;
164.636 + parm->presolve = GLP_OFF;
164.637 + parm->binarize = GLP_OFF;
164.638 + parm->fp_heur = GLP_OFF;
164.639 +#if 1 /* 28/V-2010 */
164.640 + parm->alien = GLP_OFF;
164.641 +#endif
164.642 + return;
164.643 +}
164.644 +
164.645 +/***********************************************************************
164.646 +* NAME
164.647 +*
164.648 +* glp_mip_status - retrieve status of MIP solution
164.649 +*
164.650 +* SYNOPSIS
164.651 +*
164.652 +* int glp_mip_status(glp_prob *mip);
164.653 +*
164.654 +* RETURNS
164.655 +*
164.656 +* The routine lpx_mip_status reports the status of MIP solution found
164.657 +* by the branch-and-bound solver as follows:
164.658 +*
164.659 +* GLP_UNDEF - MIP solution is undefined;
164.660 +* GLP_OPT - MIP solution is integer optimal;
164.661 +* GLP_FEAS - MIP solution is integer feasible but its optimality
164.662 +* (or non-optimality) has not been proven, perhaps due to
164.663 +* premature termination of the search;
164.664 +* GLP_NOFEAS - problem has no integer feasible solution (proven by the
164.665 +* solver). */
164.666 +
164.667 +int glp_mip_status(glp_prob *mip)
164.668 +{ int mip_stat = mip->mip_stat;
164.669 + return mip_stat;
164.670 +}
164.671 +
164.672 +/***********************************************************************
164.673 +* NAME
164.674 +*
164.675 +* glp_mip_obj_val - retrieve objective value (MIP solution)
164.676 +*
164.677 +* SYNOPSIS
164.678 +*
164.679 +* double glp_mip_obj_val(glp_prob *mip);
164.680 +*
164.681 +* RETURNS
164.682 +*
164.683 +* The routine glp_mip_obj_val returns value of the objective function
164.684 +* for MIP solution. */
164.685 +
164.686 +double glp_mip_obj_val(glp_prob *mip)
164.687 +{ /*struct LPXCPS *cps = mip->cps;*/
164.688 + double z;
164.689 + z = mip->mip_obj;
164.690 + /*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/
164.691 + return z;
164.692 +}
164.693 +
164.694 +/***********************************************************************
164.695 +* NAME
164.696 +*
164.697 +* glp_mip_row_val - retrieve row value (MIP solution)
164.698 +*
164.699 +* SYNOPSIS
164.700 +*
164.701 +* double glp_mip_row_val(glp_prob *mip, int i);
164.702 +*
164.703 +* RETURNS
164.704 +*
164.705 +* The routine glp_mip_row_val returns value of the auxiliary variable
164.706 +* associated with i-th row. */
164.707 +
164.708 +double glp_mip_row_val(glp_prob *mip, int i)
164.709 +{ /*struct LPXCPS *cps = mip->cps;*/
164.710 + double mipx;
164.711 + if (!(1 <= i && i <= mip->m))
164.712 + xerror("glp_mip_row_val: i = %d; row number out of range\n", i)
164.713 + ;
164.714 + mipx = mip->row[i]->mipx;
164.715 + /*if (cps->round && fabs(mipx) < 1e-9) mipx = 0.0;*/
164.716 + return mipx;
164.717 +}
164.718 +
164.719 +/***********************************************************************
164.720 +* NAME
164.721 +*
164.722 +* glp_mip_col_val - retrieve column value (MIP solution)
164.723 +*
164.724 +* SYNOPSIS
164.725 +*
164.726 +* double glp_mip_col_val(glp_prob *mip, int j);
164.727 +*
164.728 +* RETURNS
164.729 +*
164.730 +* The routine glp_mip_col_val returns value of the structural variable
164.731 +* associated with j-th column. */
164.732 +
164.733 +double glp_mip_col_val(glp_prob *mip, int j)
164.734 +{ /*struct LPXCPS *cps = mip->cps;*/
164.735 + double mipx;
164.736 + if (!(1 <= j && j <= mip->n))
164.737 + xerror("glp_mip_col_val: j = %d; column number out of range\n",
164.738 + j);
164.739 + mipx = mip->col[j]->mipx;
164.740 + /*if (cps->round && fabs(mipx) < 1e-9) mipx = 0.0;*/
164.741 + return mipx;
164.742 +}
164.743 +
164.744 +/* eof */
165.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
165.2 +++ b/src/glpapi10.c Mon Dec 06 13:09:21 2010 +0100
165.3 @@ -0,0 +1,282 @@
165.4 +/* glpapi10.c (solution checking routines) */
165.5 +
165.6 +/***********************************************************************
165.7 +* This code is part of GLPK (GNU Linear Programming Kit).
165.8 +*
165.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
165.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
165.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
165.12 +* E-mail: <mao@gnu.org>.
165.13 +*
165.14 +* GLPK is free software: you can redistribute it and/or modify it
165.15 +* under the terms of the GNU General Public License as published by
165.16 +* the Free Software Foundation, either version 3 of the License, or
165.17 +* (at your option) any later version.
165.18 +*
165.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
165.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
165.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
165.22 +* License for more details.
165.23 +*
165.24 +* You should have received a copy of the GNU General Public License
165.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
165.26 +***********************************************************************/
165.27 +
165.28 +#include "glpapi.h"
165.29 +
165.30 +void _glp_check_kkt(glp_prob *P, int sol, int cond, double *_ae_max,
165.31 + int *_ae_ind, double *_re_max, int *_re_ind)
165.32 +{ /* check feasibility and optimality conditions */
165.33 + int m = P->m;
165.34 + int n = P->n;
165.35 + GLPROW *row;
165.36 + GLPCOL *col;
165.37 + GLPAIJ *aij;
165.38 + int i, j, ae_ind, re_ind;
165.39 + double e, sp, sn, t, ae_max, re_max;
165.40 + if (!(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP))
165.41 + xerror("glp_check_kkt: sol = %d; invalid solution indicator\n",
165.42 + sol);
165.43 + if (!(cond == GLP_KKT_PE || cond == GLP_KKT_PB ||
165.44 + cond == GLP_KKT_DE || cond == GLP_KKT_DB ||
165.45 + cond == GLP_KKT_CS))
165.46 + xerror("glp_check_kkt: cond = %d; invalid condition indicator "
165.47 + "\n", cond);
165.48 + ae_max = re_max = 0.0;
165.49 + ae_ind = re_ind = 0;
165.50 + if (cond == GLP_KKT_PE)
165.51 + { /* xR - A * xS = 0 */
165.52 + for (i = 1; i <= m; i++)
165.53 + { row = P->row[i];
165.54 + sp = sn = 0.0;
165.55 + /* t := xR[i] */
165.56 + if (sol == GLP_SOL)
165.57 + t = row->prim;
165.58 + else if (sol == GLP_IPT)
165.59 + t = row->pval;
165.60 + else if (sol == GLP_MIP)
165.61 + t = row->mipx;
165.62 + else
165.63 + xassert(sol != sol);
165.64 + if (t >= 0.0) sp += t; else sn -= t;
165.65 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
165.66 + { col = aij->col;
165.67 + /* t := - a[i,j] * xS[j] */
165.68 + if (sol == GLP_SOL)
165.69 + t = - aij->val * col->prim;
165.70 + else if (sol == GLP_IPT)
165.71 + t = - aij->val * col->pval;
165.72 + else if (sol == GLP_MIP)
165.73 + t = - aij->val * col->mipx;
165.74 + else
165.75 + xassert(sol != sol);
165.76 + if (t >= 0.0) sp += t; else sn -= t;
165.77 + }
165.78 + /* absolute error */
165.79 + e = fabs(sp - sn);
165.80 + if (ae_max < e)
165.81 + ae_max = e, ae_ind = i;
165.82 + /* relative error */
165.83 + e /= (1.0 + sp + sn);
165.84 + if (re_max < e)
165.85 + re_max = e, re_ind = i;
165.86 + }
165.87 + }
165.88 + else if (cond == GLP_KKT_PB)
165.89 + { /* lR <= xR <= uR */
165.90 + for (i = 1; i <= m; i++)
165.91 + { row = P->row[i];
165.92 + /* t := xR[i] */
165.93 + if (sol == GLP_SOL)
165.94 + t = row->prim;
165.95 + else if (sol == GLP_IPT)
165.96 + t = row->pval;
165.97 + else if (sol == GLP_MIP)
165.98 + t = row->mipx;
165.99 + else
165.100 + xassert(sol != sol);
165.101 + /* check lower bound */
165.102 + if (row->type == GLP_LO || row->type == GLP_DB ||
165.103 + row->type == GLP_FX)
165.104 + { if (t < row->lb)
165.105 + { /* absolute error */
165.106 + e = row->lb - t;
165.107 + if (ae_max < e)
165.108 + ae_max = e, ae_ind = i;
165.109 + /* relative error */
165.110 + e /= (1.0 + fabs(row->lb));
165.111 + if (re_max < e)
165.112 + re_max = e, re_ind = i;
165.113 + }
165.114 + }
165.115 + /* check upper bound */
165.116 + if (row->type == GLP_UP || row->type == GLP_DB ||
165.117 + row->type == GLP_FX)
165.118 + { if (t > row->ub)
165.119 + { /* absolute error */
165.120 + e = t - row->ub;
165.121 + if (ae_max < e)
165.122 + ae_max = e, ae_ind = i;
165.123 + /* relative error */
165.124 + e /= (1.0 + fabs(row->ub));
165.125 + if (re_max < e)
165.126 + re_max = e, re_ind = i;
165.127 + }
165.128 + }
165.129 + }
165.130 + /* lS <= xS <= uS */
165.131 + for (j = 1; j <= n; j++)
165.132 + { col = P->col[j];
165.133 + /* t := xS[j] */
165.134 + if (sol == GLP_SOL)
165.135 + t = col->prim;
165.136 + else if (sol == GLP_IPT)
165.137 + t = col->pval;
165.138 + else if (sol == GLP_MIP)
165.139 + t = col->mipx;
165.140 + else
165.141 + xassert(sol != sol);
165.142 + /* check lower bound */
165.143 + if (col->type == GLP_LO || col->type == GLP_DB ||
165.144 + col->type == GLP_FX)
165.145 + { if (t < col->lb)
165.146 + { /* absolute error */
165.147 + e = col->lb - t;
165.148 + if (ae_max < e)
165.149 + ae_max = e, ae_ind = m+j;
165.150 + /* relative error */
165.151 + e /= (1.0 + fabs(col->lb));
165.152 + if (re_max < e)
165.153 + re_max = e, re_ind = m+j;
165.154 + }
165.155 + }
165.156 + /* check upper bound */
165.157 + if (col->type == GLP_UP || col->type == GLP_DB ||
165.158 + col->type == GLP_FX)
165.159 + { if (t > col->ub)
165.160 + { /* absolute error */
165.161 + e = t - col->ub;
165.162 + if (ae_max < e)
165.163 + ae_max = e, ae_ind = m+j;
165.164 + /* relative error */
165.165 + e /= (1.0 + fabs(col->ub));
165.166 + if (re_max < e)
165.167 + re_max = e, re_ind = m+j;
165.168 + }
165.169 + }
165.170 + }
165.171 + }
165.172 + else if (cond == GLP_KKT_DE)
165.173 + { /* A' * (lambdaR - cR) + (lambdaS - cS) = 0 */
165.174 + for (j = 1; j <= n; j++)
165.175 + { col = P->col[j];
165.176 + sp = sn = 0.0;
165.177 + /* t := lambdaS[j] - cS[j] */
165.178 + if (sol == GLP_SOL)
165.179 + t = col->dual - col->coef;
165.180 + else if (sol == GLP_IPT)
165.181 + t = col->dval - col->coef;
165.182 + else
165.183 + xassert(sol != sol);
165.184 + if (t >= 0.0) sp += t; else sn -= t;
165.185 + for (aij = col->ptr; aij != NULL; aij = aij->c_next)
165.186 + { row = aij->row;
165.187 + /* t := a[i,j] * (lambdaR[i] - cR[i]) */
165.188 + if (sol == GLP_SOL)
165.189 + t = aij->val * row->dual;
165.190 + else if (sol == GLP_IPT)
165.191 + t = aij->val * row->dval;
165.192 + else
165.193 + xassert(sol != sol);
165.194 + if (t >= 0.0) sp += t; else sn -= t;
165.195 + }
165.196 + /* absolute error */
165.197 + e = fabs(sp - sn);
165.198 + if (ae_max < e)
165.199 + ae_max = e, ae_ind = m+j;
165.200 + /* relative error */
165.201 + e /= (1.0 + sp + sn);
165.202 + if (re_max < e)
165.203 + re_max = e, re_ind = m+j;
165.204 + }
165.205 + }
165.206 + else if (cond == GLP_KKT_DB)
165.207 + { /* check lambdaR */
165.208 + for (i = 1; i <= m; i++)
165.209 + { row = P->row[i];
165.210 + /* t := lambdaR[i] */
165.211 + if (sol == GLP_SOL)
165.212 + t = row->dual;
165.213 + else if (sol == GLP_IPT)
165.214 + t = row->dval;
165.215 + else
165.216 + xassert(sol != sol);
165.217 + /* correct sign */
165.218 + if (P->dir == GLP_MIN)
165.219 + t = + t;
165.220 + else if (P->dir == GLP_MAX)
165.221 + t = - t;
165.222 + else
165.223 + xassert(P != P);
165.224 + /* check for positivity */
165.225 + if (row->type == GLP_FR || row->type == GLP_LO)
165.226 + { if (t < 0.0)
165.227 + { e = - t;
165.228 + if (ae_max < e)
165.229 + ae_max = re_max = e, ae_ind = re_ind = i;
165.230 + }
165.231 + }
165.232 + /* check for negativity */
165.233 + if (row->type == GLP_FR || row->type == GLP_UP)
165.234 + { if (t > 0.0)
165.235 + { e = + t;
165.236 + if (ae_max < e)
165.237 + ae_max = re_max = e, ae_ind = re_ind = i;
165.238 + }
165.239 + }
165.240 + }
165.241 + /* check lambdaS */
165.242 + for (j = 1; j <= n; j++)
165.243 + { col = P->col[j];
165.244 + /* t := lambdaS[j] */
165.245 + if (sol == GLP_SOL)
165.246 + t = col->dual;
165.247 + else if (sol == GLP_IPT)
165.248 + t = col->dval;
165.249 + else
165.250 + xassert(sol != sol);
165.251 + /* correct sign */
165.252 + if (P->dir == GLP_MIN)
165.253 + t = + t;
165.254 + else if (P->dir == GLP_MAX)
165.255 + t = - t;
165.256 + else
165.257 + xassert(P != P);
165.258 + /* check for positivity */
165.259 + if (col->type == GLP_FR || col->type == GLP_LO)
165.260 + { if (t < 0.0)
165.261 + { e = - t;
165.262 + if (ae_max < e)
165.263 + ae_max = re_max = e, ae_ind = re_ind = m+j;
165.264 + }
165.265 + }
165.266 + /* check for negativity */
165.267 + if (col->type == GLP_FR || col->type == GLP_UP)
165.268 + { if (t > 0.0)
165.269 + { e = + t;
165.270 + if (ae_max < e)
165.271 + ae_max = re_max = e, ae_ind = re_ind = m+j;
165.272 + }
165.273 + }
165.274 + }
165.275 + }
165.276 + else
165.277 + xassert(cond != cond);
165.278 + if (_ae_max != NULL) *_ae_max = ae_max;
165.279 + if (_ae_ind != NULL) *_ae_ind = ae_ind;
165.280 + if (_re_max != NULL) *_re_max = re_max;
165.281 + if (_re_ind != NULL) *_re_ind = re_ind;
165.282 + return;
165.283 +}
165.284 +
165.285 +/* eof */
166.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
166.2 +++ b/src/glpapi11.c Mon Dec 06 13:09:21 2010 +0100
166.3 @@ -0,0 +1,1217 @@
166.4 +/* glpapi11.c (utility routines) */
166.5 +
166.6 +/***********************************************************************
166.7 +* This code is part of GLPK (GNU Linear Programming Kit).
166.8 +*
166.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
166.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
166.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
166.12 +* E-mail: <mao@gnu.org>.
166.13 +*
166.14 +* GLPK is free software: you can redistribute it and/or modify it
166.15 +* under the terms of the GNU General Public License as published by
166.16 +* the Free Software Foundation, either version 3 of the License, or
166.17 +* (at your option) any later version.
166.18 +*
166.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
166.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
166.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
166.22 +* License for more details.
166.23 +*
166.24 +* You should have received a copy of the GNU General Public License
166.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
166.26 +***********************************************************************/
166.27 +
166.28 +#include "glpapi.h"
166.29 +
166.30 +int glp_print_sol(glp_prob *P, const char *fname)
166.31 +{ /* write basic solution in printable format */
166.32 + XFILE *fp;
166.33 + GLPROW *row;
166.34 + GLPCOL *col;
166.35 + int i, j, t, ae_ind, re_ind, ret;
166.36 + double ae_max, re_max;
166.37 + xprintf("Writing basic solution to `%s'...\n", fname);
166.38 + fp = xfopen(fname, "w");
166.39 + if (fp == NULL)
166.40 + { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
166.41 + ret = 1;
166.42 + goto done;
166.43 + }
166.44 + xfprintf(fp, "%-12s%s\n", "Problem:",
166.45 + P->name == NULL ? "" : P->name);
166.46 + xfprintf(fp, "%-12s%d\n", "Rows:", P->m);
166.47 + xfprintf(fp, "%-12s%d\n", "Columns:", P->n);
166.48 + xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz);
166.49 + t = glp_get_status(P);
166.50 + xfprintf(fp, "%-12s%s\n", "Status:",
166.51 + t == GLP_OPT ? "OPTIMAL" :
166.52 + t == GLP_FEAS ? "FEASIBLE" :
166.53 + t == GLP_INFEAS ? "INFEASIBLE (INTERMEDIATE)" :
166.54 + t == GLP_NOFEAS ? "INFEASIBLE (FINAL)" :
166.55 + t == GLP_UNBND ? "UNBOUNDED" :
166.56 + t == GLP_UNDEF ? "UNDEFINED" : "???");
166.57 + xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
166.58 + P->obj == NULL ? "" : P->obj,
166.59 + P->obj == NULL ? "" : " = ", P->obj_val,
166.60 + P->dir == GLP_MIN ? "MINimum" :
166.61 + P->dir == GLP_MAX ? "MAXimum" : "???");
166.62 + xfprintf(fp, "\n");
166.63 + xfprintf(fp, " No. Row name St Activity Lower bound "
166.64 + " Upper bound Marginal\n");
166.65 + xfprintf(fp, "------ ------------ -- ------------- ------------- "
166.66 + "------------- -------------\n");
166.67 + for (i = 1; i <= P->m; i++)
166.68 + { row = P->row[i];
166.69 + xfprintf(fp, "%6d ", i);
166.70 + if (row->name == NULL || strlen(row->name) <= 12)
166.71 + xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
166.72 + else
166.73 + xfprintf(fp, "%s\n%20s", row->name, "");
166.74 + xfprintf(fp, "%s ",
166.75 + row->stat == GLP_BS ? "B " :
166.76 + row->stat == GLP_NL ? "NL" :
166.77 + row->stat == GLP_NU ? "NU" :
166.78 + row->stat == GLP_NF ? "NF" :
166.79 + row->stat == GLP_NS ? "NS" : "??");
166.80 + xfprintf(fp, "%13.6g ",
166.81 + fabs(row->prim) <= 1e-9 ? 0.0 : row->prim);
166.82 + if (row->type == GLP_LO || row->type == GLP_DB ||
166.83 + row->type == GLP_FX)
166.84 + xfprintf(fp, "%13.6g ", row->lb);
166.85 + else
166.86 + xfprintf(fp, "%13s ", "");
166.87 + if (row->type == GLP_UP || row->type == GLP_DB)
166.88 + xfprintf(fp, "%13.6g ", row->ub);
166.89 + else
166.90 + xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
166.91 + if (row->stat != GLP_BS)
166.92 + { if (fabs(row->dual) <= 1e-9)
166.93 + xfprintf(fp, "%13s", "< eps");
166.94 + else
166.95 + xfprintf(fp, "%13.6g ", row->dual);
166.96 + }
166.97 + xfprintf(fp, "\n");
166.98 + }
166.99 + xfprintf(fp, "\n");
166.100 + xfprintf(fp, " No. Column name St Activity Lower bound "
166.101 + " Upper bound Marginal\n");
166.102 + xfprintf(fp, "------ ------------ -- ------------- ------------- "
166.103 + "------------- -------------\n");
166.104 + for (j = 1; j <= P->n; j++)
166.105 + { col = P->col[j];
166.106 + xfprintf(fp, "%6d ", j);
166.107 + if (col->name == NULL || strlen(col->name) <= 12)
166.108 + xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
166.109 + else
166.110 + xfprintf(fp, "%s\n%20s", col->name, "");
166.111 + xfprintf(fp, "%s ",
166.112 + col->stat == GLP_BS ? "B " :
166.113 + col->stat == GLP_NL ? "NL" :
166.114 + col->stat == GLP_NU ? "NU" :
166.115 + col->stat == GLP_NF ? "NF" :
166.116 + col->stat == GLP_NS ? "NS" : "??");
166.117 + xfprintf(fp, "%13.6g ",
166.118 + fabs(col->prim) <= 1e-9 ? 0.0 : col->prim);
166.119 + if (col->type == GLP_LO || col->type == GLP_DB ||
166.120 + col->type == GLP_FX)
166.121 + xfprintf(fp, "%13.6g ", col->lb);
166.122 + else
166.123 + xfprintf(fp, "%13s ", "");
166.124 + if (col->type == GLP_UP || col->type == GLP_DB)
166.125 + xfprintf(fp, "%13.6g ", col->ub);
166.126 + else
166.127 + xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
166.128 + if (col->stat != GLP_BS)
166.129 + { if (fabs(col->dual) <= 1e-9)
166.130 + xfprintf(fp, "%13s", "< eps");
166.131 + else
166.132 + xfprintf(fp, "%13.6g ", col->dual);
166.133 + }
166.134 + xfprintf(fp, "\n");
166.135 + }
166.136 + xfprintf(fp, "\n");
166.137 + xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n");
166.138 + xfprintf(fp, "\n");
166.139 + _glp_check_kkt(P, GLP_SOL, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
166.140 + &re_ind);
166.141 + xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
166.142 + ae_max, ae_ind);
166.143 + xfprintf(fp, " max.rel.err = %.2e on row %d\n",
166.144 + re_max, re_ind);
166.145 + xfprintf(fp, "%8s%s\n", "",
166.146 + re_max <= 1e-9 ? "High quality" :
166.147 + re_max <= 1e-6 ? "Medium quality" :
166.148 + re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS WRONG");
166.149 + xfprintf(fp, "\n");
166.150 + _glp_check_kkt(P, GLP_SOL, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
166.151 + &re_ind);
166.152 + xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n",
166.153 + ae_max, ae_ind <= P->m ? "row" : "column",
166.154 + ae_ind <= P->m ? ae_ind : ae_ind - P->m);
166.155 + xfprintf(fp, " max.rel.err = %.2e on %s %d\n",
166.156 + re_max, re_ind <= P->m ? "row" : "column",
166.157 + re_ind <= P->m ? re_ind : re_ind - P->m);
166.158 + xfprintf(fp, "%8s%s\n", "",
166.159 + re_max <= 1e-9 ? "High quality" :
166.160 + re_max <= 1e-6 ? "Medium quality" :
166.161 + re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS INFEASIBL"
166.162 + "E");
166.163 + xfprintf(fp, "\n");
166.164 + _glp_check_kkt(P, GLP_SOL, GLP_KKT_DE, &ae_max, &ae_ind, &re_max,
166.165 + &re_ind);
166.166 + xfprintf(fp, "KKT.DE: max.abs.err = %.2e on column %d\n",
166.167 + ae_max, ae_ind == 0 ? 0 : ae_ind - P->m);
166.168 + xfprintf(fp, " max.rel.err = %.2e on column %d\n",
166.169 + re_max, re_ind == 0 ? 0 : re_ind - P->m);
166.170 + xfprintf(fp, "%8s%s\n", "",
166.171 + re_max <= 1e-9 ? "High quality" :
166.172 + re_max <= 1e-6 ? "Medium quality" :
166.173 + re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS WRONG");
166.174 + xfprintf(fp, "\n");
166.175 + _glp_check_kkt(P, GLP_SOL, GLP_KKT_DB, &ae_max, &ae_ind, &re_max,
166.176 + &re_ind);
166.177 + xfprintf(fp, "KKT.DB: max.abs.err = %.2e on %s %d\n",
166.178 + ae_max, ae_ind <= P->m ? "row" : "column",
166.179 + ae_ind <= P->m ? ae_ind : ae_ind - P->m);
166.180 + xfprintf(fp, " max.rel.err = %.2e on %s %d\n",
166.181 + re_max, re_ind <= P->m ? "row" : "column",
166.182 + re_ind <= P->m ? re_ind : re_ind - P->m);
166.183 + xfprintf(fp, "%8s%s\n", "",
166.184 + re_max <= 1e-9 ? "High quality" :
166.185 + re_max <= 1e-6 ? "Medium quality" :
166.186 + re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS INFEASIBLE")
166.187 + ;
166.188 + xfprintf(fp, "\n");
166.189 + xfprintf(fp, "End of output\n");
166.190 + xfflush(fp);
166.191 + if (xferror(fp))
166.192 + { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
166.193 + ret = 1;
166.194 + goto done;
166.195 + }
166.196 + ret = 0;
166.197 +done: if (fp != NULL) xfclose(fp);
166.198 + return ret;
166.199 +}
166.200 +
166.201 +/***********************************************************************
166.202 +* NAME
166.203 +*
166.204 +* glp_read_sol - read basic solution from text file
166.205 +*
166.206 +* SYNOPSIS
166.207 +*
166.208 +* int glp_read_sol(glp_prob *lp, const char *fname);
166.209 +*
166.210 +* DESCRIPTION
166.211 +*
166.212 +* The routine glp_read_sol reads basic solution from a text file whose
166.213 +* name is specified by the parameter fname into the problem object.
166.214 +*
166.215 +* For the file format see description of the routine glp_write_sol.
166.216 +*
166.217 +* RETURNS
166.218 +*
166.219 +* On success the routine returns zero, otherwise non-zero. */
166.220 +
166.221 +int glp_read_sol(glp_prob *lp, const char *fname)
166.222 +{ glp_data *data;
166.223 + jmp_buf jump;
166.224 + int i, j, k, ret = 0;
166.225 + xprintf("Reading basic solution from `%s'...\n", fname);
166.226 + data = glp_sdf_open_file(fname);
166.227 + if (data == NULL)
166.228 + { ret = 1;
166.229 + goto done;
166.230 + }
166.231 + if (setjmp(jump))
166.232 + { ret = 1;
166.233 + goto done;
166.234 + }
166.235 + glp_sdf_set_jump(data, jump);
166.236 + /* number of rows, number of columns */
166.237 + k = glp_sdf_read_int(data);
166.238 + if (k != lp->m)
166.239 + glp_sdf_error(data, "wrong number of rows\n");
166.240 + k = glp_sdf_read_int(data);
166.241 + if (k != lp->n)
166.242 + glp_sdf_error(data, "wrong number of columns\n");
166.243 + /* primal status, dual status, objective value */
166.244 + k = glp_sdf_read_int(data);
166.245 + if (!(k == GLP_UNDEF || k == GLP_FEAS || k == GLP_INFEAS ||
166.246 + k == GLP_NOFEAS))
166.247 + glp_sdf_error(data, "invalid primal status\n");
166.248 + lp->pbs_stat = k;
166.249 + k = glp_sdf_read_int(data);
166.250 + if (!(k == GLP_UNDEF || k == GLP_FEAS || k == GLP_INFEAS ||
166.251 + k == GLP_NOFEAS))
166.252 + glp_sdf_error(data, "invalid dual status\n");
166.253 + lp->dbs_stat = k;
166.254 + lp->obj_val = glp_sdf_read_num(data);
166.255 + /* rows (auxiliary variables) */
166.256 + for (i = 1; i <= lp->m; i++)
166.257 + { GLPROW *row = lp->row[i];
166.258 + /* status, primal value, dual value */
166.259 + k = glp_sdf_read_int(data);
166.260 + if (!(k == GLP_BS || k == GLP_NL || k == GLP_NU ||
166.261 + k == GLP_NF || k == GLP_NS))
166.262 + glp_sdf_error(data, "invalid row status\n");
166.263 + glp_set_row_stat(lp, i, k);
166.264 + row->prim = glp_sdf_read_num(data);
166.265 + row->dual = glp_sdf_read_num(data);
166.266 + }
166.267 + /* columns (structural variables) */
166.268 + for (j = 1; j <= lp->n; j++)
166.269 + { GLPCOL *col = lp->col[j];
166.270 + /* status, primal value, dual value */
166.271 + k = glp_sdf_read_int(data);
166.272 + if (!(k == GLP_BS || k == GLP_NL || k == GLP_NU ||
166.273 + k == GLP_NF || k == GLP_NS))
166.274 + glp_sdf_error(data, "invalid column status\n");
166.275 + glp_set_col_stat(lp, j, k);
166.276 + col->prim = glp_sdf_read_num(data);
166.277 + col->dual = glp_sdf_read_num(data);
166.278 + }
166.279 + xprintf("%d lines were read\n", glp_sdf_line(data));
166.280 +done: if (ret) lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
166.281 + if (data != NULL) glp_sdf_close_file(data);
166.282 + return ret;
166.283 +}
166.284 +
166.285 +/***********************************************************************
166.286 +* NAME
166.287 +*
166.288 +* glp_write_sol - write basic solution to text file
166.289 +*
166.290 +* SYNOPSIS
166.291 +*
166.292 +* int glp_write_sol(glp_prob *lp, const char *fname);
166.293 +*
166.294 +* DESCRIPTION
166.295 +*
166.296 +* The routine glp_write_sol writes the current basic solution to a
166.297 +* text file whose name is specified by the parameter fname. This file
166.298 +* can be read back with the routine glp_read_sol.
166.299 +*
166.300 +* RETURNS
166.301 +*
166.302 +* On success the routine returns zero, otherwise non-zero.
166.303 +*
166.304 +* FILE FORMAT
166.305 +*
166.306 +* The file created by the routine glp_write_sol is a plain text file,
166.307 +* which contains the following information:
166.308 +*
166.309 +* m n
166.310 +* p_stat d_stat obj_val
166.311 +* r_stat[1] r_prim[1] r_dual[1]
166.312 +* . . .
166.313 +* r_stat[m] r_prim[m] r_dual[m]
166.314 +* c_stat[1] c_prim[1] c_dual[1]
166.315 +* . . .
166.316 +* c_stat[n] c_prim[n] c_dual[n]
166.317 +*
166.318 +* where:
166.319 +* m is the number of rows (auxiliary variables);
166.320 +* n is the number of columns (structural variables);
166.321 +* p_stat is the primal status of the basic solution (GLP_UNDEF = 1,
166.322 +* GLP_FEAS = 2, GLP_INFEAS = 3, or GLP_NOFEAS = 4);
166.323 +* d_stat is the dual status of the basic solution (GLP_UNDEF = 1,
166.324 +* GLP_FEAS = 2, GLP_INFEAS = 3, or GLP_NOFEAS = 4);
166.325 +* obj_val is the objective value;
166.326 +* r_stat[i], i = 1,...,m, is the status of i-th row (GLP_BS = 1,
166.327 +* GLP_NL = 2, GLP_NU = 3, GLP_NF = 4, or GLP_NS = 5);
166.328 +* r_prim[i], i = 1,...,m, is the primal value of i-th row;
166.329 +* r_dual[i], i = 1,...,m, is the dual value of i-th row;
166.330 +* c_stat[j], j = 1,...,n, is the status of j-th column (GLP_BS = 1,
166.331 +* GLP_NL = 2, GLP_NU = 3, GLP_NF = 4, or GLP_NS = 5);
166.332 +* c_prim[j], j = 1,...,n, is the primal value of j-th column;
166.333 +* c_dual[j], j = 1,...,n, is the dual value of j-th column. */
166.334 +
166.335 +int glp_write_sol(glp_prob *lp, const char *fname)
166.336 +{ XFILE *fp;
166.337 + int i, j, ret = 0;
166.338 + xprintf("Writing basic solution to `%s'...\n", fname);
166.339 + fp = xfopen(fname, "w");
166.340 + if (fp == NULL)
166.341 + { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
166.342 + ret = 1;
166.343 + goto done;
166.344 + }
166.345 + /* number of rows, number of columns */
166.346 + xfprintf(fp, "%d %d\n", lp->m, lp->n);
166.347 + /* primal status, dual status, objective value */
166.348 + xfprintf(fp, "%d %d %.*g\n", lp->pbs_stat, lp->dbs_stat, DBL_DIG,
166.349 + lp->obj_val);
166.350 + /* rows (auxiliary variables) */
166.351 + for (i = 1; i <= lp->m; i++)
166.352 + { GLPROW *row = lp->row[i];
166.353 + /* status, primal value, dual value */
166.354 + xfprintf(fp, "%d %.*g %.*g\n", row->stat, DBL_DIG, row->prim,
166.355 + DBL_DIG, row->dual);
166.356 + }
166.357 + /* columns (structural variables) */
166.358 + for (j = 1; j <= lp->n; j++)
166.359 + { GLPCOL *col = lp->col[j];
166.360 + /* status, primal value, dual value */
166.361 + xfprintf(fp, "%d %.*g %.*g\n", col->stat, DBL_DIG, col->prim,
166.362 + DBL_DIG, col->dual);
166.363 + }
166.364 + xfflush(fp);
166.365 + if (xferror(fp))
166.366 + { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
166.367 + ret = 1;
166.368 + goto done;
166.369 + }
166.370 + xprintf("%d lines were written\n", 2 + lp->m + lp->n);
166.371 +done: if (fp != NULL) xfclose(fp);
166.372 + return ret;
166.373 +}
166.374 +
166.375 +/**********************************************************************/
166.376 +
166.377 +static char *format(char buf[13+1], double x)
166.378 +{ /* format floating-point number in MPS/360-like style */
166.379 + if (x == -DBL_MAX)
166.380 + strcpy(buf, " -Inf");
166.381 + else if (x == +DBL_MAX)
166.382 + strcpy(buf, " +Inf");
166.383 + else if (fabs(x) <= 999999.99998)
166.384 + { sprintf(buf, "%13.5f", x);
166.385 +#if 1
166.386 + if (strcmp(buf, " 0.00000") == 0 ||
166.387 + strcmp(buf, " -0.00000") == 0)
166.388 + strcpy(buf, " . ");
166.389 + else if (memcmp(buf, " 0.", 8) == 0)
166.390 + memcpy(buf, " .", 8);
166.391 + else if (memcmp(buf, " -0.", 8) == 0)
166.392 + memcpy(buf, " -.", 8);
166.393 +#endif
166.394 + }
166.395 + else
166.396 + sprintf(buf, "%13.6g", x);
166.397 + return buf;
166.398 +}
166.399 +
166.400 +int glp_print_ranges(glp_prob *P, int len, const int list[],
166.401 + int flags, const char *fname)
166.402 +{ /* print sensitivity analysis report */
166.403 + XFILE *fp = NULL;
166.404 + GLPROW *row;
166.405 + GLPCOL *col;
166.406 + int m, n, pass, k, t, numb, type, stat, var1, var2, count, page,
166.407 + ret;
166.408 + double lb, ub, slack, coef, prim, dual, value1, value2, coef1,
166.409 + coef2, obj1, obj2;
166.410 + const char *name, *limit;
166.411 + char buf[13+1];
166.412 + /* sanity checks */
166.413 + if (P == NULL || P->magic != GLP_PROB_MAGIC)
166.414 + xerror("glp_print_ranges: P = %p; invalid problem object\n",
166.415 + P);
166.416 + m = P->m, n = P->n;
166.417 + if (len < 0)
166.418 + xerror("glp_print_ranges: len = %d; invalid list length\n",
166.419 + len);
166.420 + if (len > 0)
166.421 + { if (list == NULL)
166.422 + xerror("glp_print_ranges: list = %p: invalid parameter\n",
166.423 + list);
166.424 + for (t = 1; t <= len; t++)
166.425 + { k = list[t];
166.426 + if (!(1 <= k && k <= m+n))
166.427 + xerror("glp_print_ranges: list[%d] = %d; row/column numb"
166.428 + "er out of range\n", t, k);
166.429 + }
166.430 + }
166.431 + if (flags != 0)
166.432 + xerror("glp_print_ranges: flags = %d; invalid parameter\n",
166.433 + flags);
166.434 + if (fname == NULL)
166.435 + xerror("glp_print_ranges: fname = %p; invalid parameter\n",
166.436 + fname);
166.437 + if (glp_get_status(P) != GLP_OPT)
166.438 + { xprintf("glp_print_ranges: optimal basic solution required\n");
166.439 + ret = 1;
166.440 + goto done;
166.441 + }
166.442 + if (!glp_bf_exists(P))
166.443 + { xprintf("glp_print_ranges: basis factorization required\n");
166.444 + ret = 2;
166.445 + goto done;
166.446 + }
166.447 + /* start reporting */
166.448 + xprintf("Write sensitivity analysis report to `%s'...\n", fname);
166.449 + fp = xfopen(fname, "w");
166.450 + if (fp == NULL)
166.451 + { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
166.452 + ret = 3;
166.453 + goto done;
166.454 + }
166.455 + page = count = 0;
166.456 + for (pass = 1; pass <= 2; pass++)
166.457 + for (t = 1; t <= (len == 0 ? m+n : len); t++)
166.458 + { if (t == 1) count = 0;
166.459 + k = (len == 0 ? t : list[t]);
166.460 + if (pass == 1 && k > m || pass == 2 && k <= m)
166.461 + continue;
166.462 + if (count == 0)
166.463 + { xfprintf(fp, "GLPK %-4s - SENSITIVITY ANALYSIS REPORT%73sPa"
166.464 + "ge%4d\n", glp_version(), "", ++page);
166.465 + xfprintf(fp, "\n");
166.466 + xfprintf(fp, "%-12s%s\n", "Problem:",
166.467 + P->name == NULL ? "" : P->name);
166.468 + xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
166.469 + P->obj == NULL ? "" : P->obj,
166.470 + P->obj == NULL ? "" : " = ", P->obj_val,
166.471 + P->dir == GLP_MIN ? "MINimum" :
166.472 + P->dir == GLP_MAX ? "MAXimum" : "???");
166.473 + xfprintf(fp, "\n");
166.474 + xfprintf(fp, "%6s %-12s %2s %13s %13s %13s %13s %13s %13s "
166.475 + "%s\n", "No.", pass == 1 ? "Row name" : "Column name",
166.476 + "St", "Activity", pass == 1 ? "Slack" : "Obj coef",
166.477 + "Lower bound", "Activity", "Obj coef", "Obj value at",
166.478 + "Limiting");
166.479 + xfprintf(fp, "%6s %-12s %2s %13s %13s %13s %13s %13s %13s "
166.480 + "%s\n", "", "", "", "", "Marginal", "Upper bound",
166.481 + "range", "range", "break point", "variable");
166.482 + xfprintf(fp, "------ ------------ -- ------------- --------"
166.483 + "----- ------------- ------------- ------------- ------"
166.484 + "------- ------------\n");
166.485 + }
166.486 + if (pass == 1)
166.487 + { numb = k;
166.488 + xassert(1 <= numb && numb <= m);
166.489 + row = P->row[numb];
166.490 + name = row->name;
166.491 + type = row->type;
166.492 + lb = glp_get_row_lb(P, numb);
166.493 + ub = glp_get_row_ub(P, numb);
166.494 + coef = 0.0;
166.495 + stat = row->stat;
166.496 + prim = row->prim;
166.497 + if (type == GLP_FR)
166.498 + slack = - prim;
166.499 + else if (type == GLP_LO)
166.500 + slack = lb - prim;
166.501 + else if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
166.502 + slack = ub - prim;
166.503 + dual = row->dual;
166.504 + }
166.505 + else
166.506 + { numb = k - m;
166.507 + xassert(1 <= numb && numb <= n);
166.508 + col = P->col[numb];
166.509 + name = col->name;
166.510 + lb = glp_get_col_lb(P, numb);
166.511 + ub = glp_get_col_ub(P, numb);
166.512 + coef = col->coef;
166.513 + stat = col->stat;
166.514 + prim = col->prim;
166.515 + slack = 0.0;
166.516 + dual = col->dual;
166.517 + }
166.518 + if (stat != GLP_BS)
166.519 + { glp_analyze_bound(P, k, &value1, &var1, &value2, &var2);
166.520 + if (stat == GLP_NF)
166.521 + coef1 = coef2 = coef;
166.522 + else if (stat == GLP_NS)
166.523 + coef1 = -DBL_MAX, coef2 = +DBL_MAX;
166.524 + else if (stat == GLP_NL && P->dir == GLP_MIN ||
166.525 + stat == GLP_NU && P->dir == GLP_MAX)
166.526 + coef1 = coef - dual, coef2 = +DBL_MAX;
166.527 + else
166.528 + coef1 = -DBL_MAX, coef2 = coef - dual;
166.529 + if (value1 == -DBL_MAX)
166.530 + { if (dual < -1e-9)
166.531 + obj1 = +DBL_MAX;
166.532 + else if (dual > +1e-9)
166.533 + obj1 = -DBL_MAX;
166.534 + else
166.535 + obj1 = P->obj_val;
166.536 + }
166.537 + else
166.538 + obj1 = P->obj_val + dual * (value1 - prim);
166.539 + if (value2 == +DBL_MAX)
166.540 + { if (dual < -1e-9)
166.541 + obj2 = -DBL_MAX;
166.542 + else if (dual > +1e-9)
166.543 + obj2 = +DBL_MAX;
166.544 + else
166.545 + obj2 = P->obj_val;
166.546 + }
166.547 + else
166.548 + obj2 = P->obj_val + dual * (value2 - prim);
166.549 + }
166.550 + else
166.551 + { glp_analyze_coef(P, k, &coef1, &var1, &value1, &coef2,
166.552 + &var2, &value2);
166.553 + if (coef1 == -DBL_MAX)
166.554 + { if (prim < -1e-9)
166.555 + obj1 = +DBL_MAX;
166.556 + else if (prim > +1e-9)
166.557 + obj1 = -DBL_MAX;
166.558 + else
166.559 + obj1 = P->obj_val;
166.560 + }
166.561 + else
166.562 + obj1 = P->obj_val + (coef1 - coef) * prim;
166.563 + if (coef2 == +DBL_MAX)
166.564 + { if (prim < -1e-9)
166.565 + obj2 = -DBL_MAX;
166.566 + else if (prim > +1e-9)
166.567 + obj2 = +DBL_MAX;
166.568 + else
166.569 + obj2 = P->obj_val;
166.570 + }
166.571 + else
166.572 + obj2 = P->obj_val + (coef2 - coef) * prim;
166.573 + }
166.574 + /*** first line ***/
166.575 + /* row/column number */
166.576 + xfprintf(fp, "%6d", numb);
166.577 + /* row/column name */
166.578 + xfprintf(fp, " %-12.12s", name == NULL ? "" : name);
166.579 + if (name != NULL && strlen(name) > 12)
166.580 + xfprintf(fp, "%s\n%6s %12s", name+12, "", "");
166.581 + /* row/column status */
166.582 + xfprintf(fp, " %2s",
166.583 + stat == GLP_BS ? "BS" : stat == GLP_NL ? "NL" :
166.584 + stat == GLP_NU ? "NU" : stat == GLP_NF ? "NF" :
166.585 + stat == GLP_NS ? "NS" : "??");
166.586 + /* row/column activity */
166.587 + xfprintf(fp, " %s", format(buf, prim));
166.588 + /* row slack, column objective coefficient */
166.589 + xfprintf(fp, " %s", format(buf, k <= m ? slack : coef));
166.590 + /* row/column lower bound */
166.591 + xfprintf(fp, " %s", format(buf, lb));
166.592 + /* row/column activity range */
166.593 + xfprintf(fp, " %s", format(buf, value1));
166.594 + /* row/column objective coefficient range */
166.595 + xfprintf(fp, " %s", format(buf, coef1));
166.596 + /* objective value at break point */
166.597 + xfprintf(fp, " %s", format(buf, obj1));
166.598 + /* limiting variable name */
166.599 + if (var1 != 0)
166.600 + { if (var1 <= m)
166.601 + limit = glp_get_row_name(P, var1);
166.602 + else
166.603 + limit = glp_get_col_name(P, var1 - m);
166.604 + if (limit != NULL)
166.605 + xfprintf(fp, " %s", limit);
166.606 + }
166.607 + xfprintf(fp, "\n");
166.608 + /*** second line ***/
166.609 + xfprintf(fp, "%6s %-12s %2s %13s", "", "", "", "");
166.610 + /* row/column reduced cost */
166.611 + xfprintf(fp, " %s", format(buf, dual));
166.612 + /* row/column upper bound */
166.613 + xfprintf(fp, " %s", format(buf, ub));
166.614 + /* row/column activity range */
166.615 + xfprintf(fp, " %s", format(buf, value2));
166.616 + /* row/column objective coefficient range */
166.617 + xfprintf(fp, " %s", format(buf, coef2));
166.618 + /* objective value at break point */
166.619 + xfprintf(fp, " %s", format(buf, obj2));
166.620 + /* limiting variable name */
166.621 + if (var2 != 0)
166.622 + { if (var2 <= m)
166.623 + limit = glp_get_row_name(P, var2);
166.624 + else
166.625 + limit = glp_get_col_name(P, var2 - m);
166.626 + if (limit != NULL)
166.627 + xfprintf(fp, " %s", limit);
166.628 + }
166.629 + xfprintf(fp, "\n");
166.630 + xfprintf(fp, "\n");
166.631 + /* print 10 items per page */
166.632 + count = (count + 1) % 10;
166.633 + }
166.634 + xfprintf(fp, "End of report\n");
166.635 + xfflush(fp);
166.636 + if (xferror(fp))
166.637 + { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
166.638 + ret = 4;
166.639 + goto done;
166.640 + }
166.641 + ret = 0;
166.642 +done: if (fp != NULL) xfclose(fp);
166.643 + return ret;
166.644 +}
166.645 +
166.646 +/**********************************************************************/
166.647 +
166.648 +int glp_print_ipt(glp_prob *P, const char *fname)
166.649 +{ /* write interior-point solution in printable format */
166.650 + XFILE *fp;
166.651 + GLPROW *row;
166.652 + GLPCOL *col;
166.653 + int i, j, t, ae_ind, re_ind, ret;
166.654 + double ae_max, re_max;
166.655 + xprintf("Writing interior-point solution to `%s'...\n", fname);
166.656 + fp = xfopen(fname, "w");
166.657 + if (fp == NULL)
166.658 + { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
166.659 + ret = 1;
166.660 + goto done;
166.661 + }
166.662 + xfprintf(fp, "%-12s%s\n", "Problem:",
166.663 + P->name == NULL ? "" : P->name);
166.664 + xfprintf(fp, "%-12s%d\n", "Rows:", P->m);
166.665 + xfprintf(fp, "%-12s%d\n", "Columns:", P->n);
166.666 + xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz);
166.667 + t = glp_ipt_status(P);
166.668 + xfprintf(fp, "%-12s%s\n", "Status:",
166.669 + t == GLP_OPT ? "OPTIMAL" :
166.670 + t == GLP_UNDEF ? "UNDEFINED" :
166.671 + t == GLP_INFEAS ? "INFEASIBLE (INTERMEDIATE)" :
166.672 + t == GLP_NOFEAS ? "INFEASIBLE (FINAL)" : "???");
166.673 + xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
166.674 + P->obj == NULL ? "" : P->obj,
166.675 + P->obj == NULL ? "" : " = ", P->ipt_obj,
166.676 + P->dir == GLP_MIN ? "MINimum" :
166.677 + P->dir == GLP_MAX ? "MAXimum" : "???");
166.678 + xfprintf(fp, "\n");
166.679 + xfprintf(fp, " No. Row name Activity Lower bound "
166.680 + " Upper bound Marginal\n");
166.681 + xfprintf(fp, "------ ------------ ------------- ------------- "
166.682 + "------------- -------------\n");
166.683 + for (i = 1; i <= P->m; i++)
166.684 + { row = P->row[i];
166.685 + xfprintf(fp, "%6d ", i);
166.686 + if (row->name == NULL || strlen(row->name) <= 12)
166.687 + xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
166.688 + else
166.689 + xfprintf(fp, "%s\n%20s", row->name, "");
166.690 + xfprintf(fp, "%3s", "");
166.691 + xfprintf(fp, "%13.6g ",
166.692 + fabs(row->pval) <= 1e-9 ? 0.0 : row->pval);
166.693 + if (row->type == GLP_LO || row->type == GLP_DB ||
166.694 + row->type == GLP_FX)
166.695 + xfprintf(fp, "%13.6g ", row->lb);
166.696 + else
166.697 + xfprintf(fp, "%13s ", "");
166.698 + if (row->type == GLP_UP || row->type == GLP_DB)
166.699 + xfprintf(fp, "%13.6g ", row->ub);
166.700 + else
166.701 + xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
166.702 + if (fabs(row->dval) <= 1e-9)
166.703 + xfprintf(fp, "%13s", "< eps");
166.704 + else
166.705 + xfprintf(fp, "%13.6g ", row->dval);
166.706 + xfprintf(fp, "\n");
166.707 + }
166.708 + xfprintf(fp, "\n");
166.709 + xfprintf(fp, " No. Column name Activity Lower bound "
166.710 + " Upper bound Marginal\n");
166.711 + xfprintf(fp, "------ ------------ ------------- ------------- "
166.712 + "------------- -------------\n");
166.713 + for (j = 1; j <= P->n; j++)
166.714 + { col = P->col[j];
166.715 + xfprintf(fp, "%6d ", j);
166.716 + if (col->name == NULL || strlen(col->name) <= 12)
166.717 + xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
166.718 + else
166.719 + xfprintf(fp, "%s\n%20s", col->name, "");
166.720 + xfprintf(fp, "%3s", "");
166.721 + xfprintf(fp, "%13.6g ",
166.722 + fabs(col->pval) <= 1e-9 ? 0.0 : col->pval);
166.723 + if (col->type == GLP_LO || col->type == GLP_DB ||
166.724 + col->type == GLP_FX)
166.725 + xfprintf(fp, "%13.6g ", col->lb);
166.726 + else
166.727 + xfprintf(fp, "%13s ", "");
166.728 + if (col->type == GLP_UP || col->type == GLP_DB)
166.729 + xfprintf(fp, "%13.6g ", col->ub);
166.730 + else
166.731 + xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
166.732 + if (fabs(col->dval) <= 1e-9)
166.733 + xfprintf(fp, "%13s", "< eps");
166.734 + else
166.735 + xfprintf(fp, "%13.6g ", col->dval);
166.736 + xfprintf(fp, "\n");
166.737 + }
166.738 + xfprintf(fp, "\n");
166.739 + xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n");
166.740 + xfprintf(fp, "\n");
166.741 + _glp_check_kkt(P, GLP_IPT, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
166.742 + &re_ind);
166.743 + xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
166.744 + ae_max, ae_ind);
166.745 + xfprintf(fp, " max.rel.err = %.2e on row %d\n",
166.746 + re_max, re_ind);
166.747 + xfprintf(fp, "%8s%s\n", "",
166.748 + re_max <= 1e-9 ? "High quality" :
166.749 + re_max <= 1e-6 ? "Medium quality" :
166.750 + re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS WRONG");
166.751 + xfprintf(fp, "\n");
166.752 + _glp_check_kkt(P, GLP_IPT, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
166.753 + &re_ind);
166.754 + xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n",
166.755 + ae_max, ae_ind <= P->m ? "row" : "column",
166.756 + ae_ind <= P->m ? ae_ind : ae_ind - P->m);
166.757 + xfprintf(fp, " max.rel.err = %.2e on %s %d\n",
166.758 + re_max, re_ind <= P->m ? "row" : "column",
166.759 + re_ind <= P->m ? re_ind : re_ind - P->m);
166.760 + xfprintf(fp, "%8s%s\n", "",
166.761 + re_max <= 1e-9 ? "High quality" :
166.762 + re_max <= 1e-6 ? "Medium quality" :
166.763 + re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS INFEASIBL"
166.764 + "E");
166.765 + xfprintf(fp, "\n");
166.766 + _glp_check_kkt(P, GLP_IPT, GLP_KKT_DE, &ae_max, &ae_ind, &re_max,
166.767 + &re_ind);
166.768 + xfprintf(fp, "KKT.DE: max.abs.err = %.2e on column %d\n",
166.769 + ae_max, ae_ind == 0 ? 0 : ae_ind - P->m);
166.770 + xfprintf(fp, " max.rel.err = %.2e on column %d\n",
166.771 + re_max, re_ind == 0 ? 0 : re_ind - P->m);
166.772 + xfprintf(fp, "%8s%s\n", "",
166.773 + re_max <= 1e-9 ? "High quality" :
166.774 + re_max <= 1e-6 ? "Medium quality" :
166.775 + re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS WRONG");
166.776 + xfprintf(fp, "\n");
166.777 + _glp_check_kkt(P, GLP_IPT, GLP_KKT_DB, &ae_max, &ae_ind, &re_max,
166.778 + &re_ind);
166.779 + xfprintf(fp, "KKT.DB: max.abs.err = %.2e on %s %d\n",
166.780 + ae_max, ae_ind <= P->m ? "row" : "column",
166.781 + ae_ind <= P->m ? ae_ind : ae_ind - P->m);
166.782 + xfprintf(fp, " max.rel.err = %.2e on %s %d\n",
166.783 + re_max, re_ind <= P->m ? "row" : "column",
166.784 + re_ind <= P->m ? re_ind : re_ind - P->m);
166.785 + xfprintf(fp, "%8s%s\n", "",
166.786 + re_max <= 1e-9 ? "High quality" :
166.787 + re_max <= 1e-6 ? "Medium quality" :
166.788 + re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS INFEASIBLE")
166.789 + ;
166.790 + xfprintf(fp, "\n");
166.791 + xfprintf(fp, "End of output\n");
166.792 + xfflush(fp);
166.793 + if (xferror(fp))
166.794 + { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
166.795 + ret = 1;
166.796 + goto done;
166.797 + }
166.798 + ret = 0;
166.799 +done: if (fp != NULL) xfclose(fp);
166.800 + return ret;
166.801 +}
166.802 +
166.803 +/***********************************************************************
166.804 +* NAME
166.805 +*
166.806 +* glp_read_ipt - read interior-point solution from text file
166.807 +*
166.808 +* SYNOPSIS
166.809 +*
166.810 +* int glp_read_ipt(glp_prob *lp, const char *fname);
166.811 +*
166.812 +* DESCRIPTION
166.813 +*
166.814 +* The routine glp_read_ipt reads interior-point solution from a text
166.815 +* file whose name is specified by the parameter fname into the problem
166.816 +* object.
166.817 +*
166.818 +* For the file format see description of the routine glp_write_ipt.
166.819 +*
166.820 +* RETURNS
166.821 +*
166.822 +* On success the routine returns zero, otherwise non-zero. */
166.823 +
166.824 +int glp_read_ipt(glp_prob *lp, const char *fname)
166.825 +{ glp_data *data;
166.826 + jmp_buf jump;
166.827 + int i, j, k, ret = 0;
166.828 + xprintf("Reading interior-point solution from `%s'...\n", fname);
166.829 + data = glp_sdf_open_file(fname);
166.830 + if (data == NULL)
166.831 + { ret = 1;
166.832 + goto done;
166.833 + }
166.834 + if (setjmp(jump))
166.835 + { ret = 1;
166.836 + goto done;
166.837 + }
166.838 + glp_sdf_set_jump(data, jump);
166.839 + /* number of rows, number of columns */
166.840 + k = glp_sdf_read_int(data);
166.841 + if (k != lp->m)
166.842 + glp_sdf_error(data, "wrong number of rows\n");
166.843 + k = glp_sdf_read_int(data);
166.844 + if (k != lp->n)
166.845 + glp_sdf_error(data, "wrong number of columns\n");
166.846 + /* solution status, objective value */
166.847 + k = glp_sdf_read_int(data);
166.848 + if (!(k == GLP_UNDEF || k == GLP_OPT))
166.849 + glp_sdf_error(data, "invalid solution status\n");
166.850 + lp->ipt_stat = k;
166.851 + lp->ipt_obj = glp_sdf_read_num(data);
166.852 + /* rows (auxiliary variables) */
166.853 + for (i = 1; i <= lp->m; i++)
166.854 + { GLPROW *row = lp->row[i];
166.855 + /* primal value, dual value */
166.856 + row->pval = glp_sdf_read_num(data);
166.857 + row->dval = glp_sdf_read_num(data);
166.858 + }
166.859 + /* columns (structural variables) */
166.860 + for (j = 1; j <= lp->n; j++)
166.861 + { GLPCOL *col = lp->col[j];
166.862 + /* primal value, dual value */
166.863 + col->pval = glp_sdf_read_num(data);
166.864 + col->dval = glp_sdf_read_num(data);
166.865 + }
166.866 + xprintf("%d lines were read\n", glp_sdf_line(data));
166.867 +done: if (ret) lp->ipt_stat = GLP_UNDEF;
166.868 + if (data != NULL) glp_sdf_close_file(data);
166.869 + return ret;
166.870 +}
166.871 +
166.872 +/***********************************************************************
166.873 +* NAME
166.874 +*
166.875 +* glp_write_ipt - write interior-point solution to text file
166.876 +*
166.877 +* SYNOPSIS
166.878 +*
166.879 +* int glp_write_ipt(glp_prob *lp, const char *fname);
166.880 +*
166.881 +* DESCRIPTION
166.882 +*
166.883 +* The routine glp_write_ipt writes the current interior-point solution
166.884 +* to a text file whose name is specified by the parameter fname. This
166.885 +* file can be read back with the routine glp_read_ipt.
166.886 +*
166.887 +* RETURNS
166.888 +*
166.889 +* On success the routine returns zero, otherwise non-zero.
166.890 +*
166.891 +* FILE FORMAT
166.892 +*
166.893 +* The file created by the routine glp_write_ipt is a plain text file,
166.894 +* which contains the following information:
166.895 +*
166.896 +* m n
166.897 +* stat obj_val
166.898 +* r_prim[1] r_dual[1]
166.899 +* . . .
166.900 +* r_prim[m] r_dual[m]
166.901 +* c_prim[1] c_dual[1]
166.902 +* . . .
166.903 +* c_prim[n] c_dual[n]
166.904 +*
166.905 +* where:
166.906 +* m is the number of rows (auxiliary variables);
166.907 +* n is the number of columns (structural variables);
166.908 +* stat is the solution status (GLP_UNDEF = 1 or GLP_OPT = 5);
166.909 +* obj_val is the objective value;
166.910 +* r_prim[i], i = 1,...,m, is the primal value of i-th row;
166.911 +* r_dual[i], i = 1,...,m, is the dual value of i-th row;
166.912 +* c_prim[j], j = 1,...,n, is the primal value of j-th column;
166.913 +* c_dual[j], j = 1,...,n, is the dual value of j-th column. */
166.914 +
166.915 +int glp_write_ipt(glp_prob *lp, const char *fname)
166.916 +{ XFILE *fp;
166.917 + int i, j, ret = 0;
166.918 + xprintf("Writing interior-point solution to `%s'...\n", fname);
166.919 + fp = xfopen(fname, "w");
166.920 + if (fp == NULL)
166.921 + { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
166.922 + ret = 1;
166.923 + goto done;
166.924 + }
166.925 + /* number of rows, number of columns */
166.926 + xfprintf(fp, "%d %d\n", lp->m, lp->n);
166.927 + /* solution status, objective value */
166.928 + xfprintf(fp, "%d %.*g\n", lp->ipt_stat, DBL_DIG, lp->ipt_obj);
166.929 + /* rows (auxiliary variables) */
166.930 + for (i = 1; i <= lp->m; i++)
166.931 + { GLPROW *row = lp->row[i];
166.932 + /* primal value, dual value */
166.933 + xfprintf(fp, "%.*g %.*g\n", DBL_DIG, row->pval, DBL_DIG,
166.934 + row->dval);
166.935 + }
166.936 + /* columns (structural variables) */
166.937 + for (j = 1; j <= lp->n; j++)
166.938 + { GLPCOL *col = lp->col[j];
166.939 + /* primal value, dual value */
166.940 + xfprintf(fp, "%.*g %.*g\n", DBL_DIG, col->pval, DBL_DIG,
166.941 + col->dval);
166.942 + }
166.943 + xfflush(fp);
166.944 + if (xferror(fp))
166.945 + { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
166.946 + ret = 1;
166.947 + goto done;
166.948 + }
166.949 + xprintf("%d lines were written\n", 2 + lp->m + lp->n);
166.950 +done: if (fp != NULL) xfclose(fp);
166.951 + return ret;
166.952 +}
166.953 +
166.954 +/**********************************************************************/
166.955 +
166.956 +int glp_print_mip(glp_prob *P, const char *fname)
166.957 +{ /* write MIP solution in printable format */
166.958 + XFILE *fp;
166.959 + GLPROW *row;
166.960 + GLPCOL *col;
166.961 + int i, j, t, ae_ind, re_ind, ret;
166.962 + double ae_max, re_max;
166.963 + xprintf("Writing MIP solution to `%s'...\n", fname);
166.964 + fp = xfopen(fname, "w");
166.965 + if (fp == NULL)
166.966 + { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
166.967 + ret = 1;
166.968 + goto done;
166.969 + }
166.970 + xfprintf(fp, "%-12s%s\n", "Problem:",
166.971 + P->name == NULL ? "" : P->name);
166.972 + xfprintf(fp, "%-12s%d\n", "Rows:", P->m);
166.973 + xfprintf(fp, "%-12s%d (%d integer, %d binary)\n", "Columns:",
166.974 + P->n, glp_get_num_int(P), glp_get_num_bin(P));
166.975 + xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz);
166.976 + t = glp_mip_status(P);
166.977 + xfprintf(fp, "%-12s%s\n", "Status:",
166.978 + t == GLP_OPT ? "INTEGER OPTIMAL" :
166.979 + t == GLP_FEAS ? "INTEGER NON-OPTIMAL" :
166.980 + t == GLP_NOFEAS ? "INTEGER EMPTY" :
166.981 + t == GLP_UNDEF ? "INTEGER UNDEFINED" : "???");
166.982 + xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
166.983 + P->obj == NULL ? "" : P->obj,
166.984 + P->obj == NULL ? "" : " = ", P->mip_obj,
166.985 + P->dir == GLP_MIN ? "MINimum" :
166.986 + P->dir == GLP_MAX ? "MAXimum" : "???");
166.987 + xfprintf(fp, "\n");
166.988 + xfprintf(fp, " No. Row name Activity Lower bound "
166.989 + " Upper bound\n");
166.990 + xfprintf(fp, "------ ------------ ------------- ------------- "
166.991 + "-------------\n");
166.992 + for (i = 1; i <= P->m; i++)
166.993 + { row = P->row[i];
166.994 + xfprintf(fp, "%6d ", i);
166.995 + if (row->name == NULL || strlen(row->name) <= 12)
166.996 + xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
166.997 + else
166.998 + xfprintf(fp, "%s\n%20s", row->name, "");
166.999 + xfprintf(fp, "%3s", "");
166.1000 + xfprintf(fp, "%13.6g ",
166.1001 + fabs(row->mipx) <= 1e-9 ? 0.0 : row->mipx);
166.1002 + if (row->type == GLP_LO || row->type == GLP_DB ||
166.1003 + row->type == GLP_FX)
166.1004 + xfprintf(fp, "%13.6g ", row->lb);
166.1005 + else
166.1006 + xfprintf(fp, "%13s ", "");
166.1007 + if (row->type == GLP_UP || row->type == GLP_DB)
166.1008 + xfprintf(fp, "%13.6g ", row->ub);
166.1009 + else
166.1010 + xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
166.1011 + xfprintf(fp, "\n");
166.1012 + }
166.1013 + xfprintf(fp, "\n");
166.1014 + xfprintf(fp, " No. Column name Activity Lower bound "
166.1015 + " Upper bound\n");
166.1016 + xfprintf(fp, "------ ------------ ------------- ------------- "
166.1017 + "-------------\n");
166.1018 + for (j = 1; j <= P->n; j++)
166.1019 + { col = P->col[j];
166.1020 + xfprintf(fp, "%6d ", j);
166.1021 + if (col->name == NULL || strlen(col->name) <= 12)
166.1022 + xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
166.1023 + else
166.1024 + xfprintf(fp, "%s\n%20s", col->name, "");
166.1025 + xfprintf(fp, "%s ",
166.1026 + col->kind == GLP_CV ? " " :
166.1027 + col->kind == GLP_IV ? "*" : "?");
166.1028 + xfprintf(fp, "%13.6g ",
166.1029 + fabs(col->mipx) <= 1e-9 ? 0.0 : col->mipx);
166.1030 + if (col->type == GLP_LO || col->type == GLP_DB ||
166.1031 + col->type == GLP_FX)
166.1032 + xfprintf(fp, "%13.6g ", col->lb);
166.1033 + else
166.1034 + xfprintf(fp, "%13s ", "");
166.1035 + if (col->type == GLP_UP || col->type == GLP_DB)
166.1036 + xfprintf(fp, "%13.6g ", col->ub);
166.1037 + else
166.1038 + xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
166.1039 + xfprintf(fp, "\n");
166.1040 + }
166.1041 + xfprintf(fp, "\n");
166.1042 + xfprintf(fp, "Integer feasibility conditions:\n");
166.1043 + xfprintf(fp, "\n");
166.1044 + _glp_check_kkt(P, GLP_MIP, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
166.1045 + &re_ind);
166.1046 + xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
166.1047 + ae_max, ae_ind);
166.1048 + xfprintf(fp, " max.rel.err = %.2e on row %d\n",
166.1049 + re_max, re_ind);
166.1050 + xfprintf(fp, "%8s%s\n", "",
166.1051 + re_max <= 1e-9 ? "High quality" :
166.1052 + re_max <= 1e-6 ? "Medium quality" :
166.1053 + re_max <= 1e-3 ? "Low quality" : "SOLUTION IS WRONG");
166.1054 + xfprintf(fp, "\n");
166.1055 + _glp_check_kkt(P, GLP_MIP, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
166.1056 + &re_ind);
166.1057 + xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n",
166.1058 + ae_max, ae_ind <= P->m ? "row" : "column",
166.1059 + ae_ind <= P->m ? ae_ind : ae_ind - P->m);
166.1060 + xfprintf(fp, " max.rel.err = %.2e on %s %d\n",
166.1061 + re_max, re_ind <= P->m ? "row" : "column",
166.1062 + re_ind <= P->m ? re_ind : re_ind - P->m);
166.1063 + xfprintf(fp, "%8s%s\n", "",
166.1064 + re_max <= 1e-9 ? "High quality" :
166.1065 + re_max <= 1e-6 ? "Medium quality" :
166.1066 + re_max <= 1e-3 ? "Low quality" : "SOLUTION IS INFEASIBLE");
166.1067 + xfprintf(fp, "\n");
166.1068 + xfprintf(fp, "End of output\n");
166.1069 + xfflush(fp);
166.1070 + if (xferror(fp))
166.1071 + { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
166.1072 + ret = 1;
166.1073 + goto done;
166.1074 + }
166.1075 + ret = 0;
166.1076 +done: if (fp != NULL) xfclose(fp);
166.1077 + return ret;
166.1078 +}
166.1079 +
166.1080 +/***********************************************************************
166.1081 +* NAME
166.1082 +*
166.1083 +* glp_read_mip - read MIP solution from text file
166.1084 +*
166.1085 +* SYNOPSIS
166.1086 +*
166.1087 +* int glp_read_mip(glp_prob *mip, const char *fname);
166.1088 +*
166.1089 +* DESCRIPTION
166.1090 +*
166.1091 +* The routine glp_read_mip reads MIP solution from a text file whose
166.1092 +* name is specified by the parameter fname into the problem object.
166.1093 +*
166.1094 +* For the file format see description of the routine glp_write_mip.
166.1095 +*
166.1096 +* RETURNS
166.1097 +*
166.1098 +* On success the routine returns zero, otherwise non-zero. */
166.1099 +
166.1100 +int glp_read_mip(glp_prob *mip, const char *fname)
166.1101 +{ glp_data *data;
166.1102 + jmp_buf jump;
166.1103 + int i, j, k, ret = 0;
166.1104 + xprintf("Reading MIP solution from `%s'...\n", fname);
166.1105 + data = glp_sdf_open_file(fname);
166.1106 + if (data == NULL)
166.1107 + { ret = 1;
166.1108 + goto done;
166.1109 + }
166.1110 + if (setjmp(jump))
166.1111 + { ret = 1;
166.1112 + goto done;
166.1113 + }
166.1114 + glp_sdf_set_jump(data, jump);
166.1115 + /* number of rows, number of columns */
166.1116 + k = glp_sdf_read_int(data);
166.1117 + if (k != mip->m)
166.1118 + glp_sdf_error(data, "wrong number of rows\n");
166.1119 + k = glp_sdf_read_int(data);
166.1120 + if (k != mip->n)
166.1121 + glp_sdf_error(data, "wrong number of columns\n");
166.1122 + /* solution status, objective value */
166.1123 + k = glp_sdf_read_int(data);
166.1124 + if (!(k == GLP_UNDEF || k == GLP_OPT || k == GLP_FEAS ||
166.1125 + k == GLP_NOFEAS))
166.1126 + glp_sdf_error(data, "invalid solution status\n");
166.1127 + mip->mip_stat = k;
166.1128 + mip->mip_obj = glp_sdf_read_num(data);
166.1129 + /* rows (auxiliary variables) */
166.1130 + for (i = 1; i <= mip->m; i++)
166.1131 + { GLPROW *row = mip->row[i];
166.1132 + row->mipx = glp_sdf_read_num(data);
166.1133 + }
166.1134 + /* columns (structural variables) */
166.1135 + for (j = 1; j <= mip->n; j++)
166.1136 + { GLPCOL *col = mip->col[j];
166.1137 + col->mipx = glp_sdf_read_num(data);
166.1138 + if (col->kind == GLP_IV && col->mipx != floor(col->mipx))
166.1139 + glp_sdf_error(data, "non-integer column value");
166.1140 + }
166.1141 + xprintf("%d lines were read\n", glp_sdf_line(data));
166.1142 +done: if (ret) mip->mip_stat = GLP_UNDEF;
166.1143 + if (data != NULL) glp_sdf_close_file(data);
166.1144 + return ret;
166.1145 +}
166.1146 +
166.1147 +/***********************************************************************
166.1148 +* NAME
166.1149 +*
166.1150 +* glp_write_mip - write MIP solution to text file
166.1151 +*
166.1152 +* SYNOPSIS
166.1153 +*
166.1154 +* int glp_write_mip(glp_prob *mip, const char *fname);
166.1155 +*
166.1156 +* DESCRIPTION
166.1157 +*
166.1158 +* The routine glp_write_mip writes the current MIP solution to a text
166.1159 +* file whose name is specified by the parameter fname. This file can
166.1160 +* be read back with the routine glp_read_mip.
166.1161 +*
166.1162 +* RETURNS
166.1163 +*
166.1164 +* On success the routine returns zero, otherwise non-zero.
166.1165 +*
166.1166 +* FILE FORMAT
166.1167 +*
166.1168 +* The file created by the routine glp_write_sol is a plain text file,
166.1169 +* which contains the following information:
166.1170 +*
166.1171 +* m n
166.1172 +* stat obj_val
166.1173 +* r_val[1]
166.1174 +* . . .
166.1175 +* r_val[m]
166.1176 +* c_val[1]
166.1177 +* . . .
166.1178 +* c_val[n]
166.1179 +*
166.1180 +* where:
166.1181 +* m is the number of rows (auxiliary variables);
166.1182 +* n is the number of columns (structural variables);
166.1183 +* stat is the solution status (GLP_UNDEF = 1, GLP_FEAS = 2,
166.1184 +* GLP_NOFEAS = 4, or GLP_OPT = 5);
166.1185 +* obj_val is the objective value;
166.1186 +* r_val[i], i = 1,...,m, is the value of i-th row;
166.1187 +* c_val[j], j = 1,...,n, is the value of j-th column. */
166.1188 +
166.1189 +int glp_write_mip(glp_prob *mip, const char *fname)
166.1190 +{ XFILE *fp;
166.1191 + int i, j, ret = 0;
166.1192 + xprintf("Writing MIP solution to `%s'...\n", fname);
166.1193 + fp = xfopen(fname, "w");
166.1194 + if (fp == NULL)
166.1195 + { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
166.1196 + ret = 1;
166.1197 + goto done;
166.1198 + }
166.1199 + /* number of rows, number of columns */
166.1200 + xfprintf(fp, "%d %d\n", mip->m, mip->n);
166.1201 + /* solution status, objective value */
166.1202 + xfprintf(fp, "%d %.*g\n", mip->mip_stat, DBL_DIG, mip->mip_obj);
166.1203 + /* rows (auxiliary variables) */
166.1204 + for (i = 1; i <= mip->m; i++)
166.1205 + xfprintf(fp, "%.*g\n", DBL_DIG, mip->row[i]->mipx);
166.1206 + /* columns (structural variables) */
166.1207 + for (j = 1; j <= mip->n; j++)
166.1208 + xfprintf(fp, "%.*g\n", DBL_DIG, mip->col[j]->mipx);
166.1209 + xfflush(fp);
166.1210 + if (xferror(fp))
166.1211 + { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
166.1212 + ret = 1;
166.1213 + goto done;
166.1214 + }
166.1215 + xprintf("%d lines were written\n", 2 + mip->m + mip->n);
166.1216 +done: if (fp != NULL) xfclose(fp);
166.1217 + return ret;
166.1218 +}
166.1219 +
166.1220 +/* eof */
167.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
167.2 +++ b/src/glpapi12.c Mon Dec 06 13:09:21 2010 +0100
167.3 @@ -0,0 +1,2219 @@
167.4 +/* glpapi12.c (basis factorization and simplex tableau routines) */
167.5 +
167.6 +/***********************************************************************
167.7 +* This code is part of GLPK (GNU Linear Programming Kit).
167.8 +*
167.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
167.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
167.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
167.12 +* E-mail: <mao@gnu.org>.
167.13 +*
167.14 +* GLPK is free software: you can redistribute it and/or modify it
167.15 +* under the terms of the GNU General Public License as published by
167.16 +* the Free Software Foundation, either version 3 of the License, or
167.17 +* (at your option) any later version.
167.18 +*
167.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
167.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
167.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
167.22 +* License for more details.
167.23 +*
167.24 +* You should have received a copy of the GNU General Public License
167.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
167.26 +***********************************************************************/
167.27 +
167.28 +#include "glpapi.h"
167.29 +
167.30 +/***********************************************************************
167.31 +* NAME
167.32 +*
167.33 +* glp_bf_exists - check if the basis factorization exists
167.34 +*
167.35 +* SYNOPSIS
167.36 +*
167.37 +* int glp_bf_exists(glp_prob *lp);
167.38 +*
167.39 +* RETURNS
167.40 +*
167.41 +* If the basis factorization for the current basis associated with
167.42 +* the specified problem object exists and therefore is available for
167.43 +* computations, the routine glp_bf_exists returns non-zero. Otherwise
167.44 +* the routine returns zero. */
167.45 +
167.46 +int glp_bf_exists(glp_prob *lp)
167.47 +{ int ret;
167.48 + ret = (lp->m == 0 || lp->valid);
167.49 + return ret;
167.50 +}
167.51 +
167.52 +/***********************************************************************
167.53 +* NAME
167.54 +*
167.55 +* glp_factorize - compute the basis factorization
167.56 +*
167.57 +* SYNOPSIS
167.58 +*
167.59 +* int glp_factorize(glp_prob *lp);
167.60 +*
167.61 +* DESCRIPTION
167.62 +*
167.63 +* The routine glp_factorize computes the basis factorization for the
167.64 +* current basis associated with the specified problem object.
167.65 +*
167.66 +* RETURNS
167.67 +*
167.68 +* 0 The basis factorization has been successfully computed.
167.69 +*
167.70 +* GLP_EBADB
167.71 +* The basis matrix is invalid, i.e. the number of basic (auxiliary
167.72 +* and structural) variables differs from the number of rows in the
167.73 +* problem object.
167.74 +*
167.75 +* GLP_ESING
167.76 +* The basis matrix is singular within the working precision.
167.77 +*
167.78 +* GLP_ECOND
167.79 +* The basis matrix is ill-conditioned. */
167.80 +
167.81 +static int b_col(void *info, int j, int ind[], double val[])
167.82 +{ glp_prob *lp = info;
167.83 + int m = lp->m;
167.84 + GLPAIJ *aij;
167.85 + int k, len;
167.86 + xassert(1 <= j && j <= m);
167.87 + /* determine the ordinal number of basic auxiliary or structural
167.88 + variable x[k] corresponding to basic variable xB[j] */
167.89 + k = lp->head[j];
167.90 + /* build j-th column of the basic matrix, which is k-th column of
167.91 + the scaled augmented matrix (I | -R*A*S) */
167.92 + if (k <= m)
167.93 + { /* x[k] is auxiliary variable */
167.94 + len = 1;
167.95 + ind[1] = k;
167.96 + val[1] = 1.0;
167.97 + }
167.98 + else
167.99 + { /* x[k] is structural variable */
167.100 + len = 0;
167.101 + for (aij = lp->col[k-m]->ptr; aij != NULL; aij = aij->c_next)
167.102 + { len++;
167.103 + ind[len] = aij->row->i;
167.104 + val[len] = - aij->row->rii * aij->val * aij->col->sjj;
167.105 + }
167.106 + }
167.107 + return len;
167.108 +}
167.109 +
167.110 +static void copy_bfcp(glp_prob *lp);
167.111 +
167.112 +int glp_factorize(glp_prob *lp)
167.113 +{ int m = lp->m;
167.114 + int n = lp->n;
167.115 + GLPROW **row = lp->row;
167.116 + GLPCOL **col = lp->col;
167.117 + int *head = lp->head;
167.118 + int j, k, stat, ret;
167.119 + /* invalidate the basis factorization */
167.120 + lp->valid = 0;
167.121 + /* build the basis header */
167.122 + j = 0;
167.123 + for (k = 1; k <= m+n; k++)
167.124 + { if (k <= m)
167.125 + { stat = row[k]->stat;
167.126 + row[k]->bind = 0;
167.127 + }
167.128 + else
167.129 + { stat = col[k-m]->stat;
167.130 + col[k-m]->bind = 0;
167.131 + }
167.132 + if (stat == GLP_BS)
167.133 + { j++;
167.134 + if (j > m)
167.135 + { /* too many basic variables */
167.136 + ret = GLP_EBADB;
167.137 + goto fini;
167.138 + }
167.139 + head[j] = k;
167.140 + if (k <= m)
167.141 + row[k]->bind = j;
167.142 + else
167.143 + col[k-m]->bind = j;
167.144 + }
167.145 + }
167.146 + if (j < m)
167.147 + { /* too few basic variables */
167.148 + ret = GLP_EBADB;
167.149 + goto fini;
167.150 + }
167.151 + /* try to factorize the basis matrix */
167.152 + if (m > 0)
167.153 + { if (lp->bfd == NULL)
167.154 + { lp->bfd = bfd_create_it();
167.155 + copy_bfcp(lp);
167.156 + }
167.157 + switch (bfd_factorize(lp->bfd, m, lp->head, b_col, lp))
167.158 + { case 0:
167.159 + /* ok */
167.160 + break;
167.161 + case BFD_ESING:
167.162 + /* singular matrix */
167.163 + ret = GLP_ESING;
167.164 + goto fini;
167.165 + case BFD_ECOND:
167.166 + /* ill-conditioned matrix */
167.167 + ret = GLP_ECOND;
167.168 + goto fini;
167.169 + default:
167.170 + xassert(lp != lp);
167.171 + }
167.172 + lp->valid = 1;
167.173 + }
167.174 + /* factorization successful */
167.175 + ret = 0;
167.176 +fini: /* bring the return code to the calling program */
167.177 + return ret;
167.178 +}
167.179 +
167.180 +/***********************************************************************
167.181 +* NAME
167.182 +*
167.183 +* glp_bf_updated - check if the basis factorization has been updated
167.184 +*
167.185 +* SYNOPSIS
167.186 +*
167.187 +* int glp_bf_updated(glp_prob *lp);
167.188 +*
167.189 +* RETURNS
167.190 +*
167.191 +* If the basis factorization has been just computed from scratch, the
167.192 +* routine glp_bf_updated returns zero. Otherwise, if the factorization
167.193 +* has been updated one or more times, the routine returns non-zero. */
167.194 +
167.195 +int glp_bf_updated(glp_prob *lp)
167.196 +{ int cnt;
167.197 + if (!(lp->m == 0 || lp->valid))
167.198 + xerror("glp_bf_update: basis factorization does not exist\n");
167.199 +#if 0 /* 15/XI-2009 */
167.200 + cnt = (lp->m == 0 ? 0 : lp->bfd->upd_cnt);
167.201 +#else
167.202 + cnt = (lp->m == 0 ? 0 : bfd_get_count(lp->bfd));
167.203 +#endif
167.204 + return cnt;
167.205 +}
167.206 +
167.207 +/***********************************************************************
167.208 +* NAME
167.209 +*
167.210 +* glp_get_bfcp - retrieve basis factorization control parameters
167.211 +*
167.212 +* SYNOPSIS
167.213 +*
167.214 +* void glp_get_bfcp(glp_prob *lp, glp_bfcp *parm);
167.215 +*
167.216 +* DESCRIPTION
167.217 +*
167.218 +* The routine glp_get_bfcp retrieves control parameters, which are
167.219 +* used on computing and updating the basis factorization associated
167.220 +* with the specified problem object.
167.221 +*
167.222 +* Current values of control parameters are stored by the routine in
167.223 +* a glp_bfcp structure, which the parameter parm points to. */
167.224 +
167.225 +void glp_get_bfcp(glp_prob *lp, glp_bfcp *parm)
167.226 +{ glp_bfcp *bfcp = lp->bfcp;
167.227 + if (bfcp == NULL)
167.228 + { parm->type = GLP_BF_FT;
167.229 + parm->lu_size = 0;
167.230 + parm->piv_tol = 0.10;
167.231 + parm->piv_lim = 4;
167.232 + parm->suhl = GLP_ON;
167.233 + parm->eps_tol = 1e-15;
167.234 + parm->max_gro = 1e+10;
167.235 + parm->nfs_max = 100;
167.236 + parm->upd_tol = 1e-6;
167.237 + parm->nrs_max = 100;
167.238 + parm->rs_size = 0;
167.239 + }
167.240 + else
167.241 + memcpy(parm, bfcp, sizeof(glp_bfcp));
167.242 + return;
167.243 +}
167.244 +
167.245 +/***********************************************************************
167.246 +* NAME
167.247 +*
167.248 +* glp_set_bfcp - change basis factorization control parameters
167.249 +*
167.250 +* SYNOPSIS
167.251 +*
167.252 +* void glp_set_bfcp(glp_prob *lp, const glp_bfcp *parm);
167.253 +*
167.254 +* DESCRIPTION
167.255 +*
167.256 +* The routine glp_set_bfcp changes control parameters, which are used
167.257 +* by internal GLPK routines in computing and updating the basis
167.258 +* factorization associated with the specified problem object.
167.259 +*
167.260 +* New values of the control parameters should be passed in a structure
167.261 +* glp_bfcp, which the parameter parm points to.
167.262 +*
167.263 +* The parameter parm can be specified as NULL, in which case all
167.264 +* control parameters are reset to their default values. */
167.265 +
167.266 +#if 0 /* 15/XI-2009 */
167.267 +static void copy_bfcp(glp_prob *lp)
167.268 +{ glp_bfcp _parm, *parm = &_parm;
167.269 + BFD *bfd = lp->bfd;
167.270 + glp_get_bfcp(lp, parm);
167.271 + xassert(bfd != NULL);
167.272 + bfd->type = parm->type;
167.273 + bfd->lu_size = parm->lu_size;
167.274 + bfd->piv_tol = parm->piv_tol;
167.275 + bfd->piv_lim = parm->piv_lim;
167.276 + bfd->suhl = parm->suhl;
167.277 + bfd->eps_tol = parm->eps_tol;
167.278 + bfd->max_gro = parm->max_gro;
167.279 + bfd->nfs_max = parm->nfs_max;
167.280 + bfd->upd_tol = parm->upd_tol;
167.281 + bfd->nrs_max = parm->nrs_max;
167.282 + bfd->rs_size = parm->rs_size;
167.283 + return;
167.284 +}
167.285 +#else
167.286 +static void copy_bfcp(glp_prob *lp)
167.287 +{ glp_bfcp _parm, *parm = &_parm;
167.288 + glp_get_bfcp(lp, parm);
167.289 + bfd_set_parm(lp->bfd, parm);
167.290 + return;
167.291 +}
167.292 +#endif
167.293 +
167.294 +void glp_set_bfcp(glp_prob *lp, const glp_bfcp *parm)
167.295 +{ glp_bfcp *bfcp = lp->bfcp;
167.296 + if (parm == NULL)
167.297 + { /* reset to default values */
167.298 + if (bfcp != NULL)
167.299 + xfree(bfcp), lp->bfcp = NULL;
167.300 + }
167.301 + else
167.302 + { /* set to specified values */
167.303 + if (bfcp == NULL)
167.304 + bfcp = lp->bfcp = xmalloc(sizeof(glp_bfcp));
167.305 + memcpy(bfcp, parm, sizeof(glp_bfcp));
167.306 + if (!(bfcp->type == GLP_BF_FT || bfcp->type == GLP_BF_BG ||
167.307 + bfcp->type == GLP_BF_GR))
167.308 + xerror("glp_set_bfcp: type = %d; invalid parameter\n",
167.309 + bfcp->type);
167.310 + if (bfcp->lu_size < 0)
167.311 + xerror("glp_set_bfcp: lu_size = %d; invalid parameter\n",
167.312 + bfcp->lu_size);
167.313 + if (!(0.0 < bfcp->piv_tol && bfcp->piv_tol < 1.0))
167.314 + xerror("glp_set_bfcp: piv_tol = %g; invalid parameter\n",
167.315 + bfcp->piv_tol);
167.316 + if (bfcp->piv_lim < 1)
167.317 + xerror("glp_set_bfcp: piv_lim = %d; invalid parameter\n",
167.318 + bfcp->piv_lim);
167.319 + if (!(bfcp->suhl == GLP_ON || bfcp->suhl == GLP_OFF))
167.320 + xerror("glp_set_bfcp: suhl = %d; invalid parameter\n",
167.321 + bfcp->suhl);
167.322 + if (!(0.0 <= bfcp->eps_tol && bfcp->eps_tol <= 1e-6))
167.323 + xerror("glp_set_bfcp: eps_tol = %g; invalid parameter\n",
167.324 + bfcp->eps_tol);
167.325 + if (bfcp->max_gro < 1.0)
167.326 + xerror("glp_set_bfcp: max_gro = %g; invalid parameter\n",
167.327 + bfcp->max_gro);
167.328 + if (!(1 <= bfcp->nfs_max && bfcp->nfs_max <= 32767))
167.329 + xerror("glp_set_bfcp: nfs_max = %d; invalid parameter\n",
167.330 + bfcp->nfs_max);
167.331 + if (!(0.0 < bfcp->upd_tol && bfcp->upd_tol < 1.0))
167.332 + xerror("glp_set_bfcp: upd_tol = %g; invalid parameter\n",
167.333 + bfcp->upd_tol);
167.334 + if (!(1 <= bfcp->nrs_max && bfcp->nrs_max <= 32767))
167.335 + xerror("glp_set_bfcp: nrs_max = %d; invalid parameter\n",
167.336 + bfcp->nrs_max);
167.337 + if (bfcp->rs_size < 0)
167.338 + xerror("glp_set_bfcp: rs_size = %d; invalid parameter\n",
167.339 + bfcp->nrs_max);
167.340 + if (bfcp->rs_size == 0)
167.341 + bfcp->rs_size = 20 * bfcp->nrs_max;
167.342 + }
167.343 + if (lp->bfd != NULL) copy_bfcp(lp);
167.344 + return;
167.345 +}
167.346 +
167.347 +/***********************************************************************
167.348 +* NAME
167.349 +*
167.350 +* glp_get_bhead - retrieve the basis header information
167.351 +*
167.352 +* SYNOPSIS
167.353 +*
167.354 +* int glp_get_bhead(glp_prob *lp, int k);
167.355 +*
167.356 +* DESCRIPTION
167.357 +*
167.358 +* The routine glp_get_bhead returns the basis header information for
167.359 +* the current basis associated with the specified problem object.
167.360 +*
167.361 +* RETURNS
167.362 +*
167.363 +* If xB[k], 1 <= k <= m, is i-th auxiliary variable (1 <= i <= m), the
167.364 +* routine returns i. Otherwise, if xB[k] is j-th structural variable
167.365 +* (1 <= j <= n), the routine returns m+j. Here m is the number of rows
167.366 +* and n is the number of columns in the problem object. */
167.367 +
167.368 +int glp_get_bhead(glp_prob *lp, int k)
167.369 +{ if (!(lp->m == 0 || lp->valid))
167.370 + xerror("glp_get_bhead: basis factorization does not exist\n");
167.371 + if (!(1 <= k && k <= lp->m))
167.372 + xerror("glp_get_bhead: k = %d; index out of range\n", k);
167.373 + return lp->head[k];
167.374 +}
167.375 +
167.376 +/***********************************************************************
167.377 +* NAME
167.378 +*
167.379 +* glp_get_row_bind - retrieve row index in the basis header
167.380 +*
167.381 +* SYNOPSIS
167.382 +*
167.383 +* int glp_get_row_bind(glp_prob *lp, int i);
167.384 +*
167.385 +* RETURNS
167.386 +*
167.387 +* The routine glp_get_row_bind returns the index k of basic variable
167.388 +* xB[k], 1 <= k <= m, which is i-th auxiliary variable, 1 <= i <= m,
167.389 +* in the current basis associated with the specified problem object,
167.390 +* where m is the number of rows. However, if i-th auxiliary variable
167.391 +* is non-basic, the routine returns zero. */
167.392 +
167.393 +int glp_get_row_bind(glp_prob *lp, int i)
167.394 +{ if (!(lp->m == 0 || lp->valid))
167.395 + xerror("glp_get_row_bind: basis factorization does not exist\n"
167.396 + );
167.397 + if (!(1 <= i && i <= lp->m))
167.398 + xerror("glp_get_row_bind: i = %d; row number out of range\n",
167.399 + i);
167.400 + return lp->row[i]->bind;
167.401 +}
167.402 +
167.403 +/***********************************************************************
167.404 +* NAME
167.405 +*
167.406 +* glp_get_col_bind - retrieve column index in the basis header
167.407 +*
167.408 +* SYNOPSIS
167.409 +*
167.410 +* int glp_get_col_bind(glp_prob *lp, int j);
167.411 +*
167.412 +* RETURNS
167.413 +*
167.414 +* The routine glp_get_col_bind returns the index k of basic variable
167.415 +* xB[k], 1 <= k <= m, which is j-th structural variable, 1 <= j <= n,
167.416 +* in the current basis associated with the specified problem object,
167.417 +* where m is the number of rows, n is the number of columns. However,
167.418 +* if j-th structural variable is non-basic, the routine returns zero.*/
167.419 +
167.420 +int glp_get_col_bind(glp_prob *lp, int j)
167.421 +{ if (!(lp->m == 0 || lp->valid))
167.422 + xerror("glp_get_col_bind: basis factorization does not exist\n"
167.423 + );
167.424 + if (!(1 <= j && j <= lp->n))
167.425 + xerror("glp_get_col_bind: j = %d; column number out of range\n"
167.426 + , j);
167.427 + return lp->col[j]->bind;
167.428 +}
167.429 +
167.430 +/***********************************************************************
167.431 +* NAME
167.432 +*
167.433 +* glp_ftran - perform forward transformation (solve system B*x = b)
167.434 +*
167.435 +* SYNOPSIS
167.436 +*
167.437 +* void glp_ftran(glp_prob *lp, double x[]);
167.438 +*
167.439 +* DESCRIPTION
167.440 +*
167.441 +* The routine glp_ftran performs forward transformation, i.e. solves
167.442 +* the system B*x = b, where B is the basis matrix corresponding to the
167.443 +* current basis for the specified problem object, x is the vector of
167.444 +* unknowns to be computed, b is the vector of right-hand sides.
167.445 +*
167.446 +* On entry elements of the vector b should be stored in dense format
167.447 +* in locations x[1], ..., x[m], where m is the number of rows. On exit
167.448 +* the routine stores elements of the vector x in the same locations.
167.449 +*
167.450 +* SCALING/UNSCALING
167.451 +*
167.452 +* Let A~ = (I | -A) is the augmented constraint matrix of the original
167.453 +* (unscaled) problem. In the scaled LP problem instead the matrix A the
167.454 +* scaled matrix A" = R*A*S is actually used, so
167.455 +*
167.456 +* A~" = (I | A") = (I | R*A*S) = (R*I*inv(R) | R*A*S) =
167.457 +* (1)
167.458 +* = R*(I | A)*S~ = R*A~*S~,
167.459 +*
167.460 +* is the scaled augmented constraint matrix, where R and S are diagonal
167.461 +* scaling matrices used to scale rows and columns of the matrix A, and
167.462 +*
167.463 +* S~ = diag(inv(R) | S) (2)
167.464 +*
167.465 +* is an augmented diagonal scaling matrix.
167.466 +*
167.467 +* By definition:
167.468 +*
167.469 +* A~ = (B | N), (3)
167.470 +*
167.471 +* where B is the basic matrix, which consists of basic columns of the
167.472 +* augmented constraint matrix A~, and N is a matrix, which consists of
167.473 +* non-basic columns of A~. From (1) it follows that:
167.474 +*
167.475 +* A~" = (B" | N") = (R*B*SB | R*N*SN), (4)
167.476 +*
167.477 +* where SB and SN are parts of the augmented scaling matrix S~, which
167.478 +* correspond to basic and non-basic variables, respectively. Therefore
167.479 +*
167.480 +* B" = R*B*SB, (5)
167.481 +*
167.482 +* which is the scaled basis matrix. */
167.483 +
167.484 +void glp_ftran(glp_prob *lp, double x[])
167.485 +{ int m = lp->m;
167.486 + GLPROW **row = lp->row;
167.487 + GLPCOL **col = lp->col;
167.488 + int i, k;
167.489 + /* B*x = b ===> (R*B*SB)*(inv(SB)*x) = R*b ===>
167.490 + B"*x" = b", where b" = R*b, x = SB*x" */
167.491 + if (!(m == 0 || lp->valid))
167.492 + xerror("glp_ftran: basis factorization does not exist\n");
167.493 + /* b" := R*b */
167.494 + for (i = 1; i <= m; i++)
167.495 + x[i] *= row[i]->rii;
167.496 + /* x" := inv(B")*b" */
167.497 + if (m > 0) bfd_ftran(lp->bfd, x);
167.498 + /* x := SB*x" */
167.499 + for (i = 1; i <= m; i++)
167.500 + { k = lp->head[i];
167.501 + if (k <= m)
167.502 + x[i] /= row[k]->rii;
167.503 + else
167.504 + x[i] *= col[k-m]->sjj;
167.505 + }
167.506 + return;
167.507 +}
167.508 +
167.509 +/***********************************************************************
167.510 +* NAME
167.511 +*
167.512 +* glp_btran - perform backward transformation (solve system B'*x = b)
167.513 +*
167.514 +* SYNOPSIS
167.515 +*
167.516 +* void glp_btran(glp_prob *lp, double x[]);
167.517 +*
167.518 +* DESCRIPTION
167.519 +*
167.520 +* The routine glp_btran performs backward transformation, i.e. solves
167.521 +* the system B'*x = b, where B' is a matrix transposed to the basis
167.522 +* matrix corresponding to the current basis for the specified problem
167.523 +* problem object, x is the vector of unknowns to be computed, b is the
167.524 +* vector of right-hand sides.
167.525 +*
167.526 +* On entry elements of the vector b should be stored in dense format
167.527 +* in locations x[1], ..., x[m], where m is the number of rows. On exit
167.528 +* the routine stores elements of the vector x in the same locations.
167.529 +*
167.530 +* SCALING/UNSCALING
167.531 +*
167.532 +* See comments to the routine glp_ftran. */
167.533 +
167.534 +void glp_btran(glp_prob *lp, double x[])
167.535 +{ int m = lp->m;
167.536 + GLPROW **row = lp->row;
167.537 + GLPCOL **col = lp->col;
167.538 + int i, k;
167.539 + /* B'*x = b ===> (SB*B'*R)*(inv(R)*x) = SB*b ===>
167.540 + (B")'*x" = b", where b" = SB*b, x = R*x" */
167.541 + if (!(m == 0 || lp->valid))
167.542 + xerror("glp_btran: basis factorization does not exist\n");
167.543 + /* b" := SB*b */
167.544 + for (i = 1; i <= m; i++)
167.545 + { k = lp->head[i];
167.546 + if (k <= m)
167.547 + x[i] /= row[k]->rii;
167.548 + else
167.549 + x[i] *= col[k-m]->sjj;
167.550 + }
167.551 + /* x" := inv[(B")']*b" */
167.552 + if (m > 0) bfd_btran(lp->bfd, x);
167.553 + /* x := R*x" */
167.554 + for (i = 1; i <= m; i++)
167.555 + x[i] *= row[i]->rii;
167.556 + return;
167.557 +}
167.558 +
167.559 +/***********************************************************************
167.560 +* NAME
167.561 +*
167.562 +* glp_warm_up - "warm up" LP basis
167.563 +*
167.564 +* SYNOPSIS
167.565 +*
167.566 +* int glp_warm_up(glp_prob *P);
167.567 +*
167.568 +* DESCRIPTION
167.569 +*
167.570 +* The routine glp_warm_up "warms up" the LP basis for the specified
167.571 +* problem object using current statuses assigned to rows and columns
167.572 +* (that is, to auxiliary and structural variables).
167.573 +*
167.574 +* This operation includes computing factorization of the basis matrix
167.575 +* (if it does not exist), computing primal and dual components of basic
167.576 +* solution, and determining the solution status.
167.577 +*
167.578 +* RETURNS
167.579 +*
167.580 +* 0 The operation has been successfully performed.
167.581 +*
167.582 +* GLP_EBADB
167.583 +* The basis matrix is invalid, i.e. the number of basic (auxiliary
167.584 +* and structural) variables differs from the number of rows in the
167.585 +* problem object.
167.586 +*
167.587 +* GLP_ESING
167.588 +* The basis matrix is singular within the working precision.
167.589 +*
167.590 +* GLP_ECOND
167.591 +* The basis matrix is ill-conditioned. */
167.592 +
167.593 +int glp_warm_up(glp_prob *P)
167.594 +{ GLPROW *row;
167.595 + GLPCOL *col;
167.596 + GLPAIJ *aij;
167.597 + int i, j, type, ret;
167.598 + double eps, temp, *work;
167.599 + /* invalidate basic solution */
167.600 + P->pbs_stat = P->dbs_stat = GLP_UNDEF;
167.601 + P->obj_val = 0.0;
167.602 + P->some = 0;
167.603 + for (i = 1; i <= P->m; i++)
167.604 + { row = P->row[i];
167.605 + row->prim = row->dual = 0.0;
167.606 + }
167.607 + for (j = 1; j <= P->n; j++)
167.608 + { col = P->col[j];
167.609 + col->prim = col->dual = 0.0;
167.610 + }
167.611 + /* compute the basis factorization, if necessary */
167.612 + if (!glp_bf_exists(P))
167.613 + { ret = glp_factorize(P);
167.614 + if (ret != 0) goto done;
167.615 + }
167.616 + /* allocate working array */
167.617 + work = xcalloc(1+P->m, sizeof(double));
167.618 + /* determine and store values of non-basic variables, compute
167.619 + vector (- N * xN) */
167.620 + for (i = 1; i <= P->m; i++)
167.621 + work[i] = 0.0;
167.622 + for (i = 1; i <= P->m; i++)
167.623 + { row = P->row[i];
167.624 + if (row->stat == GLP_BS)
167.625 + continue;
167.626 + else if (row->stat == GLP_NL)
167.627 + row->prim = row->lb;
167.628 + else if (row->stat == GLP_NU)
167.629 + row->prim = row->ub;
167.630 + else if (row->stat == GLP_NF)
167.631 + row->prim = 0.0;
167.632 + else if (row->stat == GLP_NS)
167.633 + row->prim = row->lb;
167.634 + else
167.635 + xassert(row != row);
167.636 + /* N[j] is i-th column of matrix (I|-A) */
167.637 + work[i] -= row->prim;
167.638 + }
167.639 + for (j = 1; j <= P->n; j++)
167.640 + { col = P->col[j];
167.641 + if (col->stat == GLP_BS)
167.642 + continue;
167.643 + else if (col->stat == GLP_NL)
167.644 + col->prim = col->lb;
167.645 + else if (col->stat == GLP_NU)
167.646 + col->prim = col->ub;
167.647 + else if (col->stat == GLP_NF)
167.648 + col->prim = 0.0;
167.649 + else if (col->stat == GLP_NS)
167.650 + col->prim = col->lb;
167.651 + else
167.652 + xassert(col != col);
167.653 + /* N[j] is (m+j)-th column of matrix (I|-A) */
167.654 + if (col->prim != 0.0)
167.655 + { for (aij = col->ptr; aij != NULL; aij = aij->c_next)
167.656 + work[aij->row->i] += aij->val * col->prim;
167.657 + }
167.658 + }
167.659 + /* compute vector of basic variables xB = - inv(B) * N * xN */
167.660 + glp_ftran(P, work);
167.661 + /* store values of basic variables, check primal feasibility */
167.662 + P->pbs_stat = GLP_FEAS;
167.663 + for (i = 1; i <= P->m; i++)
167.664 + { row = P->row[i];
167.665 + if (row->stat != GLP_BS)
167.666 + continue;
167.667 + row->prim = work[row->bind];
167.668 + type = row->type;
167.669 + if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
167.670 + { eps = 1e-6 + 1e-9 * fabs(row->lb);
167.671 + if (row->prim < row->lb - eps)
167.672 + P->pbs_stat = GLP_INFEAS;
167.673 + }
167.674 + if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
167.675 + { eps = 1e-6 + 1e-9 * fabs(row->ub);
167.676 + if (row->prim > row->ub + eps)
167.677 + P->pbs_stat = GLP_INFEAS;
167.678 + }
167.679 + }
167.680 + for (j = 1; j <= P->n; j++)
167.681 + { col = P->col[j];
167.682 + if (col->stat != GLP_BS)
167.683 + continue;
167.684 + col->prim = work[col->bind];
167.685 + type = col->type;
167.686 + if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
167.687 + { eps = 1e-6 + 1e-9 * fabs(col->lb);
167.688 + if (col->prim < col->lb - eps)
167.689 + P->pbs_stat = GLP_INFEAS;
167.690 + }
167.691 + if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
167.692 + { eps = 1e-6 + 1e-9 * fabs(col->ub);
167.693 + if (col->prim > col->ub + eps)
167.694 + P->pbs_stat = GLP_INFEAS;
167.695 + }
167.696 + }
167.697 + /* compute value of the objective function */
167.698 + P->obj_val = P->c0;
167.699 + for (j = 1; j <= P->n; j++)
167.700 + { col = P->col[j];
167.701 + P->obj_val += col->coef * col->prim;
167.702 + }
167.703 + /* build vector cB of objective coefficients at basic variables */
167.704 + for (i = 1; i <= P->m; i++)
167.705 + work[i] = 0.0;
167.706 + for (j = 1; j <= P->n; j++)
167.707 + { col = P->col[j];
167.708 + if (col->stat == GLP_BS)
167.709 + work[col->bind] = col->coef;
167.710 + }
167.711 + /* compute vector of simplex multipliers pi = inv(B') * cB */
167.712 + glp_btran(P, work);
167.713 + /* compute and store reduced costs of non-basic variables d[j] =
167.714 + c[j] - N'[j] * pi, check dual feasibility */
167.715 + P->dbs_stat = GLP_FEAS;
167.716 + for (i = 1; i <= P->m; i++)
167.717 + { row = P->row[i];
167.718 + if (row->stat == GLP_BS)
167.719 + { row->dual = 0.0;
167.720 + continue;
167.721 + }
167.722 + /* N[j] is i-th column of matrix (I|-A) */
167.723 + row->dual = - work[i];
167.724 + type = row->type;
167.725 + temp = (P->dir == GLP_MIN ? + row->dual : - row->dual);
167.726 + if ((type == GLP_FR || type == GLP_LO) && temp < -1e-5 ||
167.727 + (type == GLP_FR || type == GLP_UP) && temp > +1e-5)
167.728 + P->dbs_stat = GLP_INFEAS;
167.729 + }
167.730 + for (j = 1; j <= P->n; j++)
167.731 + { col = P->col[j];
167.732 + if (col->stat == GLP_BS)
167.733 + { col->dual = 0.0;
167.734 + continue;
167.735 + }
167.736 + /* N[j] is (m+j)-th column of matrix (I|-A) */
167.737 + col->dual = col->coef;
167.738 + for (aij = col->ptr; aij != NULL; aij = aij->c_next)
167.739 + col->dual += aij->val * work[aij->row->i];
167.740 + type = col->type;
167.741 + temp = (P->dir == GLP_MIN ? + col->dual : - col->dual);
167.742 + if ((type == GLP_FR || type == GLP_LO) && temp < -1e-5 ||
167.743 + (type == GLP_FR || type == GLP_UP) && temp > +1e-5)
167.744 + P->dbs_stat = GLP_INFEAS;
167.745 + }
167.746 + /* free working array */
167.747 + xfree(work);
167.748 + ret = 0;
167.749 +done: return ret;
167.750 +}
167.751 +
167.752 +/***********************************************************************
167.753 +* NAME
167.754 +*
167.755 +* glp_eval_tab_row - compute row of the simplex tableau
167.756 +*
167.757 +* SYNOPSIS
167.758 +*
167.759 +* int glp_eval_tab_row(glp_prob *lp, int k, int ind[], double val[]);
167.760 +*
167.761 +* DESCRIPTION
167.762 +*
167.763 +* The routine glp_eval_tab_row computes a row of the current simplex
167.764 +* tableau for the basic variable, which is specified by the number k:
167.765 +* if 1 <= k <= m, x[k] is k-th auxiliary variable; if m+1 <= k <= m+n,
167.766 +* x[k] is (k-m)-th structural variable, where m is number of rows, and
167.767 +* n is number of columns. The current basis must be available.
167.768 +*
167.769 +* The routine stores column indices and numerical values of non-zero
167.770 +* elements of the computed row using sparse format to the locations
167.771 +* ind[1], ..., ind[len] and val[1], ..., val[len], respectively, where
167.772 +* 0 <= len <= n is number of non-zeros returned on exit.
167.773 +*
167.774 +* Element indices stored in the array ind have the same sense as the
167.775 +* index k, i.e. indices 1 to m denote auxiliary variables and indices
167.776 +* m+1 to m+n denote structural ones (all these variables are obviously
167.777 +* non-basic by definition).
167.778 +*
167.779 +* The computed row shows how the specified basic variable x[k] = xB[i]
167.780 +* depends on non-basic variables:
167.781 +*
167.782 +* xB[i] = alfa[i,1]*xN[1] + alfa[i,2]*xN[2] + ... + alfa[i,n]*xN[n],
167.783 +*
167.784 +* where alfa[i,j] are elements of the simplex table row, xN[j] are
167.785 +* non-basic (auxiliary and structural) variables.
167.786 +*
167.787 +* RETURNS
167.788 +*
167.789 +* The routine returns number of non-zero elements in the simplex table
167.790 +* row stored in the arrays ind and val.
167.791 +*
167.792 +* BACKGROUND
167.793 +*
167.794 +* The system of equality constraints of the LP problem is:
167.795 +*
167.796 +* xR = A * xS, (1)
167.797 +*
167.798 +* where xR is the vector of auxliary variables, xS is the vector of
167.799 +* structural variables, A is the matrix of constraint coefficients.
167.800 +*
167.801 +* The system (1) can be written in homogenous form as follows:
167.802 +*
167.803 +* A~ * x = 0, (2)
167.804 +*
167.805 +* where A~ = (I | -A) is the augmented constraint matrix (has m rows
167.806 +* and m+n columns), x = (xR | xS) is the vector of all (auxiliary and
167.807 +* structural) variables.
167.808 +*
167.809 +* By definition for the current basis we have:
167.810 +*
167.811 +* A~ = (B | N), (3)
167.812 +*
167.813 +* where B is the basis matrix. Thus, the system (2) can be written as:
167.814 +*
167.815 +* B * xB + N * xN = 0. (4)
167.816 +*
167.817 +* From (4) it follows that:
167.818 +*
167.819 +* xB = A^ * xN, (5)
167.820 +*
167.821 +* where the matrix
167.822 +*
167.823 +* A^ = - inv(B) * N (6)
167.824 +*
167.825 +* is called the simplex table.
167.826 +*
167.827 +* It is understood that i-th row of the simplex table is:
167.828 +*
167.829 +* e * A^ = - e * inv(B) * N, (7)
167.830 +*
167.831 +* where e is a unity vector with e[i] = 1.
167.832 +*
167.833 +* To compute i-th row of the simplex table the routine first computes
167.834 +* i-th row of the inverse:
167.835 +*
167.836 +* rho = inv(B') * e, (8)
167.837 +*
167.838 +* where B' is a matrix transposed to B, and then computes elements of
167.839 +* i-th row of the simplex table as scalar products:
167.840 +*
167.841 +* alfa[i,j] = - rho * N[j] for all j, (9)
167.842 +*
167.843 +* where N[j] is a column of the augmented constraint matrix A~, which
167.844 +* corresponds to some non-basic auxiliary or structural variable. */
167.845 +
167.846 +int glp_eval_tab_row(glp_prob *lp, int k, int ind[], double val[])
167.847 +{ int m = lp->m;
167.848 + int n = lp->n;
167.849 + int i, t, len, lll, *iii;
167.850 + double alfa, *rho, *vvv;
167.851 + if (!(m == 0 || lp->valid))
167.852 + xerror("glp_eval_tab_row: basis factorization does not exist\n"
167.853 + );
167.854 + if (!(1 <= k && k <= m+n))
167.855 + xerror("glp_eval_tab_row: k = %d; variable number out of range"
167.856 + , k);
167.857 + /* determine xB[i] which corresponds to x[k] */
167.858 + if (k <= m)
167.859 + i = glp_get_row_bind(lp, k);
167.860 + else
167.861 + i = glp_get_col_bind(lp, k-m);
167.862 + if (i == 0)
167.863 + xerror("glp_eval_tab_row: k = %d; variable must be basic", k);
167.864 + xassert(1 <= i && i <= m);
167.865 + /* allocate working arrays */
167.866 + rho = xcalloc(1+m, sizeof(double));
167.867 + iii = xcalloc(1+m, sizeof(int));
167.868 + vvv = xcalloc(1+m, sizeof(double));
167.869 + /* compute i-th row of the inverse; see (8) */
167.870 + for (t = 1; t <= m; t++) rho[t] = 0.0;
167.871 + rho[i] = 1.0;
167.872 + glp_btran(lp, rho);
167.873 + /* compute i-th row of the simplex table */
167.874 + len = 0;
167.875 + for (k = 1; k <= m+n; k++)
167.876 + { if (k <= m)
167.877 + { /* x[k] is auxiliary variable, so N[k] is a unity column */
167.878 + if (glp_get_row_stat(lp, k) == GLP_BS) continue;
167.879 + /* compute alfa[i,j]; see (9) */
167.880 + alfa = - rho[k];
167.881 + }
167.882 + else
167.883 + { /* x[k] is structural variable, so N[k] is a column of the
167.884 + original constraint matrix A with negative sign */
167.885 + if (glp_get_col_stat(lp, k-m) == GLP_BS) continue;
167.886 + /* compute alfa[i,j]; see (9) */
167.887 + lll = glp_get_mat_col(lp, k-m, iii, vvv);
167.888 + alfa = 0.0;
167.889 + for (t = 1; t <= lll; t++) alfa += rho[iii[t]] * vvv[t];
167.890 + }
167.891 + /* store alfa[i,j] */
167.892 + if (alfa != 0.0) len++, ind[len] = k, val[len] = alfa;
167.893 + }
167.894 + xassert(len <= n);
167.895 + /* free working arrays */
167.896 + xfree(rho);
167.897 + xfree(iii);
167.898 + xfree(vvv);
167.899 + /* return to the calling program */
167.900 + return len;
167.901 +}
167.902 +
167.903 +/***********************************************************************
167.904 +* NAME
167.905 +*
167.906 +* glp_eval_tab_col - compute column of the simplex tableau
167.907 +*
167.908 +* SYNOPSIS
167.909 +*
167.910 +* int glp_eval_tab_col(glp_prob *lp, int k, int ind[], double val[]);
167.911 +*
167.912 +* DESCRIPTION
167.913 +*
167.914 +* The routine glp_eval_tab_col computes a column of the current simplex
167.915 +* table for the non-basic variable, which is specified by the number k:
167.916 +* if 1 <= k <= m, x[k] is k-th auxiliary variable; if m+1 <= k <= m+n,
167.917 +* x[k] is (k-m)-th structural variable, where m is number of rows, and
167.918 +* n is number of columns. The current basis must be available.
167.919 +*
167.920 +* The routine stores row indices and numerical values of non-zero
167.921 +* elements of the computed column using sparse format to the locations
167.922 +* ind[1], ..., ind[len] and val[1], ..., val[len] respectively, where
167.923 +* 0 <= len <= m is number of non-zeros returned on exit.
167.924 +*
167.925 +* Element indices stored in the array ind have the same sense as the
167.926 +* index k, i.e. indices 1 to m denote auxiliary variables and indices
167.927 +* m+1 to m+n denote structural ones (all these variables are obviously
167.928 +* basic by the definition).
167.929 +*
167.930 +* The computed column shows how basic variables depend on the specified
167.931 +* non-basic variable x[k] = xN[j]:
167.932 +*
167.933 +* xB[1] = ... + alfa[1,j]*xN[j] + ...
167.934 +* xB[2] = ... + alfa[2,j]*xN[j] + ...
167.935 +* . . . . . .
167.936 +* xB[m] = ... + alfa[m,j]*xN[j] + ...
167.937 +*
167.938 +* where alfa[i,j] are elements of the simplex table column, xB[i] are
167.939 +* basic (auxiliary and structural) variables.
167.940 +*
167.941 +* RETURNS
167.942 +*
167.943 +* The routine returns number of non-zero elements in the simplex table
167.944 +* column stored in the arrays ind and val.
167.945 +*
167.946 +* BACKGROUND
167.947 +*
167.948 +* As it was explained in comments to the routine glp_eval_tab_row (see
167.949 +* above) the simplex table is the following matrix:
167.950 +*
167.951 +* A^ = - inv(B) * N. (1)
167.952 +*
167.953 +* Therefore j-th column of the simplex table is:
167.954 +*
167.955 +* A^ * e = - inv(B) * N * e = - inv(B) * N[j], (2)
167.956 +*
167.957 +* where e is a unity vector with e[j] = 1, B is the basis matrix, N[j]
167.958 +* is a column of the augmented constraint matrix A~, which corresponds
167.959 +* to the given non-basic auxiliary or structural variable. */
167.960 +
167.961 +int glp_eval_tab_col(glp_prob *lp, int k, int ind[], double val[])
167.962 +{ int m = lp->m;
167.963 + int n = lp->n;
167.964 + int t, len, stat;
167.965 + double *col;
167.966 + if (!(m == 0 || lp->valid))
167.967 + xerror("glp_eval_tab_col: basis factorization does not exist\n"
167.968 + );
167.969 + if (!(1 <= k && k <= m+n))
167.970 + xerror("glp_eval_tab_col: k = %d; variable number out of range"
167.971 + , k);
167.972 + if (k <= m)
167.973 + stat = glp_get_row_stat(lp, k);
167.974 + else
167.975 + stat = glp_get_col_stat(lp, k-m);
167.976 + if (stat == GLP_BS)
167.977 + xerror("glp_eval_tab_col: k = %d; variable must be non-basic",
167.978 + k);
167.979 + /* obtain column N[k] with negative sign */
167.980 + col = xcalloc(1+m, sizeof(double));
167.981 + for (t = 1; t <= m; t++) col[t] = 0.0;
167.982 + if (k <= m)
167.983 + { /* x[k] is auxiliary variable, so N[k] is a unity column */
167.984 + col[k] = -1.0;
167.985 + }
167.986 + else
167.987 + { /* x[k] is structural variable, so N[k] is a column of the
167.988 + original constraint matrix A with negative sign */
167.989 + len = glp_get_mat_col(lp, k-m, ind, val);
167.990 + for (t = 1; t <= len; t++) col[ind[t]] = val[t];
167.991 + }
167.992 + /* compute column of the simplex table, which corresponds to the
167.993 + specified non-basic variable x[k] */
167.994 + glp_ftran(lp, col);
167.995 + len = 0;
167.996 + for (t = 1; t <= m; t++)
167.997 + { if (col[t] != 0.0)
167.998 + { len++;
167.999 + ind[len] = glp_get_bhead(lp, t);
167.1000 + val[len] = col[t];
167.1001 + }
167.1002 + }
167.1003 + xfree(col);
167.1004 + /* return to the calling program */
167.1005 + return len;
167.1006 +}
167.1007 +
167.1008 +/***********************************************************************
167.1009 +* NAME
167.1010 +*
167.1011 +* glp_transform_row - transform explicitly specified row
167.1012 +*
167.1013 +* SYNOPSIS
167.1014 +*
167.1015 +* int glp_transform_row(glp_prob *P, int len, int ind[], double val[]);
167.1016 +*
167.1017 +* DESCRIPTION
167.1018 +*
167.1019 +* The routine glp_transform_row performs the same operation as the
167.1020 +* routine glp_eval_tab_row with exception that the row to be
167.1021 +* transformed is specified explicitly as a sparse vector.
167.1022 +*
167.1023 +* The explicitly specified row may be thought as a linear form:
167.1024 +*
167.1025 +* x = a[1]*x[m+1] + a[2]*x[m+2] + ... + a[n]*x[m+n], (1)
167.1026 +*
167.1027 +* where x is an auxiliary variable for this row, a[j] are coefficients
167.1028 +* of the linear form, x[m+j] are structural variables.
167.1029 +*
167.1030 +* On entry column indices and numerical values of non-zero elements of
167.1031 +* the row should be stored in locations ind[1], ..., ind[len] and
167.1032 +* val[1], ..., val[len], where len is the number of non-zero elements.
167.1033 +*
167.1034 +* This routine uses the system of equality constraints and the current
167.1035 +* basis in order to express the auxiliary variable x in (1) through the
167.1036 +* current non-basic variables (as if the transformed row were added to
167.1037 +* the problem object and its auxiliary variable were basic), i.e. the
167.1038 +* resultant row has the form:
167.1039 +*
167.1040 +* x = alfa[1]*xN[1] + alfa[2]*xN[2] + ... + alfa[n]*xN[n], (2)
167.1041 +*
167.1042 +* where xN[j] are non-basic (auxiliary or structural) variables, n is
167.1043 +* the number of columns in the LP problem object.
167.1044 +*
167.1045 +* On exit the routine stores indices and numerical values of non-zero
167.1046 +* elements of the resultant row (2) in locations ind[1], ..., ind[len']
167.1047 +* and val[1], ..., val[len'], where 0 <= len' <= n is the number of
167.1048 +* non-zero elements in the resultant row returned by the routine. Note
167.1049 +* that indices (numbers) of non-basic variables stored in the array ind
167.1050 +* correspond to original ordinal numbers of variables: indices 1 to m
167.1051 +* mean auxiliary variables and indices m+1 to m+n mean structural ones.
167.1052 +*
167.1053 +* RETURNS
167.1054 +*
167.1055 +* The routine returns len', which is the number of non-zero elements in
167.1056 +* the resultant row stored in the arrays ind and val.
167.1057 +*
167.1058 +* BACKGROUND
167.1059 +*
167.1060 +* The explicitly specified row (1) is transformed in the same way as it
167.1061 +* were the objective function row.
167.1062 +*
167.1063 +* From (1) it follows that:
167.1064 +*
167.1065 +* x = aB * xB + aN * xN, (3)
167.1066 +*
167.1067 +* where xB is the vector of basic variables, xN is the vector of
167.1068 +* non-basic variables.
167.1069 +*
167.1070 +* The simplex table, which corresponds to the current basis, is:
167.1071 +*
167.1072 +* xB = [-inv(B) * N] * xN. (4)
167.1073 +*
167.1074 +* Therefore substituting xB from (4) to (3) we have:
167.1075 +*
167.1076 +* x = aB * [-inv(B) * N] * xN + aN * xN =
167.1077 +* (5)
167.1078 +* = rho * (-N) * xN + aN * xN = alfa * xN,
167.1079 +*
167.1080 +* where:
167.1081 +*
167.1082 +* rho = inv(B') * aB, (6)
167.1083 +*
167.1084 +* and
167.1085 +*
167.1086 +* alfa = aN + rho * (-N) (7)
167.1087 +*
167.1088 +* is the resultant row computed by the routine. */
167.1089 +
167.1090 +int glp_transform_row(glp_prob *P, int len, int ind[], double val[])
167.1091 +{ int i, j, k, m, n, t, lll, *iii;
167.1092 + double alfa, *a, *aB, *rho, *vvv;
167.1093 + if (!glp_bf_exists(P))
167.1094 + xerror("glp_transform_row: basis factorization does not exist "
167.1095 + "\n");
167.1096 + m = glp_get_num_rows(P);
167.1097 + n = glp_get_num_cols(P);
167.1098 + /* unpack the row to be transformed to the array a */
167.1099 + a = xcalloc(1+n, sizeof(double));
167.1100 + for (j = 1; j <= n; j++) a[j] = 0.0;
167.1101 + if (!(0 <= len && len <= n))
167.1102 + xerror("glp_transform_row: len = %d; invalid row length\n",
167.1103 + len);
167.1104 + for (t = 1; t <= len; t++)
167.1105 + { j = ind[t];
167.1106 + if (!(1 <= j && j <= n))
167.1107 + xerror("glp_transform_row: ind[%d] = %d; column index out o"
167.1108 + "f range\n", t, j);
167.1109 + if (val[t] == 0.0)
167.1110 + xerror("glp_transform_row: val[%d] = 0; zero coefficient no"
167.1111 + "t allowed\n", t);
167.1112 + if (a[j] != 0.0)
167.1113 + xerror("glp_transform_row: ind[%d] = %d; duplicate column i"
167.1114 + "ndices not allowed\n", t, j);
167.1115 + a[j] = val[t];
167.1116 + }
167.1117 + /* construct the vector aB */
167.1118 + aB = xcalloc(1+m, sizeof(double));
167.1119 + for (i = 1; i <= m; i++)
167.1120 + { k = glp_get_bhead(P, i);
167.1121 + /* xB[i] is k-th original variable */
167.1122 + xassert(1 <= k && k <= m+n);
167.1123 + aB[i] = (k <= m ? 0.0 : a[k-m]);
167.1124 + }
167.1125 + /* solve the system B'*rho = aB to compute the vector rho */
167.1126 + rho = aB, glp_btran(P, rho);
167.1127 + /* compute coefficients at non-basic auxiliary variables */
167.1128 + len = 0;
167.1129 + for (i = 1; i <= m; i++)
167.1130 + { if (glp_get_row_stat(P, i) != GLP_BS)
167.1131 + { alfa = - rho[i];
167.1132 + if (alfa != 0.0)
167.1133 + { len++;
167.1134 + ind[len] = i;
167.1135 + val[len] = alfa;
167.1136 + }
167.1137 + }
167.1138 + }
167.1139 + /* compute coefficients at non-basic structural variables */
167.1140 + iii = xcalloc(1+m, sizeof(int));
167.1141 + vvv = xcalloc(1+m, sizeof(double));
167.1142 + for (j = 1; j <= n; j++)
167.1143 + { if (glp_get_col_stat(P, j) != GLP_BS)
167.1144 + { alfa = a[j];
167.1145 + lll = glp_get_mat_col(P, j, iii, vvv);
167.1146 + for (t = 1; t <= lll; t++) alfa += vvv[t] * rho[iii[t]];
167.1147 + if (alfa != 0.0)
167.1148 + { len++;
167.1149 + ind[len] = m+j;
167.1150 + val[len] = alfa;
167.1151 + }
167.1152 + }
167.1153 + }
167.1154 + xassert(len <= n);
167.1155 + xfree(iii);
167.1156 + xfree(vvv);
167.1157 + xfree(aB);
167.1158 + xfree(a);
167.1159 + return len;
167.1160 +}
167.1161 +
167.1162 +/***********************************************************************
167.1163 +* NAME
167.1164 +*
167.1165 +* glp_transform_col - transform explicitly specified column
167.1166 +*
167.1167 +* SYNOPSIS
167.1168 +*
167.1169 +* int glp_transform_col(glp_prob *P, int len, int ind[], double val[]);
167.1170 +*
167.1171 +* DESCRIPTION
167.1172 +*
167.1173 +* The routine glp_transform_col performs the same operation as the
167.1174 +* routine glp_eval_tab_col with exception that the column to be
167.1175 +* transformed is specified explicitly as a sparse vector.
167.1176 +*
167.1177 +* The explicitly specified column may be thought as if it were added
167.1178 +* to the original system of equality constraints:
167.1179 +*
167.1180 +* x[1] = a[1,1]*x[m+1] + ... + a[1,n]*x[m+n] + a[1]*x
167.1181 +* x[2] = a[2,1]*x[m+1] + ... + a[2,n]*x[m+n] + a[2]*x (1)
167.1182 +* . . . . . . . . . . . . . . .
167.1183 +* x[m] = a[m,1]*x[m+1] + ... + a[m,n]*x[m+n] + a[m]*x
167.1184 +*
167.1185 +* where x[i] are auxiliary variables, x[m+j] are structural variables,
167.1186 +* x is a structural variable for the explicitly specified column, a[i]
167.1187 +* are constraint coefficients for x.
167.1188 +*
167.1189 +* On entry row indices and numerical values of non-zero elements of
167.1190 +* the column should be stored in locations ind[1], ..., ind[len] and
167.1191 +* val[1], ..., val[len], where len is the number of non-zero elements.
167.1192 +*
167.1193 +* This routine uses the system of equality constraints and the current
167.1194 +* basis in order to express the current basic variables through the
167.1195 +* structural variable x in (1) (as if the transformed column were added
167.1196 +* to the problem object and the variable x were non-basic), i.e. the
167.1197 +* resultant column has the form:
167.1198 +*
167.1199 +* xB[1] = ... + alfa[1]*x
167.1200 +* xB[2] = ... + alfa[2]*x (2)
167.1201 +* . . . . . .
167.1202 +* xB[m] = ... + alfa[m]*x
167.1203 +*
167.1204 +* where xB are basic (auxiliary and structural) variables, m is the
167.1205 +* number of rows in the problem object.
167.1206 +*
167.1207 +* On exit the routine stores indices and numerical values of non-zero
167.1208 +* elements of the resultant column (2) in locations ind[1], ...,
167.1209 +* ind[len'] and val[1], ..., val[len'], where 0 <= len' <= m is the
167.1210 +* number of non-zero element in the resultant column returned by the
167.1211 +* routine. Note that indices (numbers) of basic variables stored in
167.1212 +* the array ind correspond to original ordinal numbers of variables:
167.1213 +* indices 1 to m mean auxiliary variables and indices m+1 to m+n mean
167.1214 +* structural ones.
167.1215 +*
167.1216 +* RETURNS
167.1217 +*
167.1218 +* The routine returns len', which is the number of non-zero elements
167.1219 +* in the resultant column stored in the arrays ind and val.
167.1220 +*
167.1221 +* BACKGROUND
167.1222 +*
167.1223 +* The explicitly specified column (1) is transformed in the same way
167.1224 +* as any other column of the constraint matrix using the formula:
167.1225 +*
167.1226 +* alfa = inv(B) * a, (3)
167.1227 +*
167.1228 +* where alfa is the resultant column computed by the routine. */
167.1229 +
167.1230 +int glp_transform_col(glp_prob *P, int len, int ind[], double val[])
167.1231 +{ int i, m, t;
167.1232 + double *a, *alfa;
167.1233 + if (!glp_bf_exists(P))
167.1234 + xerror("glp_transform_col: basis factorization does not exist "
167.1235 + "\n");
167.1236 + m = glp_get_num_rows(P);
167.1237 + /* unpack the column to be transformed to the array a */
167.1238 + a = xcalloc(1+m, sizeof(double));
167.1239 + for (i = 1; i <= m; i++) a[i] = 0.0;
167.1240 + if (!(0 <= len && len <= m))
167.1241 + xerror("glp_transform_col: len = %d; invalid column length\n",
167.1242 + len);
167.1243 + for (t = 1; t <= len; t++)
167.1244 + { i = ind[t];
167.1245 + if (!(1 <= i && i <= m))
167.1246 + xerror("glp_transform_col: ind[%d] = %d; row index out of r"
167.1247 + "ange\n", t, i);
167.1248 + if (val[t] == 0.0)
167.1249 + xerror("glp_transform_col: val[%d] = 0; zero coefficient no"
167.1250 + "t allowed\n", t);
167.1251 + if (a[i] != 0.0)
167.1252 + xerror("glp_transform_col: ind[%d] = %d; duplicate row indi"
167.1253 + "ces not allowed\n", t, i);
167.1254 + a[i] = val[t];
167.1255 + }
167.1256 + /* solve the system B*a = alfa to compute the vector alfa */
167.1257 + alfa = a, glp_ftran(P, alfa);
167.1258 + /* store resultant coefficients */
167.1259 + len = 0;
167.1260 + for (i = 1; i <= m; i++)
167.1261 + { if (alfa[i] != 0.0)
167.1262 + { len++;
167.1263 + ind[len] = glp_get_bhead(P, i);
167.1264 + val[len] = alfa[i];
167.1265 + }
167.1266 + }
167.1267 + xfree(a);
167.1268 + return len;
167.1269 +}
167.1270 +
167.1271 +/***********************************************************************
167.1272 +* NAME
167.1273 +*
167.1274 +* glp_prim_rtest - perform primal ratio test
167.1275 +*
167.1276 +* SYNOPSIS
167.1277 +*
167.1278 +* int glp_prim_rtest(glp_prob *P, int len, const int ind[],
167.1279 +* const double val[], int dir, double eps);
167.1280 +*
167.1281 +* DESCRIPTION
167.1282 +*
167.1283 +* The routine glp_prim_rtest performs the primal ratio test using an
167.1284 +* explicitly specified column of the simplex table.
167.1285 +*
167.1286 +* The current basic solution associated with the LP problem object
167.1287 +* must be primal feasible.
167.1288 +*
167.1289 +* The explicitly specified column of the simplex table shows how the
167.1290 +* basic variables xB depend on some non-basic variable x (which is not
167.1291 +* necessarily presented in the problem object):
167.1292 +*
167.1293 +* xB[1] = ... + alfa[1] * x + ...
167.1294 +* xB[2] = ... + alfa[2] * x + ... (*)
167.1295 +* . . . . . . . .
167.1296 +* xB[m] = ... + alfa[m] * x + ...
167.1297 +*
167.1298 +* The column (*) is specifed on entry to the routine using the sparse
167.1299 +* format. Ordinal numbers of basic variables xB[i] should be placed in
167.1300 +* locations ind[1], ..., ind[len], where ordinal number 1 to m denote
167.1301 +* auxiliary variables, and ordinal numbers m+1 to m+n denote structural
167.1302 +* variables. The corresponding non-zero coefficients alfa[i] should be
167.1303 +* placed in locations val[1], ..., val[len]. The arrays ind and val are
167.1304 +* not changed on exit.
167.1305 +*
167.1306 +* The parameter dir specifies direction in which the variable x changes
167.1307 +* on entering the basis: +1 means increasing, -1 means decreasing.
167.1308 +*
167.1309 +* The parameter eps is an absolute tolerance (small positive number)
167.1310 +* used by the routine to skip small alfa[j] of the row (*).
167.1311 +*
167.1312 +* The routine determines which basic variable (among specified in
167.1313 +* ind[1], ..., ind[len]) should leave the basis in order to keep primal
167.1314 +* feasibility.
167.1315 +*
167.1316 +* RETURNS
167.1317 +*
167.1318 +* The routine glp_prim_rtest returns the index piv in the arrays ind
167.1319 +* and val corresponding to the pivot element chosen, 1 <= piv <= len.
167.1320 +* If the adjacent basic solution is primal unbounded and therefore the
167.1321 +* choice cannot be made, the routine returns zero.
167.1322 +*
167.1323 +* COMMENTS
167.1324 +*
167.1325 +* If the non-basic variable x is presented in the LP problem object,
167.1326 +* the column (*) can be computed with the routine glp_eval_tab_col;
167.1327 +* otherwise it can be computed with the routine glp_transform_col. */
167.1328 +
167.1329 +int glp_prim_rtest(glp_prob *P, int len, const int ind[],
167.1330 + const double val[], int dir, double eps)
167.1331 +{ int k, m, n, piv, t, type, stat;
167.1332 + double alfa, big, beta, lb, ub, temp, teta;
167.1333 + if (glp_get_prim_stat(P) != GLP_FEAS)
167.1334 + xerror("glp_prim_rtest: basic solution is not primal feasible "
167.1335 + "\n");
167.1336 + if (!(dir == +1 || dir == -1))
167.1337 + xerror("glp_prim_rtest: dir = %d; invalid parameter\n", dir);
167.1338 + if (!(0.0 < eps && eps < 1.0))
167.1339 + xerror("glp_prim_rtest: eps = %g; invalid parameter\n", eps);
167.1340 + m = glp_get_num_rows(P);
167.1341 + n = glp_get_num_cols(P);
167.1342 + /* initial settings */
167.1343 + piv = 0, teta = DBL_MAX, big = 0.0;
167.1344 + /* walk through the entries of the specified column */
167.1345 + for (t = 1; t <= len; t++)
167.1346 + { /* get the ordinal number of basic variable */
167.1347 + k = ind[t];
167.1348 + if (!(1 <= k && k <= m+n))
167.1349 + xerror("glp_prim_rtest: ind[%d] = %d; variable number out o"
167.1350 + "f range\n", t, k);
167.1351 + /* determine type, bounds, status and primal value of basic
167.1352 + variable xB[i] = x[k] in the current basic solution */
167.1353 + if (k <= m)
167.1354 + { type = glp_get_row_type(P, k);
167.1355 + lb = glp_get_row_lb(P, k);
167.1356 + ub = glp_get_row_ub(P, k);
167.1357 + stat = glp_get_row_stat(P, k);
167.1358 + beta = glp_get_row_prim(P, k);
167.1359 + }
167.1360 + else
167.1361 + { type = glp_get_col_type(P, k-m);
167.1362 + lb = glp_get_col_lb(P, k-m);
167.1363 + ub = glp_get_col_ub(P, k-m);
167.1364 + stat = glp_get_col_stat(P, k-m);
167.1365 + beta = glp_get_col_prim(P, k-m);
167.1366 + }
167.1367 + if (stat != GLP_BS)
167.1368 + xerror("glp_prim_rtest: ind[%d] = %d; non-basic variable no"
167.1369 + "t allowed\n", t, k);
167.1370 + /* determine influence coefficient at basic variable xB[i]
167.1371 + in the explicitly specified column and turn to the case of
167.1372 + increasing the variable x in order to simplify the program
167.1373 + logic */
167.1374 + alfa = (dir > 0 ? + val[t] : - val[t]);
167.1375 + /* analyze main cases */
167.1376 + if (type == GLP_FR)
167.1377 + { /* xB[i] is free variable */
167.1378 + continue;
167.1379 + }
167.1380 + else if (type == GLP_LO)
167.1381 +lo: { /* xB[i] has an lower bound */
167.1382 + if (alfa > - eps) continue;
167.1383 + temp = (lb - beta) / alfa;
167.1384 + }
167.1385 + else if (type == GLP_UP)
167.1386 +up: { /* xB[i] has an upper bound */
167.1387 + if (alfa < + eps) continue;
167.1388 + temp = (ub - beta) / alfa;
167.1389 + }
167.1390 + else if (type == GLP_DB)
167.1391 + { /* xB[i] has both lower and upper bounds */
167.1392 + if (alfa < 0.0) goto lo; else goto up;
167.1393 + }
167.1394 + else if (type == GLP_FX)
167.1395 + { /* xB[i] is fixed variable */
167.1396 + if (- eps < alfa && alfa < + eps) continue;
167.1397 + temp = 0.0;
167.1398 + }
167.1399 + else
167.1400 + xassert(type != type);
167.1401 + /* if the value of the variable xB[i] violates its lower or
167.1402 + upper bound (slightly, because the current basis is assumed
167.1403 + to be primal feasible), temp is negative; we can think this
167.1404 + happens due to round-off errors and the value is exactly on
167.1405 + the bound; this allows replacing temp by zero */
167.1406 + if (temp < 0.0) temp = 0.0;
167.1407 + /* apply the minimal ratio test */
167.1408 + if (teta > temp || teta == temp && big < fabs(alfa))
167.1409 + piv = t, teta = temp, big = fabs(alfa);
167.1410 + }
167.1411 + /* return index of the pivot element chosen */
167.1412 + return piv;
167.1413 +}
167.1414 +
167.1415 +/***********************************************************************
167.1416 +* NAME
167.1417 +*
167.1418 +* glp_dual_rtest - perform dual ratio test
167.1419 +*
167.1420 +* SYNOPSIS
167.1421 +*
167.1422 +* int glp_dual_rtest(glp_prob *P, int len, const int ind[],
167.1423 +* const double val[], int dir, double eps);
167.1424 +*
167.1425 +* DESCRIPTION
167.1426 +*
167.1427 +* The routine glp_dual_rtest performs the dual ratio test using an
167.1428 +* explicitly specified row of the simplex table.
167.1429 +*
167.1430 +* The current basic solution associated with the LP problem object
167.1431 +* must be dual feasible.
167.1432 +*
167.1433 +* The explicitly specified row of the simplex table is a linear form
167.1434 +* that shows how some basic variable x (which is not necessarily
167.1435 +* presented in the problem object) depends on non-basic variables xN:
167.1436 +*
167.1437 +* x = alfa[1] * xN[1] + alfa[2] * xN[2] + ... + alfa[n] * xN[n]. (*)
167.1438 +*
167.1439 +* The row (*) is specified on entry to the routine using the sparse
167.1440 +* format. Ordinal numbers of non-basic variables xN[j] should be placed
167.1441 +* in locations ind[1], ..., ind[len], where ordinal numbers 1 to m
167.1442 +* denote auxiliary variables, and ordinal numbers m+1 to m+n denote
167.1443 +* structural variables. The corresponding non-zero coefficients alfa[j]
167.1444 +* should be placed in locations val[1], ..., val[len]. The arrays ind
167.1445 +* and val are not changed on exit.
167.1446 +*
167.1447 +* The parameter dir specifies direction in which the variable x changes
167.1448 +* on leaving the basis: +1 means that x goes to its lower bound, and -1
167.1449 +* means that x goes to its upper bound.
167.1450 +*
167.1451 +* The parameter eps is an absolute tolerance (small positive number)
167.1452 +* used by the routine to skip small alfa[j] of the row (*).
167.1453 +*
167.1454 +* The routine determines which non-basic variable (among specified in
167.1455 +* ind[1], ..., ind[len]) should enter the basis in order to keep dual
167.1456 +* feasibility.
167.1457 +*
167.1458 +* RETURNS
167.1459 +*
167.1460 +* The routine glp_dual_rtest returns the index piv in the arrays ind
167.1461 +* and val corresponding to the pivot element chosen, 1 <= piv <= len.
167.1462 +* If the adjacent basic solution is dual unbounded and therefore the
167.1463 +* choice cannot be made, the routine returns zero.
167.1464 +*
167.1465 +* COMMENTS
167.1466 +*
167.1467 +* If the basic variable x is presented in the LP problem object, the
167.1468 +* row (*) can be computed with the routine glp_eval_tab_row; otherwise
167.1469 +* it can be computed with the routine glp_transform_row. */
167.1470 +
167.1471 +int glp_dual_rtest(glp_prob *P, int len, const int ind[],
167.1472 + const double val[], int dir, double eps)
167.1473 +{ int k, m, n, piv, t, stat;
167.1474 + double alfa, big, cost, obj, temp, teta;
167.1475 + if (glp_get_dual_stat(P) != GLP_FEAS)
167.1476 + xerror("glp_dual_rtest: basic solution is not dual feasible\n")
167.1477 + ;
167.1478 + if (!(dir == +1 || dir == -1))
167.1479 + xerror("glp_dual_rtest: dir = %d; invalid parameter\n", dir);
167.1480 + if (!(0.0 < eps && eps < 1.0))
167.1481 + xerror("glp_dual_rtest: eps = %g; invalid parameter\n", eps);
167.1482 + m = glp_get_num_rows(P);
167.1483 + n = glp_get_num_cols(P);
167.1484 + /* take into account optimization direction */
167.1485 + obj = (glp_get_obj_dir(P) == GLP_MIN ? +1.0 : -1.0);
167.1486 + /* initial settings */
167.1487 + piv = 0, teta = DBL_MAX, big = 0.0;
167.1488 + /* walk through the entries of the specified row */
167.1489 + for (t = 1; t <= len; t++)
167.1490 + { /* get ordinal number of non-basic variable */
167.1491 + k = ind[t];
167.1492 + if (!(1 <= k && k <= m+n))
167.1493 + xerror("glp_dual_rtest: ind[%d] = %d; variable number out o"
167.1494 + "f range\n", t, k);
167.1495 + /* determine status and reduced cost of non-basic variable
167.1496 + x[k] = xN[j] in the current basic solution */
167.1497 + if (k <= m)
167.1498 + { stat = glp_get_row_stat(P, k);
167.1499 + cost = glp_get_row_dual(P, k);
167.1500 + }
167.1501 + else
167.1502 + { stat = glp_get_col_stat(P, k-m);
167.1503 + cost = glp_get_col_dual(P, k-m);
167.1504 + }
167.1505 + if (stat == GLP_BS)
167.1506 + xerror("glp_dual_rtest: ind[%d] = %d; basic variable not al"
167.1507 + "lowed\n", t, k);
167.1508 + /* determine influence coefficient at non-basic variable xN[j]
167.1509 + in the explicitly specified row and turn to the case of
167.1510 + increasing the variable x in order to simplify the program
167.1511 + logic */
167.1512 + alfa = (dir > 0 ? + val[t] : - val[t]);
167.1513 + /* analyze main cases */
167.1514 + if (stat == GLP_NL)
167.1515 + { /* xN[j] is on its lower bound */
167.1516 + if (alfa < + eps) continue;
167.1517 + temp = (obj * cost) / alfa;
167.1518 + }
167.1519 + else if (stat == GLP_NU)
167.1520 + { /* xN[j] is on its upper bound */
167.1521 + if (alfa > - eps) continue;
167.1522 + temp = (obj * cost) / alfa;
167.1523 + }
167.1524 + else if (stat == GLP_NF)
167.1525 + { /* xN[j] is non-basic free variable */
167.1526 + if (- eps < alfa && alfa < + eps) continue;
167.1527 + temp = 0.0;
167.1528 + }
167.1529 + else if (stat == GLP_NS)
167.1530 + { /* xN[j] is non-basic fixed variable */
167.1531 + continue;
167.1532 + }
167.1533 + else
167.1534 + xassert(stat != stat);
167.1535 + /* if the reduced cost of the variable xN[j] violates its zero
167.1536 + bound (slightly, because the current basis is assumed to be
167.1537 + dual feasible), temp is negative; we can think this happens
167.1538 + due to round-off errors and the reduced cost is exact zero;
167.1539 + this allows replacing temp by zero */
167.1540 + if (temp < 0.0) temp = 0.0;
167.1541 + /* apply the minimal ratio test */
167.1542 + if (teta > temp || teta == temp && big < fabs(alfa))
167.1543 + piv = t, teta = temp, big = fabs(alfa);
167.1544 + }
167.1545 + /* return index of the pivot element chosen */
167.1546 + return piv;
167.1547 +}
167.1548 +
167.1549 +/***********************************************************************
167.1550 +* NAME
167.1551 +*
167.1552 +* glp_analyze_row - simulate one iteration of dual simplex method
167.1553 +*
167.1554 +* SYNOPSIS
167.1555 +*
167.1556 +* int glp_analyze_row(glp_prob *P, int len, const int ind[],
167.1557 +* const double val[], int type, double rhs, double eps, int *piv,
167.1558 +* double *x, double *dx, double *y, double *dy, double *dz);
167.1559 +*
167.1560 +* DESCRIPTION
167.1561 +*
167.1562 +* Let the current basis be optimal or dual feasible, and there be
167.1563 +* specified a row (constraint), which is violated by the current basic
167.1564 +* solution. The routine glp_analyze_row simulates one iteration of the
167.1565 +* dual simplex method to determine some information on the adjacent
167.1566 +* basis (see below), where the specified row becomes active constraint
167.1567 +* (i.e. its auxiliary variable becomes non-basic).
167.1568 +*
167.1569 +* The current basic solution associated with the problem object passed
167.1570 +* to the routine must be dual feasible, and its primal components must
167.1571 +* be defined.
167.1572 +*
167.1573 +* The row to be analyzed must be previously transformed either with
167.1574 +* the routine glp_eval_tab_row (if the row is in the problem object)
167.1575 +* or with the routine glp_transform_row (if the row is external, i.e.
167.1576 +* not in the problem object). This is needed to express the row only
167.1577 +* through (auxiliary and structural) variables, which are non-basic in
167.1578 +* the current basis:
167.1579 +*
167.1580 +* y = alfa[1] * xN[1] + alfa[2] * xN[2] + ... + alfa[n] * xN[n],
167.1581 +*
167.1582 +* where y is an auxiliary variable of the row, alfa[j] is an influence
167.1583 +* coefficient, xN[j] is a non-basic variable.
167.1584 +*
167.1585 +* The row is passed to the routine in sparse format. Ordinal numbers
167.1586 +* of non-basic variables are stored in locations ind[1], ..., ind[len],
167.1587 +* where numbers 1 to m denote auxiliary variables while numbers m+1 to
167.1588 +* m+n denote structural variables. Corresponding non-zero coefficients
167.1589 +* alfa[j] are stored in locations val[1], ..., val[len]. The arrays
167.1590 +* ind and val are ot changed on exit.
167.1591 +*
167.1592 +* The parameters type and rhs specify the row type and its right-hand
167.1593 +* side as follows:
167.1594 +*
167.1595 +* type = GLP_LO: y = sum alfa[j] * xN[j] >= rhs
167.1596 +*
167.1597 +* type = GLP_UP: y = sum alfa[j] * xN[j] <= rhs
167.1598 +*
167.1599 +* The parameter eps is an absolute tolerance (small positive number)
167.1600 +* used by the routine to skip small coefficients alfa[j] on performing
167.1601 +* the dual ratio test.
167.1602 +*
167.1603 +* If the operation was successful, the routine stores the following
167.1604 +* information to corresponding location (if some parameter is NULL,
167.1605 +* its value is not stored):
167.1606 +*
167.1607 +* piv index in the array ind and val, 1 <= piv <= len, determining
167.1608 +* the non-basic variable, which would enter the adjacent basis;
167.1609 +*
167.1610 +* x value of the non-basic variable in the current basis;
167.1611 +*
167.1612 +* dx difference between values of the non-basic variable in the
167.1613 +* adjacent and current bases, dx = x.new - x.old;
167.1614 +*
167.1615 +* y value of the row (i.e. of its auxiliary variable) in the
167.1616 +* current basis;
167.1617 +*
167.1618 +* dy difference between values of the row in the adjacent and
167.1619 +* current bases, dy = y.new - y.old;
167.1620 +*
167.1621 +* dz difference between values of the objective function in the
167.1622 +* adjacent and current bases, dz = z.new - z.old. Note that in
167.1623 +* case of minimization dz >= 0, and in case of maximization
167.1624 +* dz <= 0, i.e. in the adjacent basis the objective function
167.1625 +* always gets worse (degrades). */
167.1626 +
167.1627 +int _glp_analyze_row(glp_prob *P, int len, const int ind[],
167.1628 + const double val[], int type, double rhs, double eps, int *_piv,
167.1629 + double *_x, double *_dx, double *_y, double *_dy, double *_dz)
167.1630 +{ int t, k, dir, piv, ret = 0;
167.1631 + double x, dx, y, dy, dz;
167.1632 + if (P->pbs_stat == GLP_UNDEF)
167.1633 + xerror("glp_analyze_row: primal basic solution components are "
167.1634 + "undefined\n");
167.1635 + if (P->dbs_stat != GLP_FEAS)
167.1636 + xerror("glp_analyze_row: basic solution is not dual feasible\n"
167.1637 + );
167.1638 + /* compute the row value y = sum alfa[j] * xN[j] in the current
167.1639 + basis */
167.1640 + if (!(0 <= len && len <= P->n))
167.1641 + xerror("glp_analyze_row: len = %d; invalid row length\n", len);
167.1642 + y = 0.0;
167.1643 + for (t = 1; t <= len; t++)
167.1644 + { /* determine value of x[k] = xN[j] in the current basis */
167.1645 + k = ind[t];
167.1646 + if (!(1 <= k && k <= P->m+P->n))
167.1647 + xerror("glp_analyze_row: ind[%d] = %d; row/column index out"
167.1648 + " of range\n", t, k);
167.1649 + if (k <= P->m)
167.1650 + { /* x[k] is auxiliary variable */
167.1651 + if (P->row[k]->stat == GLP_BS)
167.1652 + xerror("glp_analyze_row: ind[%d] = %d; basic auxiliary v"
167.1653 + "ariable is not allowed\n", t, k);
167.1654 + x = P->row[k]->prim;
167.1655 + }
167.1656 + else
167.1657 + { /* x[k] is structural variable */
167.1658 + if (P->col[k-P->m]->stat == GLP_BS)
167.1659 + xerror("glp_analyze_row: ind[%d] = %d; basic structural "
167.1660 + "variable is not allowed\n", t, k);
167.1661 + x = P->col[k-P->m]->prim;
167.1662 + }
167.1663 + y += val[t] * x;
167.1664 + }
167.1665 + /* check if the row is primal infeasible in the current basis,
167.1666 + i.e. the constraint is violated at the current point */
167.1667 + if (type == GLP_LO)
167.1668 + { if (y >= rhs)
167.1669 + { /* the constraint is not violated */
167.1670 + ret = 1;
167.1671 + goto done;
167.1672 + }
167.1673 + /* in the adjacent basis y goes to its lower bound */
167.1674 + dir = +1;
167.1675 + }
167.1676 + else if (type == GLP_UP)
167.1677 + { if (y <= rhs)
167.1678 + { /* the constraint is not violated */
167.1679 + ret = 1;
167.1680 + goto done;
167.1681 + }
167.1682 + /* in the adjacent basis y goes to its upper bound */
167.1683 + dir = -1;
167.1684 + }
167.1685 + else
167.1686 + xerror("glp_analyze_row: type = %d; invalid parameter\n",
167.1687 + type);
167.1688 + /* compute dy = y.new - y.old */
167.1689 + dy = rhs - y;
167.1690 + /* perform dual ratio test to determine which non-basic variable
167.1691 + should enter the adjacent basis to keep it dual feasible */
167.1692 + piv = glp_dual_rtest(P, len, ind, val, dir, eps);
167.1693 + if (piv == 0)
167.1694 + { /* no dual feasible adjacent basis exists */
167.1695 + ret = 2;
167.1696 + goto done;
167.1697 + }
167.1698 + /* non-basic variable x[k] = xN[j] should enter the basis */
167.1699 + k = ind[piv];
167.1700 + xassert(1 <= k && k <= P->m+P->n);
167.1701 + /* determine its value in the current basis */
167.1702 + if (k <= P->m)
167.1703 + x = P->row[k]->prim;
167.1704 + else
167.1705 + x = P->col[k-P->m]->prim;
167.1706 + /* compute dx = x.new - x.old = dy / alfa[j] */
167.1707 + xassert(val[piv] != 0.0);
167.1708 + dx = dy / val[piv];
167.1709 + /* compute dz = z.new - z.old = d[j] * dx, where d[j] is reduced
167.1710 + cost of xN[j] in the current basis */
167.1711 + if (k <= P->m)
167.1712 + dz = P->row[k]->dual * dx;
167.1713 + else
167.1714 + dz = P->col[k-P->m]->dual * dx;
167.1715 + /* store the analysis results */
167.1716 + if (_piv != NULL) *_piv = piv;
167.1717 + if (_x != NULL) *_x = x;
167.1718 + if (_dx != NULL) *_dx = dx;
167.1719 + if (_y != NULL) *_y = y;
167.1720 + if (_dy != NULL) *_dy = dy;
167.1721 + if (_dz != NULL) *_dz = dz;
167.1722 +done: return ret;
167.1723 +}
167.1724 +
167.1725 +#if 0
167.1726 +int main(void)
167.1727 +{ /* example program for the routine glp_analyze_row */
167.1728 + glp_prob *P;
167.1729 + glp_smcp parm;
167.1730 + int i, k, len, piv, ret, ind[1+100];
167.1731 + double rhs, x, dx, y, dy, dz, val[1+100];
167.1732 + P = glp_create_prob();
167.1733 + /* read plan.mps (see glpk/examples) */
167.1734 + ret = glp_read_mps(P, GLP_MPS_DECK, NULL, "plan.mps");
167.1735 + glp_assert(ret == 0);
167.1736 + /* and solve it to optimality */
167.1737 + ret = glp_simplex(P, NULL);
167.1738 + glp_assert(ret == 0);
167.1739 + glp_assert(glp_get_status(P) == GLP_OPT);
167.1740 + /* the optimal objective value is 296.217 */
167.1741 + /* we would like to know what happens if we would add a new row
167.1742 + (constraint) to plan.mps:
167.1743 + .01 * bin1 + .01 * bin2 + .02 * bin4 + .02 * bin5 <= 12 */
167.1744 + /* first, we specify this new row */
167.1745 + glp_create_index(P);
167.1746 + len = 0;
167.1747 + ind[++len] = glp_find_col(P, "BIN1"), val[len] = .01;
167.1748 + ind[++len] = glp_find_col(P, "BIN2"), val[len] = .01;
167.1749 + ind[++len] = glp_find_col(P, "BIN4"), val[len] = .02;
167.1750 + ind[++len] = glp_find_col(P, "BIN5"), val[len] = .02;
167.1751 + rhs = 12;
167.1752 + /* then we can compute value of the row (i.e. of its auxiliary
167.1753 + variable) in the current basis to see if the constraint is
167.1754 + violated */
167.1755 + y = 0.0;
167.1756 + for (k = 1; k <= len; k++)
167.1757 + y += val[k] * glp_get_col_prim(P, ind[k]);
167.1758 + glp_printf("y = %g\n", y);
167.1759 + /* this prints y = 15.1372, so the constraint is violated, since
167.1760 + we require that y <= rhs = 12 */
167.1761 + /* now we transform the row to express it only through non-basic
167.1762 + (auxiliary and artificial) variables */
167.1763 + len = glp_transform_row(P, len, ind, val);
167.1764 + /* finally, we simulate one step of the dual simplex method to
167.1765 + obtain necessary information for the adjacent basis */
167.1766 + ret = _glp_analyze_row(P, len, ind, val, GLP_UP, rhs, 1e-9, &piv,
167.1767 + &x, &dx, &y, &dy, &dz);
167.1768 + glp_assert(ret == 0);
167.1769 + glp_printf("k = %d, x = %g; dx = %g; y = %g; dy = %g; dz = %g\n",
167.1770 + ind[piv], x, dx, y, dy, dz);
167.1771 + /* this prints dz = 5.64418 and means that in the adjacent basis
167.1772 + the objective function would be 296.217 + 5.64418 = 301.861 */
167.1773 + /* now we actually include the row into the problem object; note
167.1774 + that the arrays ind and val are clobbered, so we need to build
167.1775 + them once again */
167.1776 + len = 0;
167.1777 + ind[++len] = glp_find_col(P, "BIN1"), val[len] = .01;
167.1778 + ind[++len] = glp_find_col(P, "BIN2"), val[len] = .01;
167.1779 + ind[++len] = glp_find_col(P, "BIN4"), val[len] = .02;
167.1780 + ind[++len] = glp_find_col(P, "BIN5"), val[len] = .02;
167.1781 + rhs = 12;
167.1782 + i = glp_add_rows(P, 1);
167.1783 + glp_set_row_bnds(P, i, GLP_UP, 0, rhs);
167.1784 + glp_set_mat_row(P, i, len, ind, val);
167.1785 + /* and perform one dual simplex iteration */
167.1786 + glp_init_smcp(&parm);
167.1787 + parm.meth = GLP_DUAL;
167.1788 + parm.it_lim = 1;
167.1789 + glp_simplex(P, &parm);
167.1790 + /* the current objective value is 301.861 */
167.1791 + return 0;
167.1792 +}
167.1793 +#endif
167.1794 +
167.1795 +/***********************************************************************
167.1796 +* NAME
167.1797 +*
167.1798 +* glp_analyze_bound - analyze active bound of non-basic variable
167.1799 +*
167.1800 +* SYNOPSIS
167.1801 +*
167.1802 +* void glp_analyze_bound(glp_prob *P, int k, double *limit1, int *var1,
167.1803 +* double *limit2, int *var2);
167.1804 +*
167.1805 +* DESCRIPTION
167.1806 +*
167.1807 +* The routine glp_analyze_bound analyzes the effect of varying the
167.1808 +* active bound of specified non-basic variable.
167.1809 +*
167.1810 +* The non-basic variable is specified by the parameter k, where
167.1811 +* 1 <= k <= m means auxiliary variable of corresponding row while
167.1812 +* m+1 <= k <= m+n means structural variable (column).
167.1813 +*
167.1814 +* Note that the current basic solution must be optimal, and the basis
167.1815 +* factorization must exist.
167.1816 +*
167.1817 +* Results of the analysis have the following meaning.
167.1818 +*
167.1819 +* value1 is the minimal value of the active bound, at which the basis
167.1820 +* still remains primal feasible and thus optimal. -DBL_MAX means that
167.1821 +* the active bound has no lower limit.
167.1822 +*
167.1823 +* var1 is the ordinal number of an auxiliary (1 to m) or structural
167.1824 +* (m+1 to n) basic variable, which reaches its bound first and thereby
167.1825 +* limits further decreasing the active bound being analyzed.
167.1826 +* if value1 = -DBL_MAX, var1 is set to 0.
167.1827 +*
167.1828 +* value2 is the maximal value of the active bound, at which the basis
167.1829 +* still remains primal feasible and thus optimal. +DBL_MAX means that
167.1830 +* the active bound has no upper limit.
167.1831 +*
167.1832 +* var2 is the ordinal number of an auxiliary (1 to m) or structural
167.1833 +* (m+1 to n) basic variable, which reaches its bound first and thereby
167.1834 +* limits further increasing the active bound being analyzed.
167.1835 +* if value2 = +DBL_MAX, var2 is set to 0. */
167.1836 +
167.1837 +void glp_analyze_bound(glp_prob *P, int k, double *value1, int *var1,
167.1838 + double *value2, int *var2)
167.1839 +{ GLPROW *row;
167.1840 + GLPCOL *col;
167.1841 + int m, n, stat, kase, p, len, piv, *ind;
167.1842 + double x, new_x, ll, uu, xx, delta, *val;
167.1843 + /* sanity checks */
167.1844 + if (P == NULL || P->magic != GLP_PROB_MAGIC)
167.1845 + xerror("glp_analyze_bound: P = %p; invalid problem object\n",
167.1846 + P);
167.1847 + m = P->m, n = P->n;
167.1848 + if (!(P->pbs_stat == GLP_FEAS && P->dbs_stat == GLP_FEAS))
167.1849 + xerror("glp_analyze_bound: optimal basic solution required\n");
167.1850 + if (!(m == 0 || P->valid))
167.1851 + xerror("glp_analyze_bound: basis factorization required\n");
167.1852 + if (!(1 <= k && k <= m+n))
167.1853 + xerror("glp_analyze_bound: k = %d; variable number out of rang"
167.1854 + "e\n", k);
167.1855 + /* retrieve information about the specified non-basic variable
167.1856 + x[k] whose active bound is to be analyzed */
167.1857 + if (k <= m)
167.1858 + { row = P->row[k];
167.1859 + stat = row->stat;
167.1860 + x = row->prim;
167.1861 + }
167.1862 + else
167.1863 + { col = P->col[k-m];
167.1864 + stat = col->stat;
167.1865 + x = col->prim;
167.1866 + }
167.1867 + if (stat == GLP_BS)
167.1868 + xerror("glp_analyze_bound: k = %d; basic variable not allowed "
167.1869 + "\n", k);
167.1870 + /* allocate working arrays */
167.1871 + ind = xcalloc(1+m, sizeof(int));
167.1872 + val = xcalloc(1+m, sizeof(double));
167.1873 + /* compute column of the simplex table corresponding to the
167.1874 + non-basic variable x[k] */
167.1875 + len = glp_eval_tab_col(P, k, ind, val);
167.1876 + xassert(0 <= len && len <= m);
167.1877 + /* perform analysis */
167.1878 + for (kase = -1; kase <= +1; kase += 2)
167.1879 + { /* kase < 0 means active bound of x[k] is decreasing;
167.1880 + kase > 0 means active bound of x[k] is increasing */
167.1881 + /* use the primal ratio test to determine some basic variable
167.1882 + x[p] which reaches its bound first */
167.1883 + piv = glp_prim_rtest(P, len, ind, val, kase, 1e-9);
167.1884 + if (piv == 0)
167.1885 + { /* nothing limits changing the active bound of x[k] */
167.1886 + p = 0;
167.1887 + new_x = (kase < 0 ? -DBL_MAX : +DBL_MAX);
167.1888 + goto store;
167.1889 + }
167.1890 + /* basic variable x[p] limits changing the active bound of
167.1891 + x[k]; determine its value in the current basis */
167.1892 + xassert(1 <= piv && piv <= len);
167.1893 + p = ind[piv];
167.1894 + if (p <= m)
167.1895 + { row = P->row[p];
167.1896 + ll = glp_get_row_lb(P, row->i);
167.1897 + uu = glp_get_row_ub(P, row->i);
167.1898 + stat = row->stat;
167.1899 + xx = row->prim;
167.1900 + }
167.1901 + else
167.1902 + { col = P->col[p-m];
167.1903 + ll = glp_get_col_lb(P, col->j);
167.1904 + uu = glp_get_col_ub(P, col->j);
167.1905 + stat = col->stat;
167.1906 + xx = col->prim;
167.1907 + }
167.1908 + xassert(stat == GLP_BS);
167.1909 + /* determine delta x[p] = bound of x[p] - value of x[p] */
167.1910 + if (kase < 0 && val[piv] > 0.0 ||
167.1911 + kase > 0 && val[piv] < 0.0)
167.1912 + { /* delta x[p] < 0, so x[p] goes toward its lower bound */
167.1913 + xassert(ll != -DBL_MAX);
167.1914 + delta = ll - xx;
167.1915 + }
167.1916 + else
167.1917 + { /* delta x[p] > 0, so x[p] goes toward its upper bound */
167.1918 + xassert(uu != +DBL_MAX);
167.1919 + delta = uu - xx;
167.1920 + }
167.1921 + /* delta x[p] = alfa[p,k] * delta x[k], so new x[k] = x[k] +
167.1922 + delta x[k] = x[k] + delta x[p] / alfa[p,k] is the value of
167.1923 + x[k] in the adjacent basis */
167.1924 + xassert(val[piv] != 0.0);
167.1925 + new_x = x + delta / val[piv];
167.1926 +store: /* store analysis results */
167.1927 + if (kase < 0)
167.1928 + { if (value1 != NULL) *value1 = new_x;
167.1929 + if (var1 != NULL) *var1 = p;
167.1930 + }
167.1931 + else
167.1932 + { if (value2 != NULL) *value2 = new_x;
167.1933 + if (var2 != NULL) *var2 = p;
167.1934 + }
167.1935 + }
167.1936 + /* free working arrays */
167.1937 + xfree(ind);
167.1938 + xfree(val);
167.1939 + return;
167.1940 +}
167.1941 +
167.1942 +/***********************************************************************
167.1943 +* NAME
167.1944 +*
167.1945 +* glp_analyze_coef - analyze objective coefficient at basic variable
167.1946 +*
167.1947 +* SYNOPSIS
167.1948 +*
167.1949 +* void glp_analyze_coef(glp_prob *P, int k, double *coef1, int *var1,
167.1950 +* double *value1, double *coef2, int *var2, double *value2);
167.1951 +*
167.1952 +* DESCRIPTION
167.1953 +*
167.1954 +* The routine glp_analyze_coef analyzes the effect of varying the
167.1955 +* objective coefficient at specified basic variable.
167.1956 +*
167.1957 +* The basic variable is specified by the parameter k, where
167.1958 +* 1 <= k <= m means auxiliary variable of corresponding row while
167.1959 +* m+1 <= k <= m+n means structural variable (column).
167.1960 +*
167.1961 +* Note that the current basic solution must be optimal, and the basis
167.1962 +* factorization must exist.
167.1963 +*
167.1964 +* Results of the analysis have the following meaning.
167.1965 +*
167.1966 +* coef1 is the minimal value of the objective coefficient, at which
167.1967 +* the basis still remains dual feasible and thus optimal. -DBL_MAX
167.1968 +* means that the objective coefficient has no lower limit.
167.1969 +*
167.1970 +* var1 is the ordinal number of an auxiliary (1 to m) or structural
167.1971 +* (m+1 to n) non-basic variable, whose reduced cost reaches its zero
167.1972 +* bound first and thereby limits further decreasing the objective
167.1973 +* coefficient being analyzed. If coef1 = -DBL_MAX, var1 is set to 0.
167.1974 +*
167.1975 +* value1 is value of the basic variable being analyzed in an adjacent
167.1976 +* basis, which is defined as follows. Let the objective coefficient
167.1977 +* reaches its minimal value (coef1) and continues decreasing. Then the
167.1978 +* reduced cost of the limiting non-basic variable (var1) becomes dual
167.1979 +* infeasible and the current basis becomes non-optimal that forces the
167.1980 +* limiting non-basic variable to enter the basis replacing there some
167.1981 +* basic variable that leaves the basis to keep primal feasibility.
167.1982 +* Should note that on determining the adjacent basis current bounds
167.1983 +* of the basic variable being analyzed are ignored as if it were free
167.1984 +* (unbounded) variable, so it cannot leave the basis. It may happen
167.1985 +* that no dual feasible adjacent basis exists, in which case value1 is
167.1986 +* set to -DBL_MAX or +DBL_MAX.
167.1987 +*
167.1988 +* coef2 is the maximal value of the objective coefficient, at which
167.1989 +* the basis still remains dual feasible and thus optimal. +DBL_MAX
167.1990 +* means that the objective coefficient has no upper limit.
167.1991 +*
167.1992 +* var2 is the ordinal number of an auxiliary (1 to m) or structural
167.1993 +* (m+1 to n) non-basic variable, whose reduced cost reaches its zero
167.1994 +* bound first and thereby limits further increasing the objective
167.1995 +* coefficient being analyzed. If coef2 = +DBL_MAX, var2 is set to 0.
167.1996 +*
167.1997 +* value2 is value of the basic variable being analyzed in an adjacent
167.1998 +* basis, which is defined exactly in the same way as value1 above with
167.1999 +* exception that now the objective coefficient is increasing. */
167.2000 +
167.2001 +void glp_analyze_coef(glp_prob *P, int k, double *coef1, int *var1,
167.2002 + double *value1, double *coef2, int *var2, double *value2)
167.2003 +{ GLPROW *row; GLPCOL *col;
167.2004 + int m, n, type, stat, kase, p, q, dir, clen, cpiv, rlen, rpiv,
167.2005 + *cind, *rind;
167.2006 + double lb, ub, coef, x, lim_coef, new_x, d, delta, ll, uu, xx,
167.2007 + *rval, *cval;
167.2008 + /* sanity checks */
167.2009 + if (P == NULL || P->magic != GLP_PROB_MAGIC)
167.2010 + xerror("glp_analyze_coef: P = %p; invalid problem object\n",
167.2011 + P);
167.2012 + m = P->m, n = P->n;
167.2013 + if (!(P->pbs_stat == GLP_FEAS && P->dbs_stat == GLP_FEAS))
167.2014 + xerror("glp_analyze_coef: optimal basic solution required\n");
167.2015 + if (!(m == 0 || P->valid))
167.2016 + xerror("glp_analyze_coef: basis factorization required\n");
167.2017 + if (!(1 <= k && k <= m+n))
167.2018 + xerror("glp_analyze_coef: k = %d; variable number out of range"
167.2019 + "\n", k);
167.2020 + /* retrieve information about the specified basic variable x[k]
167.2021 + whose objective coefficient c[k] is to be analyzed */
167.2022 + if (k <= m)
167.2023 + { row = P->row[k];
167.2024 + type = row->type;
167.2025 + lb = row->lb;
167.2026 + ub = row->ub;
167.2027 + coef = 0.0;
167.2028 + stat = row->stat;
167.2029 + x = row->prim;
167.2030 + }
167.2031 + else
167.2032 + { col = P->col[k-m];
167.2033 + type = col->type;
167.2034 + lb = col->lb;
167.2035 + ub = col->ub;
167.2036 + coef = col->coef;
167.2037 + stat = col->stat;
167.2038 + x = col->prim;
167.2039 + }
167.2040 + if (stat != GLP_BS)
167.2041 + xerror("glp_analyze_coef: k = %d; non-basic variable not allow"
167.2042 + "ed\n", k);
167.2043 + /* allocate working arrays */
167.2044 + cind = xcalloc(1+m, sizeof(int));
167.2045 + cval = xcalloc(1+m, sizeof(double));
167.2046 + rind = xcalloc(1+n, sizeof(int));
167.2047 + rval = xcalloc(1+n, sizeof(double));
167.2048 + /* compute row of the simplex table corresponding to the basic
167.2049 + variable x[k] */
167.2050 + rlen = glp_eval_tab_row(P, k, rind, rval);
167.2051 + xassert(0 <= rlen && rlen <= n);
167.2052 + /* perform analysis */
167.2053 + for (kase = -1; kase <= +1; kase += 2)
167.2054 + { /* kase < 0 means objective coefficient c[k] is decreasing;
167.2055 + kase > 0 means objective coefficient c[k] is increasing */
167.2056 + /* note that decreasing c[k] is equivalent to increasing dual
167.2057 + variable lambda[k] and vice versa; we need to correctly set
167.2058 + the dir flag as required by the routine glp_dual_rtest */
167.2059 + if (P->dir == GLP_MIN)
167.2060 + dir = - kase;
167.2061 + else if (P->dir == GLP_MAX)
167.2062 + dir = + kase;
167.2063 + else
167.2064 + xassert(P != P);
167.2065 + /* use the dual ratio test to determine non-basic variable
167.2066 + x[q] whose reduced cost d[q] reaches zero bound first */
167.2067 + rpiv = glp_dual_rtest(P, rlen, rind, rval, dir, 1e-9);
167.2068 + if (rpiv == 0)
167.2069 + { /* nothing limits changing c[k] */
167.2070 + lim_coef = (kase < 0 ? -DBL_MAX : +DBL_MAX);
167.2071 + q = 0;
167.2072 + /* x[k] keeps its current value */
167.2073 + new_x = x;
167.2074 + goto store;
167.2075 + }
167.2076 + /* non-basic variable x[q] limits changing coefficient c[k];
167.2077 + determine its status and reduced cost d[k] in the current
167.2078 + basis */
167.2079 + xassert(1 <= rpiv && rpiv <= rlen);
167.2080 + q = rind[rpiv];
167.2081 + xassert(1 <= q && q <= m+n);
167.2082 + if (q <= m)
167.2083 + { row = P->row[q];
167.2084 + stat = row->stat;
167.2085 + d = row->dual;
167.2086 + }
167.2087 + else
167.2088 + { col = P->col[q-m];
167.2089 + stat = col->stat;
167.2090 + d = col->dual;
167.2091 + }
167.2092 + /* note that delta d[q] = new d[q] - d[q] = - d[q], because
167.2093 + new d[q] = 0; delta d[q] = alfa[k,q] * delta c[k], so
167.2094 + delta c[k] = delta d[q] / alfa[k,q] = - d[q] / alfa[k,q] */
167.2095 + xassert(rval[rpiv] != 0.0);
167.2096 + delta = - d / rval[rpiv];
167.2097 + /* compute new c[k] = c[k] + delta c[k], which is the limiting
167.2098 + value of the objective coefficient c[k] */
167.2099 + lim_coef = coef + delta;
167.2100 + /* let c[k] continue decreasing/increasing that makes d[q]
167.2101 + dual infeasible and forces x[q] to enter the basis;
167.2102 + to perform the primal ratio test we need to know in which
167.2103 + direction x[q] changes on entering the basis; we determine
167.2104 + that analyzing the sign of delta d[q] (see above), since
167.2105 + d[q] may be close to zero having wrong sign */
167.2106 + /* let, for simplicity, the problem is minimization */
167.2107 + if (kase < 0 && rval[rpiv] > 0.0 ||
167.2108 + kase > 0 && rval[rpiv] < 0.0)
167.2109 + { /* delta d[q] < 0, so d[q] being non-negative will become
167.2110 + negative, so x[q] will increase */
167.2111 + dir = +1;
167.2112 + }
167.2113 + else
167.2114 + { /* delta d[q] > 0, so d[q] being non-positive will become
167.2115 + positive, so x[q] will decrease */
167.2116 + dir = -1;
167.2117 + }
167.2118 + /* if the problem is maximization, correct the direction */
167.2119 + if (P->dir == GLP_MAX) dir = - dir;
167.2120 + /* check that we didn't make a silly mistake */
167.2121 + if (dir > 0)
167.2122 + xassert(stat == GLP_NL || stat == GLP_NF);
167.2123 + else
167.2124 + xassert(stat == GLP_NU || stat == GLP_NF);
167.2125 + /* compute column of the simplex table corresponding to the
167.2126 + non-basic variable x[q] */
167.2127 + clen = glp_eval_tab_col(P, q, cind, cval);
167.2128 + /* make x[k] temporarily free (unbounded) */
167.2129 + if (k <= m)
167.2130 + { row = P->row[k];
167.2131 + row->type = GLP_FR;
167.2132 + row->lb = row->ub = 0.0;
167.2133 + }
167.2134 + else
167.2135 + { col = P->col[k-m];
167.2136 + col->type = GLP_FR;
167.2137 + col->lb = col->ub = 0.0;
167.2138 + }
167.2139 + /* use the primal ratio test to determine some basic variable
167.2140 + which leaves the basis */
167.2141 + cpiv = glp_prim_rtest(P, clen, cind, cval, dir, 1e-9);
167.2142 + /* restore original bounds of the basic variable x[k] */
167.2143 + if (k <= m)
167.2144 + { row = P->row[k];
167.2145 + row->type = type;
167.2146 + row->lb = lb, row->ub = ub;
167.2147 + }
167.2148 + else
167.2149 + { col = P->col[k-m];
167.2150 + col->type = type;
167.2151 + col->lb = lb, col->ub = ub;
167.2152 + }
167.2153 + if (cpiv == 0)
167.2154 + { /* non-basic variable x[q] can change unlimitedly */
167.2155 + if (dir < 0 && rval[rpiv] > 0.0 ||
167.2156 + dir > 0 && rval[rpiv] < 0.0)
167.2157 + { /* delta x[k] = alfa[k,q] * delta x[q] < 0 */
167.2158 + new_x = -DBL_MAX;
167.2159 + }
167.2160 + else
167.2161 + { /* delta x[k] = alfa[k,q] * delta x[q] > 0 */
167.2162 + new_x = +DBL_MAX;
167.2163 + }
167.2164 + goto store;
167.2165 + }
167.2166 + /* some basic variable x[p] limits changing non-basic variable
167.2167 + x[q] in the adjacent basis */
167.2168 + xassert(1 <= cpiv && cpiv <= clen);
167.2169 + p = cind[cpiv];
167.2170 + xassert(1 <= p && p <= m+n);
167.2171 + xassert(p != k);
167.2172 + if (p <= m)
167.2173 + { row = P->row[p];
167.2174 + xassert(row->stat == GLP_BS);
167.2175 + ll = glp_get_row_lb(P, row->i);
167.2176 + uu = glp_get_row_ub(P, row->i);
167.2177 + xx = row->prim;
167.2178 + }
167.2179 + else
167.2180 + { col = P->col[p-m];
167.2181 + xassert(col->stat == GLP_BS);
167.2182 + ll = glp_get_col_lb(P, col->j);
167.2183 + uu = glp_get_col_ub(P, col->j);
167.2184 + xx = col->prim;
167.2185 + }
167.2186 + /* determine delta x[p] = new x[p] - x[p] */
167.2187 + if (dir < 0 && cval[cpiv] > 0.0 ||
167.2188 + dir > 0 && cval[cpiv] < 0.0)
167.2189 + { /* delta x[p] < 0, so x[p] goes toward its lower bound */
167.2190 + xassert(ll != -DBL_MAX);
167.2191 + delta = ll - xx;
167.2192 + }
167.2193 + else
167.2194 + { /* delta x[p] > 0, so x[p] goes toward its upper bound */
167.2195 + xassert(uu != +DBL_MAX);
167.2196 + delta = uu - xx;
167.2197 + }
167.2198 + /* compute new x[k] = x[k] + alfa[k,q] * delta x[q], where
167.2199 + delta x[q] = delta x[p] / alfa[p,q] */
167.2200 + xassert(cval[cpiv] != 0.0);
167.2201 + new_x = x + (rval[rpiv] / cval[cpiv]) * delta;
167.2202 +store: /* store analysis results */
167.2203 + if (kase < 0)
167.2204 + { if (coef1 != NULL) *coef1 = lim_coef;
167.2205 + if (var1 != NULL) *var1 = q;
167.2206 + if (value1 != NULL) *value1 = new_x;
167.2207 + }
167.2208 + else
167.2209 + { if (coef2 != NULL) *coef2 = lim_coef;
167.2210 + if (var2 != NULL) *var2 = q;
167.2211 + if (value2 != NULL) *value2 = new_x;
167.2212 + }
167.2213 + }
167.2214 + /* free working arrays */
167.2215 + xfree(cind);
167.2216 + xfree(cval);
167.2217 + xfree(rind);
167.2218 + xfree(rval);
167.2219 + return;
167.2220 +}
167.2221 +
167.2222 +/* eof */
168.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
168.2 +++ b/src/glpapi13.c Mon Dec 06 13:09:21 2010 +0100
168.3 @@ -0,0 +1,702 @@
168.4 +/* glpapi13.c (branch-and-bound interface routines) */
168.5 +
168.6 +/***********************************************************************
168.7 +* This code is part of GLPK (GNU Linear Programming Kit).
168.8 +*
168.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
168.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
168.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
168.12 +* E-mail: <mao@gnu.org>.
168.13 +*
168.14 +* GLPK is free software: you can redistribute it and/or modify it
168.15 +* under the terms of the GNU General Public License as published by
168.16 +* the Free Software Foundation, either version 3 of the License, or
168.17 +* (at your option) any later version.
168.18 +*
168.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
168.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
168.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
168.22 +* License for more details.
168.23 +*
168.24 +* You should have received a copy of the GNU General Public License
168.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
168.26 +***********************************************************************/
168.27 +
168.28 +#include "glpios.h"
168.29 +
168.30 +/***********************************************************************
168.31 +* NAME
168.32 +*
168.33 +* glp_ios_reason - determine reason for calling the callback routine
168.34 +*
168.35 +* SYNOPSIS
168.36 +*
168.37 +* glp_ios_reason(glp_tree *tree);
168.38 +*
168.39 +* RETURNS
168.40 +*
168.41 +* The routine glp_ios_reason returns a code, which indicates why the
168.42 +* user-defined callback routine is being called. */
168.43 +
168.44 +int glp_ios_reason(glp_tree *tree)
168.45 +{ return
168.46 + tree->reason;
168.47 +}
168.48 +
168.49 +/***********************************************************************
168.50 +* NAME
168.51 +*
168.52 +* glp_ios_get_prob - access the problem object
168.53 +*
168.54 +* SYNOPSIS
168.55 +*
168.56 +* glp_prob *glp_ios_get_prob(glp_tree *tree);
168.57 +*
168.58 +* DESCRIPTION
168.59 +*
168.60 +* The routine glp_ios_get_prob can be called from the user-defined
168.61 +* callback routine to access the problem object, which is used by the
168.62 +* MIP solver. It is the original problem object passed to the routine
168.63 +* glp_intopt if the MIP presolver is not used; otherwise it is an
168.64 +* internal problem object built by the presolver. If the current
168.65 +* subproblem exists, LP segment of the problem object corresponds to
168.66 +* its LP relaxation.
168.67 +*
168.68 +* RETURNS
168.69 +*
168.70 +* The routine glp_ios_get_prob returns a pointer to the problem object
168.71 +* used by the MIP solver. */
168.72 +
168.73 +glp_prob *glp_ios_get_prob(glp_tree *tree)
168.74 +{ return
168.75 + tree->mip;
168.76 +}
168.77 +
168.78 +/***********************************************************************
168.79 +* NAME
168.80 +*
168.81 +* glp_ios_tree_size - determine size of the branch-and-bound tree
168.82 +*
168.83 +* SYNOPSIS
168.84 +*
168.85 +* void glp_ios_tree_size(glp_tree *tree, int *a_cnt, int *n_cnt,
168.86 +* int *t_cnt);
168.87 +*
168.88 +* DESCRIPTION
168.89 +*
168.90 +* The routine glp_ios_tree_size stores the following three counts which
168.91 +* characterize the current size of the branch-and-bound tree:
168.92 +*
168.93 +* a_cnt is the current number of active nodes, i.e. the current size of
168.94 +* the active list;
168.95 +*
168.96 +* n_cnt is the current number of all (active and inactive) nodes;
168.97 +*
168.98 +* t_cnt is the total number of nodes including those which have been
168.99 +* already removed from the tree. This count is increased whenever
168.100 +* a new node appears in the tree and never decreased.
168.101 +*
168.102 +* If some of the parameters a_cnt, n_cnt, t_cnt is a null pointer, the
168.103 +* corresponding count is not stored. */
168.104 +
168.105 +void glp_ios_tree_size(glp_tree *tree, int *a_cnt, int *n_cnt,
168.106 + int *t_cnt)
168.107 +{ if (a_cnt != NULL) *a_cnt = tree->a_cnt;
168.108 + if (n_cnt != NULL) *n_cnt = tree->n_cnt;
168.109 + if (t_cnt != NULL) *t_cnt = tree->t_cnt;
168.110 + return;
168.111 +}
168.112 +
168.113 +/***********************************************************************
168.114 +* NAME
168.115 +*
168.116 +* glp_ios_curr_node - determine current active subproblem
168.117 +*
168.118 +* SYNOPSIS
168.119 +*
168.120 +* int glp_ios_curr_node(glp_tree *tree);
168.121 +*
168.122 +* RETURNS
168.123 +*
168.124 +* The routine glp_ios_curr_node returns the reference number of the
168.125 +* current active subproblem. However, if the current subproblem does
168.126 +* not exist, the routine returns zero. */
168.127 +
168.128 +int glp_ios_curr_node(glp_tree *tree)
168.129 +{ IOSNPD *node;
168.130 + /* obtain pointer to the current subproblem */
168.131 + node = tree->curr;
168.132 + /* return its reference number */
168.133 + return node == NULL ? 0 : node->p;
168.134 +}
168.135 +
168.136 +/***********************************************************************
168.137 +* NAME
168.138 +*
168.139 +* glp_ios_next_node - determine next active subproblem
168.140 +*
168.141 +* SYNOPSIS
168.142 +*
168.143 +* int glp_ios_next_node(glp_tree *tree, int p);
168.144 +*
168.145 +* RETURNS
168.146 +*
168.147 +* If the parameter p is zero, the routine glp_ios_next_node returns
168.148 +* the reference number of the first active subproblem. However, if the
168.149 +* tree is empty, zero is returned.
168.150 +*
168.151 +* If the parameter p is not zero, it must specify the reference number
168.152 +* of some active subproblem, in which case the routine returns the
168.153 +* reference number of the next active subproblem. However, if there is
168.154 +* no next active subproblem in the list, zero is returned.
168.155 +*
168.156 +* All subproblems in the active list are ordered chronologically, i.e.
168.157 +* subproblem A precedes subproblem B if A was created before B. */
168.158 +
168.159 +int glp_ios_next_node(glp_tree *tree, int p)
168.160 +{ IOSNPD *node;
168.161 + if (p == 0)
168.162 + { /* obtain pointer to the first active subproblem */
168.163 + node = tree->head;
168.164 + }
168.165 + else
168.166 + { /* obtain pointer to the specified subproblem */
168.167 + if (!(1 <= p && p <= tree->nslots))
168.168 +err: xerror("glp_ios_next_node: p = %d; invalid subproblem refer"
168.169 + "ence number\n", p);
168.170 + node = tree->slot[p].node;
168.171 + if (node == NULL) goto err;
168.172 + /* the specified subproblem must be active */
168.173 + if (node->count != 0)
168.174 + xerror("glp_ios_next_node: p = %d; subproblem not in the ac"
168.175 + "tive list\n", p);
168.176 + /* obtain pointer to the next active subproblem */
168.177 + node = node->next;
168.178 + }
168.179 + /* return the reference number */
168.180 + return node == NULL ? 0 : node->p;
168.181 +}
168.182 +
168.183 +/***********************************************************************
168.184 +* NAME
168.185 +*
168.186 +* glp_ios_prev_node - determine previous active subproblem
168.187 +*
168.188 +* SYNOPSIS
168.189 +*
168.190 +* int glp_ios_prev_node(glp_tree *tree, int p);
168.191 +*
168.192 +* RETURNS
168.193 +*
168.194 +* If the parameter p is zero, the routine glp_ios_prev_node returns
168.195 +* the reference number of the last active subproblem. However, if the
168.196 +* tree is empty, zero is returned.
168.197 +*
168.198 +* If the parameter p is not zero, it must specify the reference number
168.199 +* of some active subproblem, in which case the routine returns the
168.200 +* reference number of the previous active subproblem. However, if there
168.201 +* is no previous active subproblem in the list, zero is returned.
168.202 +*
168.203 +* All subproblems in the active list are ordered chronologically, i.e.
168.204 +* subproblem A precedes subproblem B if A was created before B. */
168.205 +
168.206 +int glp_ios_prev_node(glp_tree *tree, int p)
168.207 +{ IOSNPD *node;
168.208 + if (p == 0)
168.209 + { /* obtain pointer to the last active subproblem */
168.210 + node = tree->tail;
168.211 + }
168.212 + else
168.213 + { /* obtain pointer to the specified subproblem */
168.214 + if (!(1 <= p && p <= tree->nslots))
168.215 +err: xerror("glp_ios_prev_node: p = %d; invalid subproblem refer"
168.216 + "ence number\n", p);
168.217 + node = tree->slot[p].node;
168.218 + if (node == NULL) goto err;
168.219 + /* the specified subproblem must be active */
168.220 + if (node->count != 0)
168.221 + xerror("glp_ios_prev_node: p = %d; subproblem not in the ac"
168.222 + "tive list\n", p);
168.223 + /* obtain pointer to the previous active subproblem */
168.224 + node = node->prev;
168.225 + }
168.226 + /* return the reference number */
168.227 + return node == NULL ? 0 : node->p;
168.228 +}
168.229 +
168.230 +/***********************************************************************
168.231 +* NAME
168.232 +*
168.233 +* glp_ios_up_node - determine parent subproblem
168.234 +*
168.235 +* SYNOPSIS
168.236 +*
168.237 +* int glp_ios_up_node(glp_tree *tree, int p);
168.238 +*
168.239 +* RETURNS
168.240 +*
168.241 +* The parameter p must specify the reference number of some (active or
168.242 +* inactive) subproblem, in which case the routine iet_get_up_node
168.243 +* returns the reference number of its parent subproblem. However, if
168.244 +* the specified subproblem is the root of the tree and, therefore, has
168.245 +* no parent, the routine returns zero. */
168.246 +
168.247 +int glp_ios_up_node(glp_tree *tree, int p)
168.248 +{ IOSNPD *node;
168.249 + /* obtain pointer to the specified subproblem */
168.250 + if (!(1 <= p && p <= tree->nslots))
168.251 +err: xerror("glp_ios_up_node: p = %d; invalid subproblem reference "
168.252 + "number\n", p);
168.253 + node = tree->slot[p].node;
168.254 + if (node == NULL) goto err;
168.255 + /* obtain pointer to the parent subproblem */
168.256 + node = node->up;
168.257 + /* return the reference number */
168.258 + return node == NULL ? 0 : node->p;
168.259 +}
168.260 +
168.261 +/***********************************************************************
168.262 +* NAME
168.263 +*
168.264 +* glp_ios_node_level - determine subproblem level
168.265 +*
168.266 +* SYNOPSIS
168.267 +*
168.268 +* int glp_ios_node_level(glp_tree *tree, int p);
168.269 +*
168.270 +* RETURNS
168.271 +*
168.272 +* The routine glp_ios_node_level returns the level of the subproblem,
168.273 +* whose reference number is p, in the branch-and-bound tree. (The root
168.274 +* subproblem has level 0, and the level of any other subproblem is the
168.275 +* level of its parent plus one.) */
168.276 +
168.277 +int glp_ios_node_level(glp_tree *tree, int p)
168.278 +{ IOSNPD *node;
168.279 + /* obtain pointer to the specified subproblem */
168.280 + if (!(1 <= p && p <= tree->nslots))
168.281 +err: xerror("glp_ios_node_level: p = %d; invalid subproblem referen"
168.282 + "ce number\n", p);
168.283 + node = tree->slot[p].node;
168.284 + if (node == NULL) goto err;
168.285 + /* return the node level */
168.286 + return node->level;
168.287 +}
168.288 +
168.289 +/***********************************************************************
168.290 +* NAME
168.291 +*
168.292 +* glp_ios_node_bound - determine subproblem local bound
168.293 +*
168.294 +* SYNOPSIS
168.295 +*
168.296 +* double glp_ios_node_bound(glp_tree *tree, int p);
168.297 +*
168.298 +* RETURNS
168.299 +*
168.300 +* The routine glp_ios_node_bound returns the local bound for (active or
168.301 +* inactive) subproblem, whose reference number is p.
168.302 +*
168.303 +* COMMENTS
168.304 +*
168.305 +* The local bound for subproblem p is an lower (minimization) or upper
168.306 +* (maximization) bound for integer optimal solution to this subproblem
168.307 +* (not to the original problem). This bound is local in the sense that
168.308 +* only subproblems in the subtree rooted at node p cannot have better
168.309 +* integer feasible solutions.
168.310 +*
168.311 +* On creating a subproblem (due to the branching step) its local bound
168.312 +* is inherited from its parent and then may get only stronger (never
168.313 +* weaker). For the root subproblem its local bound is initially set to
168.314 +* -DBL_MAX (minimization) or +DBL_MAX (maximization) and then improved
168.315 +* as the root LP relaxation has been solved.
168.316 +*
168.317 +* Note that the local bound is not necessarily the optimal objective
168.318 +* value to corresponding LP relaxation; it may be stronger. */
168.319 +
168.320 +double glp_ios_node_bound(glp_tree *tree, int p)
168.321 +{ IOSNPD *node;
168.322 + /* obtain pointer to the specified subproblem */
168.323 + if (!(1 <= p && p <= tree->nslots))
168.324 +err: xerror("glp_ios_node_bound: p = %d; invalid subproblem referen"
168.325 + "ce number\n", p);
168.326 + node = tree->slot[p].node;
168.327 + if (node == NULL) goto err;
168.328 + /* return the node local bound */
168.329 + return node->bound;
168.330 +}
168.331 +
168.332 +/***********************************************************************
168.333 +* NAME
168.334 +*
168.335 +* glp_ios_best_node - find active subproblem with best local bound
168.336 +*
168.337 +* SYNOPSIS
168.338 +*
168.339 +* int glp_ios_best_node(glp_tree *tree);
168.340 +*
168.341 +* RETURNS
168.342 +*
168.343 +* The routine glp_ios_best_node returns the reference number of the
168.344 +* active subproblem, whose local bound is best (i.e. smallest in case
168.345 +* of minimization or largest in case of maximization). However, if the
168.346 +* tree is empty, the routine returns zero.
168.347 +*
168.348 +* COMMENTS
168.349 +*
168.350 +* The best local bound is an lower (minimization) or upper
168.351 +* (maximization) bound for integer optimal solution to the original
168.352 +* MIP problem. */
168.353 +
168.354 +int glp_ios_best_node(glp_tree *tree)
168.355 +{ return
168.356 + ios_best_node(tree);
168.357 +}
168.358 +
168.359 +/***********************************************************************
168.360 +* NAME
168.361 +*
168.362 +* glp_ios_mip_gap - compute relative MIP gap
168.363 +*
168.364 +* SYNOPSIS
168.365 +*
168.366 +* double glp_ios_mip_gap(glp_tree *tree);
168.367 +*
168.368 +* DESCRIPTION
168.369 +*
168.370 +* The routine glp_ios_mip_gap computes the relative MIP gap with the
168.371 +* following formula:
168.372 +*
168.373 +* gap = |best_mip - best_bnd| / (|best_mip| + DBL_EPSILON),
168.374 +*
168.375 +* where best_mip is the best integer feasible solution found so far,
168.376 +* best_bnd is the best (global) bound. If no integer feasible solution
168.377 +* has been found yet, gap is set to DBL_MAX.
168.378 +*
168.379 +* RETURNS
168.380 +*
168.381 +* The routine glp_ios_mip_gap returns the relative MIP gap. */
168.382 +
168.383 +double glp_ios_mip_gap(glp_tree *tree)
168.384 +{ return
168.385 + ios_relative_gap(tree);
168.386 +}
168.387 +
168.388 +/***********************************************************************
168.389 +* NAME
168.390 +*
168.391 +* glp_ios_node_data - access subproblem application-specific data
168.392 +*
168.393 +* SYNOPSIS
168.394 +*
168.395 +* void *glp_ios_node_data(glp_tree *tree, int p);
168.396 +*
168.397 +* DESCRIPTION
168.398 +*
168.399 +* The routine glp_ios_node_data allows the application accessing a
168.400 +* memory block allocated for the subproblem (which may be active or
168.401 +* inactive), whose reference number is p.
168.402 +*
168.403 +* The size of the block is defined by the control parameter cb_size
168.404 +* passed to the routine glp_intopt. The block is initialized by binary
168.405 +* zeros on creating corresponding subproblem, and its contents is kept
168.406 +* until the subproblem will be removed from the tree.
168.407 +*
168.408 +* The application may use these memory blocks to store specific data
168.409 +* for each subproblem.
168.410 +*
168.411 +* RETURNS
168.412 +*
168.413 +* The routine glp_ios_node_data returns a pointer to the memory block
168.414 +* for the specified subproblem. Note that if cb_size = 0, the routine
168.415 +* returns a null pointer. */
168.416 +
168.417 +void *glp_ios_node_data(glp_tree *tree, int p)
168.418 +{ IOSNPD *node;
168.419 + /* obtain pointer to the specified subproblem */
168.420 + if (!(1 <= p && p <= tree->nslots))
168.421 +err: xerror("glp_ios_node_level: p = %d; invalid subproblem referen"
168.422 + "ce number\n", p);
168.423 + node = tree->slot[p].node;
168.424 + if (node == NULL) goto err;
168.425 + /* return pointer to the application-specific data */
168.426 + return node->data;
168.427 +}
168.428 +
168.429 +/***********************************************************************
168.430 +* NAME
168.431 +*
168.432 +* glp_ios_row_attr - retrieve additional row attributes
168.433 +*
168.434 +* SYNOPSIS
168.435 +*
168.436 +* void glp_ios_row_attr(glp_tree *tree, int i, glp_attr *attr);
168.437 +*
168.438 +* DESCRIPTION
168.439 +*
168.440 +* The routine glp_ios_row_attr retrieves additional attributes of row
168.441 +* i and stores them in the structure glp_attr. */
168.442 +
168.443 +void glp_ios_row_attr(glp_tree *tree, int i, glp_attr *attr)
168.444 +{ GLPROW *row;
168.445 + if (!(1 <= i && i <= tree->mip->m))
168.446 + xerror("glp_ios_row_attr: i = %d; row number out of range\n",
168.447 + i);
168.448 + row = tree->mip->row[i];
168.449 + attr->level = row->level;
168.450 + attr->origin = row->origin;
168.451 + attr->klass = row->klass;
168.452 + return;
168.453 +}
168.454 +
168.455 +/**********************************************************************/
168.456 +
168.457 +int glp_ios_pool_size(glp_tree *tree)
168.458 +{ /* determine current size of the cut pool */
168.459 + if (tree->reason != GLP_ICUTGEN)
168.460 + xerror("glp_ios_pool_size: operation not allowed\n");
168.461 + xassert(tree->local != NULL);
168.462 + return tree->local->size;
168.463 +}
168.464 +
168.465 +/**********************************************************************/
168.466 +
168.467 +int glp_ios_add_row(glp_tree *tree,
168.468 + const char *name, int klass, int flags, int len, const int ind[],
168.469 + const double val[], int type, double rhs)
168.470 +{ /* add row (constraint) to the cut pool */
168.471 + int num;
168.472 + if (tree->reason != GLP_ICUTGEN)
168.473 + xerror("glp_ios_add_row: operation not allowed\n");
168.474 + xassert(tree->local != NULL);
168.475 + num = ios_add_row(tree, tree->local, name, klass, flags, len,
168.476 + ind, val, type, rhs);
168.477 + return num;
168.478 +}
168.479 +
168.480 +/**********************************************************************/
168.481 +
168.482 +void glp_ios_del_row(glp_tree *tree, int i)
168.483 +{ /* remove row (constraint) from the cut pool */
168.484 + if (tree->reason != GLP_ICUTGEN)
168.485 + xerror("glp_ios_del_row: operation not allowed\n");
168.486 + ios_del_row(tree, tree->local, i);
168.487 + return;
168.488 +}
168.489 +
168.490 +/**********************************************************************/
168.491 +
168.492 +void glp_ios_clear_pool(glp_tree *tree)
168.493 +{ /* remove all rows (constraints) from the cut pool */
168.494 + if (tree->reason != GLP_ICUTGEN)
168.495 + xerror("glp_ios_clear_pool: operation not allowed\n");
168.496 + ios_clear_pool(tree, tree->local);
168.497 + return;
168.498 +}
168.499 +
168.500 +/***********************************************************************
168.501 +* NAME
168.502 +*
168.503 +* glp_ios_can_branch - check if can branch upon specified variable
168.504 +*
168.505 +* SYNOPSIS
168.506 +*
168.507 +* int glp_ios_can_branch(glp_tree *tree, int j);
168.508 +*
168.509 +* RETURNS
168.510 +*
168.511 +* If j-th variable (column) can be used to branch upon, the routine
168.512 +* glp_ios_can_branch returns non-zero, otherwise zero. */
168.513 +
168.514 +int glp_ios_can_branch(glp_tree *tree, int j)
168.515 +{ if (!(1 <= j && j <= tree->mip->n))
168.516 + xerror("glp_ios_can_branch: j = %d; column number out of range"
168.517 + "\n", j);
168.518 + return tree->non_int[j];
168.519 +}
168.520 +
168.521 +/***********************************************************************
168.522 +* NAME
168.523 +*
168.524 +* glp_ios_branch_upon - choose variable to branch upon
168.525 +*
168.526 +* SYNOPSIS
168.527 +*
168.528 +* void glp_ios_branch_upon(glp_tree *tree, int j, int sel);
168.529 +*
168.530 +* DESCRIPTION
168.531 +*
168.532 +* The routine glp_ios_branch_upon can be called from the user-defined
168.533 +* callback routine in response to the reason GLP_IBRANCH to choose a
168.534 +* branching variable, whose ordinal number is j. Should note that only
168.535 +* variables, for which the routine glp_ios_can_branch returns non-zero,
168.536 +* can be used to branch upon.
168.537 +*
168.538 +* The parameter sel is a flag that indicates which branch (subproblem)
168.539 +* should be selected next to continue the search:
168.540 +*
168.541 +* GLP_DN_BRNCH - select down-branch;
168.542 +* GLP_UP_BRNCH - select up-branch;
168.543 +* GLP_NO_BRNCH - use general selection technique. */
168.544 +
168.545 +void glp_ios_branch_upon(glp_tree *tree, int j, int sel)
168.546 +{ if (!(1 <= j && j <= tree->mip->n))
168.547 + xerror("glp_ios_branch_upon: j = %d; column number out of rang"
168.548 + "e\n", j);
168.549 + if (!(sel == GLP_DN_BRNCH || sel == GLP_UP_BRNCH ||
168.550 + sel == GLP_NO_BRNCH))
168.551 + xerror("glp_ios_branch_upon: sel = %d: invalid branch selectio"
168.552 + "n flag\n", sel);
168.553 + if (!(tree->non_int[j]))
168.554 + xerror("glp_ios_branch_upon: j = %d; variable cannot be used t"
168.555 + "o branch upon\n", j);
168.556 + if (tree->br_var != 0)
168.557 + xerror("glp_ios_branch_upon: branching variable already chosen"
168.558 + "\n");
168.559 + tree->br_var = j;
168.560 + tree->br_sel = sel;
168.561 + return;
168.562 +}
168.563 +
168.564 +/***********************************************************************
168.565 +* NAME
168.566 +*
168.567 +* glp_ios_select_node - select subproblem to continue the search
168.568 +*
168.569 +* SYNOPSIS
168.570 +*
168.571 +* void glp_ios_select_node(glp_tree *tree, int p);
168.572 +*
168.573 +* DESCRIPTION
168.574 +*
168.575 +* The routine glp_ios_select_node can be called from the user-defined
168.576 +* callback routine in response to the reason GLP_ISELECT to select an
168.577 +* active subproblem, whose reference number is p. The search will be
168.578 +* continued from the subproblem selected. */
168.579 +
168.580 +void glp_ios_select_node(glp_tree *tree, int p)
168.581 +{ IOSNPD *node;
168.582 + /* obtain pointer to the specified subproblem */
168.583 + if (!(1 <= p && p <= tree->nslots))
168.584 +err: xerror("glp_ios_select_node: p = %d; invalid subproblem refere"
168.585 + "nce number\n", p);
168.586 + node = tree->slot[p].node;
168.587 + if (node == NULL) goto err;
168.588 + /* the specified subproblem must be active */
168.589 + if (node->count != 0)
168.590 + xerror("glp_ios_select_node: p = %d; subproblem not in the act"
168.591 + "ive list\n", p);
168.592 + /* no subproblem must be selected yet */
168.593 + if (tree->next_p != 0)
168.594 + xerror("glp_ios_select_node: subproblem already selected\n");
168.595 + /* select the specified subproblem to continue the search */
168.596 + tree->next_p = p;
168.597 + return;
168.598 +}
168.599 +
168.600 +/***********************************************************************
168.601 +* NAME
168.602 +*
168.603 +* glp_ios_heur_sol - provide solution found by heuristic
168.604 +*
168.605 +* SYNOPSIS
168.606 +*
168.607 +* int glp_ios_heur_sol(glp_tree *tree, const double x[]);
168.608 +*
168.609 +* DESCRIPTION
168.610 +*
168.611 +* The routine glp_ios_heur_sol can be called from the user-defined
168.612 +* callback routine in response to the reason GLP_IHEUR to provide an
168.613 +* integer feasible solution found by a primal heuristic.
168.614 +*
168.615 +* Primal values of *all* variables (columns) found by the heuristic
168.616 +* should be placed in locations x[1], ..., x[n], where n is the number
168.617 +* of columns in the original problem object. Note that the routine
168.618 +* glp_ios_heur_sol *does not* check primal feasibility of the solution
168.619 +* provided.
168.620 +*
168.621 +* Using the solution passed in the array x the routine computes value
168.622 +* of the objective function. If the objective value is better than the
168.623 +* best known integer feasible solution, the routine computes values of
168.624 +* auxiliary variables (rows) and stores all solution components in the
168.625 +* problem object.
168.626 +*
168.627 +* RETURNS
168.628 +*
168.629 +* If the provided solution is accepted, the routine glp_ios_heur_sol
168.630 +* returns zero. Otherwise, if the provided solution is rejected, the
168.631 +* routine returns non-zero. */
168.632 +
168.633 +int glp_ios_heur_sol(glp_tree *tree, const double x[])
168.634 +{ glp_prob *mip = tree->mip;
168.635 + int m = tree->orig_m;
168.636 + int n = tree->n;
168.637 + int i, j;
168.638 + double obj;
168.639 + xassert(mip->m >= m);
168.640 + xassert(mip->n == n);
168.641 + /* check values of integer variables and compute value of the
168.642 + objective function */
168.643 + obj = mip->c0;
168.644 + for (j = 1; j <= n; j++)
168.645 + { GLPCOL *col = mip->col[j];
168.646 + if (col->kind == GLP_IV)
168.647 + { /* provided value must be integral */
168.648 + if (x[j] != floor(x[j])) return 1;
168.649 + }
168.650 + obj += col->coef * x[j];
168.651 + }
168.652 + /* check if the provided solution is better than the best known
168.653 + integer feasible solution */
168.654 + if (mip->mip_stat == GLP_FEAS)
168.655 + { switch (mip->dir)
168.656 + { case GLP_MIN:
168.657 + if (obj >= tree->mip->mip_obj) return 1;
168.658 + break;
168.659 + case GLP_MAX:
168.660 + if (obj <= tree->mip->mip_obj) return 1;
168.661 + break;
168.662 + default:
168.663 + xassert(mip != mip);
168.664 + }
168.665 + }
168.666 + /* it is better; store it in the problem object */
168.667 + if (tree->parm->msg_lev >= GLP_MSG_ON)
168.668 + xprintf("Solution found by heuristic: %.12g\n", obj);
168.669 + mip->mip_stat = GLP_FEAS;
168.670 + mip->mip_obj = obj;
168.671 + for (j = 1; j <= n; j++)
168.672 + mip->col[j]->mipx = x[j];
168.673 + for (i = 1; i <= m; i++)
168.674 + { GLPROW *row = mip->row[i];
168.675 + GLPAIJ *aij;
168.676 + row->mipx = 0.0;
168.677 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
168.678 + row->mipx += aij->val * aij->col->mipx;
168.679 + }
168.680 + return 0;
168.681 +}
168.682 +
168.683 +/***********************************************************************
168.684 +* NAME
168.685 +*
168.686 +* glp_ios_terminate - terminate the solution process.
168.687 +*
168.688 +* SYNOPSIS
168.689 +*
168.690 +* void glp_ios_terminate(glp_tree *tree);
168.691 +*
168.692 +* DESCRIPTION
168.693 +*
168.694 +* The routine glp_ios_terminate sets a flag indicating that the MIP
168.695 +* solver should prematurely terminate the search. */
168.696 +
168.697 +void glp_ios_terminate(glp_tree *tree)
168.698 +{ if (tree->parm->msg_lev >= GLP_MSG_DBG)
168.699 + xprintf("The search is prematurely terminated due to applicati"
168.700 + "on request\n");
168.701 + tree->stop = 1;
168.702 + return;
168.703 +}
168.704 +
168.705 +/* eof */
169.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
169.2 +++ b/src/glpapi14.c Mon Dec 06 13:09:21 2010 +0100
169.3 @@ -0,0 +1,274 @@
169.4 +/* glpapi14.c (processing models in GNU MathProg language) */
169.5 +
169.6 +/***********************************************************************
169.7 +* This code is part of GLPK (GNU Linear Programming Kit).
169.8 +*
169.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
169.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
169.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
169.12 +* E-mail: <mao@gnu.org>.
169.13 +*
169.14 +* GLPK is free software: you can redistribute it and/or modify it
169.15 +* under the terms of the GNU General Public License as published by
169.16 +* the Free Software Foundation, either version 3 of the License, or
169.17 +* (at your option) any later version.
169.18 +*
169.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
169.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
169.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
169.22 +* License for more details.
169.23 +*
169.24 +* You should have received a copy of the GNU General Public License
169.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
169.26 +***********************************************************************/
169.27 +
169.28 +#define GLP_TRAN_DEFINED
169.29 +typedef struct MPL glp_tran;
169.30 +
169.31 +#include "glpmpl.h"
169.32 +#include "glpapi.h"
169.33 +
169.34 +glp_tran *glp_mpl_alloc_wksp(void)
169.35 +{ /* allocate the MathProg translator workspace */
169.36 + glp_tran *tran;
169.37 + tran = mpl_initialize();
169.38 + return tran;
169.39 +}
169.40 +
169.41 +#if 1 /* 08/XII-2009 */
169.42 +void _glp_mpl_init_rand(glp_tran *tran, int seed)
169.43 +{ if (tran->phase != 0)
169.44 + xerror("glp_mpl_init_rand: invalid call sequence\n");
169.45 + rng_init_rand(tran->rand, seed);
169.46 + return;
169.47 +}
169.48 +#endif
169.49 +
169.50 +int glp_mpl_read_model(glp_tran *tran, const char *fname, int skip)
169.51 +{ /* read and translate model section */
169.52 + int ret;
169.53 + if (tran->phase != 0)
169.54 + xerror("glp_mpl_read_model: invalid call sequence\n");
169.55 + ret = mpl_read_model(tran, (char *)fname, skip);
169.56 + if (ret == 1 || ret == 2)
169.57 + ret = 0;
169.58 + else if (ret == 4)
169.59 + ret = 1;
169.60 + else
169.61 + xassert(ret != ret);
169.62 + return ret;
169.63 +}
169.64 +
169.65 +int glp_mpl_read_data(glp_tran *tran, const char *fname)
169.66 +{ /* read and translate data section */
169.67 + int ret;
169.68 + if (!(tran->phase == 1 || tran->phase == 2))
169.69 + xerror("glp_mpl_read_data: invalid call sequence\n");
169.70 + ret = mpl_read_data(tran, (char *)fname);
169.71 + if (ret == 2)
169.72 + ret = 0;
169.73 + else if (ret == 4)
169.74 + ret = 1;
169.75 + else
169.76 + xassert(ret != ret);
169.77 + return ret;
169.78 +}
169.79 +
169.80 +int glp_mpl_generate(glp_tran *tran, const char *fname)
169.81 +{ /* generate the model */
169.82 + int ret;
169.83 + if (!(tran->phase == 1 || tran->phase == 2))
169.84 + xerror("glp_mpl_generate: invalid call sequence\n");
169.85 + ret = mpl_generate(tran, (char *)fname);
169.86 + if (ret == 3)
169.87 + ret = 0;
169.88 + else if (ret == 4)
169.89 + ret = 1;
169.90 + return ret;
169.91 +}
169.92 +
169.93 +void glp_mpl_build_prob(glp_tran *tran, glp_prob *prob)
169.94 +{ /* build LP/MIP problem instance from the model */
169.95 + int m, n, i, j, t, kind, type, len, *ind;
169.96 + double lb, ub, *val;
169.97 + if (tran->phase != 3)
169.98 + xerror("glp_mpl_build_prob: invalid call sequence\n");
169.99 + /* erase the problem object */
169.100 + glp_erase_prob(prob);
169.101 + /* set problem name */
169.102 + glp_set_prob_name(prob, mpl_get_prob_name(tran));
169.103 + /* build rows (constraints) */
169.104 + m = mpl_get_num_rows(tran);
169.105 + if (m > 0)
169.106 + glp_add_rows(prob, m);
169.107 + for (i = 1; i <= m; i++)
169.108 + { /* set row name */
169.109 + glp_set_row_name(prob, i, mpl_get_row_name(tran, i));
169.110 + /* set row bounds */
169.111 + type = mpl_get_row_bnds(tran, i, &lb, &ub);
169.112 + switch (type)
169.113 + { case MPL_FR: type = GLP_FR; break;
169.114 + case MPL_LO: type = GLP_LO; break;
169.115 + case MPL_UP: type = GLP_UP; break;
169.116 + case MPL_DB: type = GLP_DB; break;
169.117 + case MPL_FX: type = GLP_FX; break;
169.118 + default: xassert(type != type);
169.119 + }
169.120 + if (type == GLP_DB && fabs(lb - ub) < 1e-9 * (1.0 + fabs(lb)))
169.121 + { type = GLP_FX;
169.122 + if (fabs(lb) <= fabs(ub)) ub = lb; else lb = ub;
169.123 + }
169.124 + glp_set_row_bnds(prob, i, type, lb, ub);
169.125 + /* warn about non-zero constant term */
169.126 + if (mpl_get_row_c0(tran, i) != 0.0)
169.127 + xprintf("glp_mpl_build_prob: row %s; constant term %.12g ig"
169.128 + "nored\n",
169.129 + mpl_get_row_name(tran, i), mpl_get_row_c0(tran, i));
169.130 + }
169.131 + /* build columns (variables) */
169.132 + n = mpl_get_num_cols(tran);
169.133 + if (n > 0)
169.134 + glp_add_cols(prob, n);
169.135 + for (j = 1; j <= n; j++)
169.136 + { /* set column name */
169.137 + glp_set_col_name(prob, j, mpl_get_col_name(tran, j));
169.138 + /* set column kind */
169.139 + kind = mpl_get_col_kind(tran, j);
169.140 + switch (kind)
169.141 + { case MPL_NUM:
169.142 + break;
169.143 + case MPL_INT:
169.144 + case MPL_BIN:
169.145 + glp_set_col_kind(prob, j, GLP_IV);
169.146 + break;
169.147 + default:
169.148 + xassert(kind != kind);
169.149 + }
169.150 + /* set column bounds */
169.151 + type = mpl_get_col_bnds(tran, j, &lb, &ub);
169.152 + switch (type)
169.153 + { case MPL_FR: type = GLP_FR; break;
169.154 + case MPL_LO: type = GLP_LO; break;
169.155 + case MPL_UP: type = GLP_UP; break;
169.156 + case MPL_DB: type = GLP_DB; break;
169.157 + case MPL_FX: type = GLP_FX; break;
169.158 + default: xassert(type != type);
169.159 + }
169.160 + if (kind == MPL_BIN)
169.161 + { if (type == GLP_FR || type == GLP_UP || lb < 0.0) lb = 0.0;
169.162 + if (type == GLP_FR || type == GLP_LO || ub > 1.0) ub = 1.0;
169.163 + type = GLP_DB;
169.164 + }
169.165 + if (type == GLP_DB && fabs(lb - ub) < 1e-9 * (1.0 + fabs(lb)))
169.166 + { type = GLP_FX;
169.167 + if (fabs(lb) <= fabs(ub)) ub = lb; else lb = ub;
169.168 + }
169.169 + glp_set_col_bnds(prob, j, type, lb, ub);
169.170 + }
169.171 + /* load the constraint matrix */
169.172 + ind = xcalloc(1+n, sizeof(int));
169.173 + val = xcalloc(1+n, sizeof(double));
169.174 + for (i = 1; i <= m; i++)
169.175 + { len = mpl_get_mat_row(tran, i, ind, val);
169.176 + glp_set_mat_row(prob, i, len, ind, val);
169.177 + }
169.178 + /* build objective function (the first objective is used) */
169.179 + for (i = 1; i <= m; i++)
169.180 + { kind = mpl_get_row_kind(tran, i);
169.181 + if (kind == MPL_MIN || kind == MPL_MAX)
169.182 + { /* set objective name */
169.183 + glp_set_obj_name(prob, mpl_get_row_name(tran, i));
169.184 + /* set optimization direction */
169.185 + glp_set_obj_dir(prob, kind == MPL_MIN ? GLP_MIN : GLP_MAX);
169.186 + /* set constant term */
169.187 + glp_set_obj_coef(prob, 0, mpl_get_row_c0(tran, i));
169.188 + /* set objective coefficients */
169.189 + len = mpl_get_mat_row(tran, i, ind, val);
169.190 + for (t = 1; t <= len; t++)
169.191 + glp_set_obj_coef(prob, ind[t], val[t]);
169.192 + break;
169.193 + }
169.194 + }
169.195 + /* free working arrays */
169.196 + xfree(ind);
169.197 + xfree(val);
169.198 + return;
169.199 +}
169.200 +
169.201 +int glp_mpl_postsolve(glp_tran *tran, glp_prob *prob, int sol)
169.202 +{ /* postsolve the model */
169.203 + int i, j, m, n, stat, ret;
169.204 + double prim, dual;
169.205 + if (!(tran->phase == 3 && !tran->flag_p))
169.206 + xerror("glp_mpl_postsolve: invalid call sequence\n");
169.207 + if (!(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP))
169.208 + xerror("glp_mpl_postsolve: sol = %d; invalid parameter\n",
169.209 + sol);
169.210 + m = mpl_get_num_rows(tran);
169.211 + n = mpl_get_num_cols(tran);
169.212 + if (!(m == glp_get_num_rows(prob) &&
169.213 + n == glp_get_num_cols(prob)))
169.214 + xerror("glp_mpl_postsolve: wrong problem object\n");
169.215 + if (!mpl_has_solve_stmt(tran))
169.216 + { ret = 0;
169.217 + goto done;
169.218 + }
169.219 + for (i = 1; i <= m; i++)
169.220 + { if (sol == GLP_SOL)
169.221 + { stat = glp_get_row_stat(prob, i);
169.222 + prim = glp_get_row_prim(prob, i);
169.223 + dual = glp_get_row_dual(prob, i);
169.224 + }
169.225 + else if (sol == GLP_IPT)
169.226 + { stat = 0;
169.227 + prim = glp_ipt_row_prim(prob, i);
169.228 + dual = glp_ipt_row_dual(prob, i);
169.229 + }
169.230 + else if (sol == GLP_MIP)
169.231 + { stat = 0;
169.232 + prim = glp_mip_row_val(prob, i);
169.233 + dual = 0.0;
169.234 + }
169.235 + else
169.236 + xassert(sol != sol);
169.237 + if (fabs(prim) < 1e-9) prim = 0.0;
169.238 + if (fabs(dual) < 1e-9) dual = 0.0;
169.239 + mpl_put_row_soln(tran, i, stat, prim, dual);
169.240 + }
169.241 + for (j = 1; j <= n; j++)
169.242 + { if (sol == GLP_SOL)
169.243 + { stat = glp_get_col_stat(prob, j);
169.244 + prim = glp_get_col_prim(prob, j);
169.245 + dual = glp_get_col_dual(prob, j);
169.246 + }
169.247 + else if (sol == GLP_IPT)
169.248 + { stat = 0;
169.249 + prim = glp_ipt_col_prim(prob, j);
169.250 + dual = glp_ipt_col_dual(prob, j);
169.251 + }
169.252 + else if (sol == GLP_MIP)
169.253 + { stat = 0;
169.254 + prim = glp_mip_col_val(prob, j);
169.255 + dual = 0.0;
169.256 + }
169.257 + else
169.258 + xassert(sol != sol);
169.259 + if (fabs(prim) < 1e-9) prim = 0.0;
169.260 + if (fabs(dual) < 1e-9) dual = 0.0;
169.261 + mpl_put_col_soln(tran, j, stat, prim, dual);
169.262 + }
169.263 + ret = mpl_postsolve(tran);
169.264 + if (ret == 3)
169.265 + ret = 0;
169.266 + else if (ret == 4)
169.267 + ret = 1;
169.268 +done: return ret;
169.269 +}
169.270 +
169.271 +void glp_mpl_free_wksp(glp_tran *tran)
169.272 +{ /* free the MathProg translator workspace */
169.273 + mpl_terminate(tran);
169.274 + return;
169.275 +}
169.276 +
169.277 +/* eof */
170.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
170.2 +++ b/src/glpapi15.c Mon Dec 06 13:09:21 2010 +0100
170.3 @@ -0,0 +1,609 @@
170.4 +/* glpapi15.c (basic graph and network routines) */
170.5 +
170.6 +/***********************************************************************
170.7 +* This code is part of GLPK (GNU Linear Programming Kit).
170.8 +*
170.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
170.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
170.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
170.12 +* E-mail: <mao@gnu.org>.
170.13 +*
170.14 +* GLPK is free software: you can redistribute it and/or modify it
170.15 +* under the terms of the GNU General Public License as published by
170.16 +* the Free Software Foundation, either version 3 of the License, or
170.17 +* (at your option) any later version.
170.18 +*
170.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
170.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
170.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
170.22 +* License for more details.
170.23 +*
170.24 +* You should have received a copy of the GNU General Public License
170.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
170.26 +***********************************************************************/
170.27 +
170.28 +#include "glpapi.h"
170.29 +
170.30 +/* CAUTION: DO NOT CHANGE THE LIMITS BELOW */
170.31 +
170.32 +#define NV_MAX 100000000 /* = 100*10^6 */
170.33 +/* maximal number of vertices in the graph */
170.34 +
170.35 +#define NA_MAX 500000000 /* = 500*10^6 */
170.36 +/* maximal number of arcs in the graph */
170.37 +
170.38 +/***********************************************************************
170.39 +* NAME
170.40 +*
170.41 +* glp_create_graph - create graph
170.42 +*
170.43 +* SYNOPSIS
170.44 +*
170.45 +* glp_graph *glp_create_graph(int v_size, int a_size);
170.46 +*
170.47 +* DESCRIPTION
170.48 +*
170.49 +* The routine creates a new graph, which initially is empty, i.e. has
170.50 +* no vertices and arcs.
170.51 +*
170.52 +* The parameter v_size specifies the size of data associated with each
170.53 +* vertex of the graph (0 to 256 bytes).
170.54 +*
170.55 +* The parameter a_size specifies the size of data associated with each
170.56 +* arc of the graph (0 to 256 bytes).
170.57 +*
170.58 +* RETURNS
170.59 +*
170.60 +* The routine returns a pointer to the graph created. */
170.61 +
170.62 +static void create_graph(glp_graph *G, int v_size, int a_size)
170.63 +{ G->pool = dmp_create_pool();
170.64 + G->name = NULL;
170.65 + G->nv_max = 50;
170.66 + G->nv = G->na = 0;
170.67 + G->v = xcalloc(1+G->nv_max, sizeof(glp_vertex *));
170.68 + G->index = NULL;
170.69 + G->v_size = v_size;
170.70 + G->a_size = a_size;
170.71 + return;
170.72 +}
170.73 +
170.74 +glp_graph *glp_create_graph(int v_size, int a_size)
170.75 +{ glp_graph *G;
170.76 + if (!(0 <= v_size && v_size <= 256))
170.77 + xerror("glp_create_graph: v_size = %d; invalid size of vertex "
170.78 + "data\n", v_size);
170.79 + if (!(0 <= a_size && a_size <= 256))
170.80 + xerror("glp_create_graph: a_size = %d; invalid size of arc dat"
170.81 + "a\n", a_size);
170.82 + G = xmalloc(sizeof(glp_graph));
170.83 + create_graph(G, v_size, a_size);
170.84 + return G;
170.85 +}
170.86 +
170.87 +/***********************************************************************
170.88 +* NAME
170.89 +*
170.90 +* glp_set_graph_name - assign (change) graph name
170.91 +*
170.92 +* SYNOPSIS
170.93 +*
170.94 +* void glp_set_graph_name(glp_graph *G, const char *name);
170.95 +*
170.96 +* DESCRIPTION
170.97 +*
170.98 +* The routine glp_set_graph_name assigns a symbolic name specified by
170.99 +* the character string name (1 to 255 chars) to the graph.
170.100 +*
170.101 +* If the parameter name is NULL or an empty string, the routine erases
170.102 +* the existing symbolic name of the graph. */
170.103 +
170.104 +void glp_set_graph_name(glp_graph *G, const char *name)
170.105 +{ if (G->name != NULL)
170.106 + { dmp_free_atom(G->pool, G->name, strlen(G->name)+1);
170.107 + G->name = NULL;
170.108 + }
170.109 + if (!(name == NULL || name[0] == '\0'))
170.110 + { int j;
170.111 + for (j = 0; name[j] != '\0'; j++)
170.112 + { if (j == 256)
170.113 + xerror("glp_set_graph_name: graph name too long\n");
170.114 + if (iscntrl((unsigned char)name[j]))
170.115 + xerror("glp_set_graph_name: graph name contains invalid "
170.116 + "character(s)\n");
170.117 + }
170.118 + G->name = dmp_get_atom(G->pool, strlen(name)+1);
170.119 + strcpy(G->name, name);
170.120 + }
170.121 + return;
170.122 +}
170.123 +
170.124 +/***********************************************************************
170.125 +* NAME
170.126 +*
170.127 +* glp_add_vertices - add new vertices to graph
170.128 +*
170.129 +* SYNOPSIS
170.130 +*
170.131 +* int glp_add_vertices(glp_graph *G, int nadd);
170.132 +*
170.133 +* DESCRIPTION
170.134 +*
170.135 +* The routine glp_add_vertices adds nadd vertices to the specified
170.136 +* graph. New vertices are always added to the end of the vertex list,
170.137 +* so ordinal numbers of existing vertices remain unchanged.
170.138 +*
170.139 +* Being added each new vertex is isolated (has no incident arcs).
170.140 +*
170.141 +* RETURNS
170.142 +*
170.143 +* The routine glp_add_vertices returns an ordinal number of the first
170.144 +* new vertex added to the graph. */
170.145 +
170.146 +int glp_add_vertices(glp_graph *G, int nadd)
170.147 +{ int i, nv_new;
170.148 + if (nadd < 1)
170.149 + xerror("glp_add_vertices: nadd = %d; invalid number of vertice"
170.150 + "s\n", nadd);
170.151 + if (nadd > NV_MAX - G->nv)
170.152 + xerror("glp_add_vertices: nadd = %d; too many vertices\n",
170.153 + nadd);
170.154 + /* determine new number of vertices */
170.155 + nv_new = G->nv + nadd;
170.156 + /* increase the room, if necessary */
170.157 + if (G->nv_max < nv_new)
170.158 + { glp_vertex **save = G->v;
170.159 + while (G->nv_max < nv_new)
170.160 + { G->nv_max += G->nv_max;
170.161 + xassert(G->nv_max > 0);
170.162 + }
170.163 + G->v = xcalloc(1+G->nv_max, sizeof(glp_vertex *));
170.164 + memcpy(&G->v[1], &save[1], G->nv * sizeof(glp_vertex *));
170.165 + xfree(save);
170.166 + }
170.167 + /* add new vertices to the end of the vertex list */
170.168 + for (i = G->nv+1; i <= nv_new; i++)
170.169 + { glp_vertex *v;
170.170 + G->v[i] = v = dmp_get_atom(G->pool, sizeof(glp_vertex));
170.171 + v->i = i;
170.172 + v->name = NULL;
170.173 + v->entry = NULL;
170.174 + if (G->v_size == 0)
170.175 + v->data = NULL;
170.176 + else
170.177 + { v->data = dmp_get_atom(G->pool, G->v_size);
170.178 + memset(v->data, 0, G->v_size);
170.179 + }
170.180 + v->temp = NULL;
170.181 + v->in = v->out = NULL;
170.182 + }
170.183 + /* set new number of vertices */
170.184 + G->nv = nv_new;
170.185 + /* return the ordinal number of the first vertex added */
170.186 + return nv_new - nadd + 1;
170.187 +}
170.188 +
170.189 +/**********************************************************************/
170.190 +
170.191 +void glp_set_vertex_name(glp_graph *G, int i, const char *name)
170.192 +{ /* assign (change) vertex name */
170.193 + glp_vertex *v;
170.194 + if (!(1 <= i && i <= G->nv))
170.195 + xerror("glp_set_vertex_name: i = %d; vertex number out of rang"
170.196 + "e\n", i);
170.197 + v = G->v[i];
170.198 + if (v->name != NULL)
170.199 + { if (v->entry != NULL)
170.200 + { xassert(G->index != NULL);
170.201 + avl_delete_node(G->index, v->entry);
170.202 + v->entry = NULL;
170.203 + }
170.204 + dmp_free_atom(G->pool, v->name, strlen(v->name)+1);
170.205 + v->name = NULL;
170.206 + }
170.207 + if (!(name == NULL || name[0] == '\0'))
170.208 + { int k;
170.209 + for (k = 0; name[k] != '\0'; k++)
170.210 + { if (k == 256)
170.211 + xerror("glp_set_vertex_name: i = %d; vertex name too lon"
170.212 + "g\n", i);
170.213 + if (iscntrl((unsigned char)name[k]))
170.214 + xerror("glp_set_vertex_name: i = %d; vertex name contain"
170.215 + "s invalid character(s)\n", i);
170.216 + }
170.217 + v->name = dmp_get_atom(G->pool, strlen(name)+1);
170.218 + strcpy(v->name, name);
170.219 + if (G->index != NULL)
170.220 + { xassert(v->entry == NULL);
170.221 + v->entry = avl_insert_node(G->index, v->name);
170.222 + avl_set_node_link(v->entry, v);
170.223 + }
170.224 + }
170.225 + return;
170.226 +}
170.227 +
170.228 +/***********************************************************************
170.229 +* NAME
170.230 +*
170.231 +* glp_add_arc - add new arc to graph
170.232 +*
170.233 +* SYNOPSIS
170.234 +*
170.235 +* glp_arc *glp_add_arc(glp_graph *G, int i, int j);
170.236 +*
170.237 +* DESCRIPTION
170.238 +*
170.239 +* The routine glp_add_arc adds a new arc to the specified graph.
170.240 +*
170.241 +* The parameters i and j specify the ordinal numbers of, resp., tail
170.242 +* and head vertices of the arc. Note that self-loops and multiple arcs
170.243 +* are allowed.
170.244 +*
170.245 +* RETURNS
170.246 +*
170.247 +* The routine glp_add_arc returns a pointer to the arc added. */
170.248 +
170.249 +glp_arc *glp_add_arc(glp_graph *G, int i, int j)
170.250 +{ glp_arc *a;
170.251 + if (!(1 <= i && i <= G->nv))
170.252 + xerror("glp_add_arc: i = %d; tail vertex number out of range\n"
170.253 + , i);
170.254 + if (!(1 <= j && j <= G->nv))
170.255 + xerror("glp_add_arc: j = %d; head vertex number out of range\n"
170.256 + , j);
170.257 + if (G->na == NA_MAX)
170.258 + xerror("glp_add_arc: too many arcs\n");
170.259 + a = dmp_get_atom(G->pool, sizeof(glp_arc));
170.260 + a->tail = G->v[i];
170.261 + a->head = G->v[j];
170.262 + if (G->a_size == 0)
170.263 + a->data = NULL;
170.264 + else
170.265 + { a->data = dmp_get_atom(G->pool, G->a_size);
170.266 + memset(a->data, 0, G->a_size);
170.267 + }
170.268 + a->temp = NULL;
170.269 + a->t_prev = NULL;
170.270 + a->t_next = G->v[i]->out;
170.271 + if (a->t_next != NULL) a->t_next->t_prev = a;
170.272 + a->h_prev = NULL;
170.273 + a->h_next = G->v[j]->in;
170.274 + if (a->h_next != NULL) a->h_next->h_prev = a;
170.275 + G->v[i]->out = G->v[j]->in = a;
170.276 + G->na++;
170.277 + return a;
170.278 +}
170.279 +
170.280 +/***********************************************************************
170.281 +* NAME
170.282 +*
170.283 +* glp_del_vertices - delete vertices from graph
170.284 +*
170.285 +* SYNOPSIS
170.286 +*
170.287 +* void glp_del_vertices(glp_graph *G, int ndel, const int num[]);
170.288 +*
170.289 +* DESCRIPTION
170.290 +*
170.291 +* The routine glp_del_vertices deletes vertices along with all
170.292 +* incident arcs from the specified graph. Ordinal numbers of vertices
170.293 +* to be deleted should be placed in locations num[1], ..., num[ndel],
170.294 +* ndel > 0.
170.295 +*
170.296 +* Note that deleting vertices involves changing ordinal numbers of
170.297 +* other vertices remaining in the graph. New ordinal numbers of the
170.298 +* remaining vertices are assigned under the assumption that the
170.299 +* original order of vertices is not changed. */
170.300 +
170.301 +void glp_del_vertices(glp_graph *G, int ndel, const int num[])
170.302 +{ glp_vertex *v;
170.303 + int i, k, nv_new;
170.304 + /* scan the list of vertices to be deleted */
170.305 + if (!(1 <= ndel && ndel <= G->nv))
170.306 + xerror("glp_del_vertices: ndel = %d; invalid number of vertice"
170.307 + "s\n", ndel);
170.308 + for (k = 1; k <= ndel; k++)
170.309 + { /* take the number of vertex to be deleted */
170.310 + i = num[k];
170.311 + /* obtain pointer to i-th vertex */
170.312 + if (!(1 <= i && i <= G->nv))
170.313 + xerror("glp_del_vertices: num[%d] = %d; vertex number out o"
170.314 + "f range\n", k, i);
170.315 + v = G->v[i];
170.316 + /* check that the vertex is not marked yet */
170.317 + if (v->i == 0)
170.318 + xerror("glp_del_vertices: num[%d] = %d; duplicate vertex nu"
170.319 + "mbers not allowed\n", k, i);
170.320 + /* erase symbolic name assigned to the vertex */
170.321 + glp_set_vertex_name(G, i, NULL);
170.322 + xassert(v->name == NULL);
170.323 + xassert(v->entry == NULL);
170.324 + /* free vertex data, if allocated */
170.325 + if (v->data != NULL)
170.326 + dmp_free_atom(G->pool, v->data, G->v_size);
170.327 + /* delete all incoming arcs */
170.328 + while (v->in != NULL)
170.329 + glp_del_arc(G, v->in);
170.330 + /* delete all outgoing arcs */
170.331 + while (v->out != NULL)
170.332 + glp_del_arc(G, v->out);
170.333 + /* mark the vertex to be deleted */
170.334 + v->i = 0;
170.335 + }
170.336 + /* delete all marked vertices from the vertex list */
170.337 + nv_new = 0;
170.338 + for (i = 1; i <= G->nv; i++)
170.339 + { /* obtain pointer to i-th vertex */
170.340 + v = G->v[i];
170.341 + /* check if the vertex is marked */
170.342 + if (v->i == 0)
170.343 + { /* it is marked, delete it */
170.344 + dmp_free_atom(G->pool, v, sizeof(glp_vertex));
170.345 + }
170.346 + else
170.347 + { /* it is not marked, keep it */
170.348 + v->i = ++nv_new;
170.349 + G->v[v->i] = v;
170.350 + }
170.351 + }
170.352 + /* set new number of vertices in the graph */
170.353 + G->nv = nv_new;
170.354 + return;
170.355 +}
170.356 +
170.357 +/***********************************************************************
170.358 +* NAME
170.359 +*
170.360 +* glp_del_arc - delete arc from graph
170.361 +*
170.362 +* SYNOPSIS
170.363 +*
170.364 +* void glp_del_arc(glp_graph *G, glp_arc *a);
170.365 +*
170.366 +* DESCRIPTION
170.367 +*
170.368 +* The routine glp_del_arc deletes an arc from the specified graph.
170.369 +* The arc to be deleted must exist. */
170.370 +
170.371 +void glp_del_arc(glp_graph *G, glp_arc *a)
170.372 +{ /* some sanity checks */
170.373 + xassert(G->na > 0);
170.374 + xassert(1 <= a->tail->i && a->tail->i <= G->nv);
170.375 + xassert(a->tail == G->v[a->tail->i]);
170.376 + xassert(1 <= a->head->i && a->head->i <= G->nv);
170.377 + xassert(a->head == G->v[a->head->i]);
170.378 + /* remove the arc from the list of incoming arcs */
170.379 + if (a->h_prev == NULL)
170.380 + a->head->in = a->h_next;
170.381 + else
170.382 + a->h_prev->h_next = a->h_next;
170.383 + if (a->h_next == NULL)
170.384 + ;
170.385 + else
170.386 + a->h_next->h_prev = a->h_prev;
170.387 + /* remove the arc from the list of outgoing arcs */
170.388 + if (a->t_prev == NULL)
170.389 + a->tail->out = a->t_next;
170.390 + else
170.391 + a->t_prev->t_next = a->t_next;
170.392 + if (a->t_next == NULL)
170.393 + ;
170.394 + else
170.395 + a->t_next->t_prev = a->t_prev;
170.396 + /* free arc data, if allocated */
170.397 + if (a->data != NULL)
170.398 + dmp_free_atom(G->pool, a->data, G->a_size);
170.399 + /* delete the arc from the graph */
170.400 + dmp_free_atom(G->pool, a, sizeof(glp_arc));
170.401 + G->na--;
170.402 + return;
170.403 +}
170.404 +
170.405 +/***********************************************************************
170.406 +* NAME
170.407 +*
170.408 +* glp_erase_graph - erase graph content
170.409 +*
170.410 +* SYNOPSIS
170.411 +*
170.412 +* void glp_erase_graph(glp_graph *G, int v_size, int a_size);
170.413 +*
170.414 +* DESCRIPTION
170.415 +*
170.416 +* The routine glp_erase_graph erases the content of the specified
170.417 +* graph. The effect of this operation is the same as if the graph
170.418 +* would be deleted with the routine glp_delete_graph and then created
170.419 +* anew with the routine glp_create_graph, with exception that the
170.420 +* handle (pointer) to the graph remains valid. */
170.421 +
170.422 +static void delete_graph(glp_graph *G)
170.423 +{ dmp_delete_pool(G->pool);
170.424 + xfree(G->v);
170.425 + if (G->index != NULL) avl_delete_tree(G->index);
170.426 + return;
170.427 +}
170.428 +
170.429 +void glp_erase_graph(glp_graph *G, int v_size, int a_size)
170.430 +{ if (!(0 <= v_size && v_size <= 256))
170.431 + xerror("glp_erase_graph: v_size = %d; invalid size of vertex d"
170.432 + "ata\n", v_size);
170.433 + if (!(0 <= a_size && a_size <= 256))
170.434 + xerror("glp_erase_graph: a_size = %d; invalid size of arc data"
170.435 + "\n", a_size);
170.436 + delete_graph(G);
170.437 + create_graph(G, v_size, a_size);
170.438 + return;
170.439 +}
170.440 +
170.441 +/***********************************************************************
170.442 +* NAME
170.443 +*
170.444 +* glp_delete_graph - delete graph
170.445 +*
170.446 +* SYNOPSIS
170.447 +*
170.448 +* void glp_delete_graph(glp_graph *G);
170.449 +*
170.450 +* DESCRIPTION
170.451 +*
170.452 +* The routine glp_delete_graph deletes the specified graph and frees
170.453 +* all the memory allocated to this program object. */
170.454 +
170.455 +void glp_delete_graph(glp_graph *G)
170.456 +{ delete_graph(G);
170.457 + xfree(G);
170.458 + return;
170.459 +}
170.460 +
170.461 +/**********************************************************************/
170.462 +
170.463 +void glp_create_v_index(glp_graph *G)
170.464 +{ /* create vertex name index */
170.465 + glp_vertex *v;
170.466 + int i;
170.467 + if (G->index == NULL)
170.468 + { G->index = avl_create_tree(avl_strcmp, NULL);
170.469 + for (i = 1; i <= G->nv; i++)
170.470 + { v = G->v[i];
170.471 + xassert(v->entry == NULL);
170.472 + if (v->name != NULL)
170.473 + { v->entry = avl_insert_node(G->index, v->name);
170.474 + avl_set_node_link(v->entry, v);
170.475 + }
170.476 + }
170.477 + }
170.478 + return;
170.479 +}
170.480 +
170.481 +int glp_find_vertex(glp_graph *G, const char *name)
170.482 +{ /* find vertex by its name */
170.483 + AVLNODE *node;
170.484 + int i = 0;
170.485 + if (G->index == NULL)
170.486 + xerror("glp_find_vertex: vertex name index does not exist\n");
170.487 + if (!(name == NULL || name[0] == '\0' || strlen(name) > 255))
170.488 + { node = avl_find_node(G->index, name);
170.489 + if (node != NULL)
170.490 + i = ((glp_vertex *)avl_get_node_link(node))->i;
170.491 + }
170.492 + return i;
170.493 +}
170.494 +
170.495 +void glp_delete_v_index(glp_graph *G)
170.496 +{ /* delete vertex name index */
170.497 + int i;
170.498 + if (G->index != NULL)
170.499 + { avl_delete_tree(G->index), G->index = NULL;
170.500 + for (i = 1; i <= G->nv; i++) G->v[i]->entry = NULL;
170.501 + }
170.502 + return;
170.503 +}
170.504 +
170.505 +/***********************************************************************
170.506 +* NAME
170.507 +*
170.508 +* glp_read_graph - read graph from plain text file
170.509 +*
170.510 +* SYNOPSIS
170.511 +*
170.512 +* int glp_read_graph(glp_graph *G, const char *fname);
170.513 +*
170.514 +* DESCRIPTION
170.515 +*
170.516 +* The routine glp_read_graph reads a graph from a plain text file.
170.517 +*
170.518 +* RETURNS
170.519 +*
170.520 +* If the operation was successful, the routine returns zero. Otherwise
170.521 +* it prints an error message and returns non-zero. */
170.522 +
170.523 +int glp_read_graph(glp_graph *G, const char *fname)
170.524 +{ glp_data *data;
170.525 + jmp_buf jump;
170.526 + int nv, na, i, j, k, ret;
170.527 + glp_erase_graph(G, G->v_size, G->a_size);
170.528 + xprintf("Reading graph from `%s'...\n", fname);
170.529 + data = glp_sdf_open_file(fname);
170.530 + if (data == NULL)
170.531 + { ret = 1;
170.532 + goto done;
170.533 + }
170.534 + if (setjmp(jump))
170.535 + { ret = 1;
170.536 + goto done;
170.537 + }
170.538 + glp_sdf_set_jump(data, jump);
170.539 + nv = glp_sdf_read_int(data);
170.540 + if (nv < 0)
170.541 + glp_sdf_error(data, "invalid number of vertices\n");
170.542 + na = glp_sdf_read_int(data);
170.543 + if (na < 0)
170.544 + glp_sdf_error(data, "invalid number of arcs\n");
170.545 + xprintf("Graph has %d vert%s and %d arc%s\n",
170.546 + nv, nv == 1 ? "ex" : "ices", na, na == 1 ? "" : "s");
170.547 + if (nv > 0) glp_add_vertices(G, nv);
170.548 + for (k = 1; k <= na; k++)
170.549 + { i = glp_sdf_read_int(data);
170.550 + if (!(1 <= i && i <= nv))
170.551 + glp_sdf_error(data, "tail vertex number out of range\n");
170.552 + j = glp_sdf_read_int(data);
170.553 + if (!(1 <= j && j <= nv))
170.554 + glp_sdf_error(data, "head vertex number out of range\n");
170.555 + glp_add_arc(G, i, j);
170.556 + }
170.557 + xprintf("%d lines were read\n", glp_sdf_line(data));
170.558 + ret = 0;
170.559 +done: if (data != NULL) glp_sdf_close_file(data);
170.560 + return ret;
170.561 +}
170.562 +
170.563 +/***********************************************************************
170.564 +* NAME
170.565 +*
170.566 +* glp_write_graph - write graph to plain text file
170.567 +*
170.568 +* SYNOPSIS
170.569 +*
170.570 +* int glp_write_graph(glp_graph *G, const char *fname).
170.571 +*
170.572 +* DESCRIPTION
170.573 +*
170.574 +* The routine glp_write_graph writes the specified graph to a plain
170.575 +* text file.
170.576 +*
170.577 +* RETURNS
170.578 +*
170.579 +* If the operation was successful, the routine returns zero. Otherwise
170.580 +* it prints an error message and returns non-zero. */
170.581 +
170.582 +int glp_write_graph(glp_graph *G, const char *fname)
170.583 +{ XFILE *fp;
170.584 + glp_vertex *v;
170.585 + glp_arc *a;
170.586 + int i, count, ret;
170.587 + xprintf("Writing graph to `%s'...\n", fname);
170.588 + fp = xfopen(fname, "w"), count = 0;
170.589 + if (fp == NULL)
170.590 + { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
170.591 + ret = 1;
170.592 + goto done;
170.593 + }
170.594 + xfprintf(fp, "%d %d\n", G->nv, G->na), count++;
170.595 + for (i = 1; i <= G->nv; i++)
170.596 + { v = G->v[i];
170.597 + for (a = v->out; a != NULL; a = a->t_next)
170.598 + xfprintf(fp, "%d %d\n", a->tail->i, a->head->i), count++;
170.599 + }
170.600 + xfflush(fp);
170.601 + if (xferror(fp))
170.602 + { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
170.603 + ret = 1;
170.604 + goto done;
170.605 + }
170.606 + xprintf("%d lines were written\n", count);
170.607 + ret = 0;
170.608 +done: if (fp != NULL) xfclose(fp);
170.609 + return ret;
170.610 +}
170.611 +
170.612 +/* eof */
171.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
171.2 +++ b/src/glpapi16.c Mon Dec 06 13:09:21 2010 +0100
171.3 @@ -0,0 +1,329 @@
171.4 +/* glpapi16.c (graph and network analysis routines) */
171.5 +
171.6 +/***********************************************************************
171.7 +* This code is part of GLPK (GNU Linear Programming Kit).
171.8 +*
171.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
171.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
171.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
171.12 +* E-mail: <mao@gnu.org>.
171.13 +*
171.14 +* GLPK is free software: you can redistribute it and/or modify it
171.15 +* under the terms of the GNU General Public License as published by
171.16 +* the Free Software Foundation, either version 3 of the License, or
171.17 +* (at your option) any later version.
171.18 +*
171.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
171.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
171.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
171.22 +* License for more details.
171.23 +*
171.24 +* You should have received a copy of the GNU General Public License
171.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
171.26 +***********************************************************************/
171.27 +
171.28 +#include "glpapi.h"
171.29 +#include "glpnet.h"
171.30 +
171.31 +/***********************************************************************
171.32 +* NAME
171.33 +*
171.34 +* glp_weak_comp - find all weakly connected components of graph
171.35 +*
171.36 +* SYNOPSIS
171.37 +*
171.38 +* int glp_weak_comp(glp_graph *G, int v_num);
171.39 +*
171.40 +* DESCRIPTION
171.41 +*
171.42 +* The routine glp_weak_comp finds all weakly connected components of
171.43 +* the specified graph.
171.44 +*
171.45 +* The parameter v_num specifies an offset of the field of type int
171.46 +* in the vertex data block, to which the routine stores the number of
171.47 +* a (weakly) connected component containing that vertex. If v_num < 0,
171.48 +* no component numbers are stored.
171.49 +*
171.50 +* The components are numbered in arbitrary order from 1 to nc, where
171.51 +* nc is the total number of components found, 0 <= nc <= |V|.
171.52 +*
171.53 +* RETURNS
171.54 +*
171.55 +* The routine returns nc, the total number of components found. */
171.56 +
171.57 +int glp_weak_comp(glp_graph *G, int v_num)
171.58 +{ glp_vertex *v;
171.59 + glp_arc *a;
171.60 + int f, i, j, nc, nv, pos1, pos2, *prev, *next, *list;
171.61 + if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
171.62 + xerror("glp_weak_comp: v_num = %d; invalid offset\n", v_num);
171.63 + nv = G->nv;
171.64 + if (nv == 0)
171.65 + { nc = 0;
171.66 + goto done;
171.67 + }
171.68 + /* allocate working arrays */
171.69 + prev = xcalloc(1+nv, sizeof(int));
171.70 + next = xcalloc(1+nv, sizeof(int));
171.71 + list = xcalloc(1+nv, sizeof(int));
171.72 + /* if vertex i is unlabelled, prev[i] is the index of previous
171.73 + unlabelled vertex, and next[i] is the index of next unlabelled
171.74 + vertex; if vertex i is labelled, then prev[i] < 0, and next[i]
171.75 + is the connected component number */
171.76 + /* initially all vertices are unlabelled */
171.77 + f = 1;
171.78 + for (i = 1; i <= nv; i++)
171.79 + prev[i] = i - 1, next[i] = i + 1;
171.80 + next[nv] = 0;
171.81 + /* main loop (until all vertices have been labelled) */
171.82 + nc = 0;
171.83 + while (f != 0)
171.84 + { /* take an unlabelled vertex */
171.85 + i = f;
171.86 + /* and remove it from the list of unlabelled vertices */
171.87 + f = next[i];
171.88 + if (f != 0) prev[f] = 0;
171.89 + /* label the vertex; it begins a new component */
171.90 + prev[i] = -1, next[i] = ++nc;
171.91 + /* breadth first search */
171.92 + list[1] = i, pos1 = pos2 = 1;
171.93 + while (pos1 <= pos2)
171.94 + { /* dequeue vertex i */
171.95 + i = list[pos1++];
171.96 + /* consider all arcs incoming to vertex i */
171.97 + for (a = G->v[i]->in; a != NULL; a = a->h_next)
171.98 + { /* vertex j is adjacent to vertex i */
171.99 + j = a->tail->i;
171.100 + if (prev[j] >= 0)
171.101 + { /* vertex j is unlabelled */
171.102 + /* remove it from the list of unlabelled vertices */
171.103 + if (prev[j] == 0)
171.104 + f = next[j];
171.105 + else
171.106 + next[prev[j]] = next[j];
171.107 + if (next[j] == 0)
171.108 + ;
171.109 + else
171.110 + prev[next[j]] = prev[j];
171.111 + /* label the vertex */
171.112 + prev[j] = -1, next[j] = nc;
171.113 + /* and enqueue it for further consideration */
171.114 + list[++pos2] = j;
171.115 + }
171.116 + }
171.117 + /* consider all arcs outgoing from vertex i */
171.118 + for (a = G->v[i]->out; a != NULL; a = a->t_next)
171.119 + { /* vertex j is adjacent to vertex i */
171.120 + j = a->head->i;
171.121 + if (prev[j] >= 0)
171.122 + { /* vertex j is unlabelled */
171.123 + /* remove it from the list of unlabelled vertices */
171.124 + if (prev[j] == 0)
171.125 + f = next[j];
171.126 + else
171.127 + next[prev[j]] = next[j];
171.128 + if (next[j] == 0)
171.129 + ;
171.130 + else
171.131 + prev[next[j]] = prev[j];
171.132 + /* label the vertex */
171.133 + prev[j] = -1, next[j] = nc;
171.134 + /* and enqueue it for further consideration */
171.135 + list[++pos2] = j;
171.136 + }
171.137 + }
171.138 + }
171.139 + }
171.140 + /* store component numbers */
171.141 + if (v_num >= 0)
171.142 + { for (i = 1; i <= nv; i++)
171.143 + { v = G->v[i];
171.144 + memcpy((char *)v->data + v_num, &next[i], sizeof(int));
171.145 + }
171.146 + }
171.147 + /* free working arrays */
171.148 + xfree(prev);
171.149 + xfree(next);
171.150 + xfree(list);
171.151 +done: return nc;
171.152 +}
171.153 +
171.154 +/***********************************************************************
171.155 +* NAME
171.156 +*
171.157 +* glp_strong_comp - find all strongly connected components of graph
171.158 +*
171.159 +* SYNOPSIS
171.160 +*
171.161 +* int glp_strong_comp(glp_graph *G, int v_num);
171.162 +*
171.163 +* DESCRIPTION
171.164 +*
171.165 +* The routine glp_strong_comp finds all strongly connected components
171.166 +* of the specified graph.
171.167 +*
171.168 +* The parameter v_num specifies an offset of the field of type int
171.169 +* in the vertex data block, to which the routine stores the number of
171.170 +* a strongly connected component containing that vertex. If v_num < 0,
171.171 +* no component numbers are stored.
171.172 +*
171.173 +* The components are numbered in arbitrary order from 1 to nc, where
171.174 +* nc is the total number of components found, 0 <= nc <= |V|. However,
171.175 +* the component numbering has the property that for every arc (i->j)
171.176 +* in the graph the condition num(i) >= num(j) holds.
171.177 +*
171.178 +* RETURNS
171.179 +*
171.180 +* The routine returns nc, the total number of components found. */
171.181 +
171.182 +int glp_strong_comp(glp_graph *G, int v_num)
171.183 +{ glp_vertex *v;
171.184 + glp_arc *a;
171.185 + int i, k, last, n, na, nc, *icn, *ip, *lenr, *ior, *ib, *lowl,
171.186 + *numb, *prev;
171.187 + if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
171.188 + xerror("glp_strong_comp: v_num = %d; invalid offset\n",
171.189 + v_num);
171.190 + n = G->nv;
171.191 + if (n == 0)
171.192 + { nc = 0;
171.193 + goto done;
171.194 + }
171.195 + na = G->na;
171.196 + icn = xcalloc(1+na, sizeof(int));
171.197 + ip = xcalloc(1+n, sizeof(int));
171.198 + lenr = xcalloc(1+n, sizeof(int));
171.199 + ior = xcalloc(1+n, sizeof(int));
171.200 + ib = xcalloc(1+n, sizeof(int));
171.201 + lowl = xcalloc(1+n, sizeof(int));
171.202 + numb = xcalloc(1+n, sizeof(int));
171.203 + prev = xcalloc(1+n, sizeof(int));
171.204 + k = 1;
171.205 + for (i = 1; i <= n; i++)
171.206 + { v = G->v[i];
171.207 + ip[i] = k;
171.208 + for (a = v->out; a != NULL; a = a->t_next)
171.209 + icn[k++] = a->head->i;
171.210 + lenr[i] = k - ip[i];
171.211 + }
171.212 + xassert(na == k-1);
171.213 + nc = mc13d(n, icn, ip, lenr, ior, ib, lowl, numb, prev);
171.214 + if (v_num >= 0)
171.215 + { xassert(ib[1] == 1);
171.216 + for (k = 1; k <= nc; k++)
171.217 + { last = (k < nc ? ib[k+1] : n+1);
171.218 + xassert(ib[k] < last);
171.219 + for (i = ib[k]; i < last; i++)
171.220 + { v = G->v[ior[i]];
171.221 + memcpy((char *)v->data + v_num, &k, sizeof(int));
171.222 + }
171.223 + }
171.224 + }
171.225 + xfree(icn);
171.226 + xfree(ip);
171.227 + xfree(lenr);
171.228 + xfree(ior);
171.229 + xfree(ib);
171.230 + xfree(lowl);
171.231 + xfree(numb);
171.232 + xfree(prev);
171.233 +done: return nc;
171.234 +}
171.235 +
171.236 +/***********************************************************************
171.237 +* NAME
171.238 +*
171.239 +* glp_top_sort - topological sorting of acyclic digraph
171.240 +*
171.241 +* SYNOPSIS
171.242 +*
171.243 +* int glp_top_sort(glp_graph *G, int v_num);
171.244 +*
171.245 +* DESCRIPTION
171.246 +*
171.247 +* The routine glp_top_sort performs topological sorting of vertices of
171.248 +* the specified acyclic digraph.
171.249 +*
171.250 +* The parameter v_num specifies an offset of the field of type int in
171.251 +* the vertex data block, to which the routine stores the vertex number
171.252 +* assigned. If v_num < 0, vertex numbers are not stored.
171.253 +*
171.254 +* The vertices are numbered from 1 to n, where n is the total number
171.255 +* of vertices in the graph. The vertex numbering has the property that
171.256 +* for every arc (i->j) in the graph the condition num(i) < num(j)
171.257 +* holds. Special case num(i) = 0 means that vertex i is not assigned a
171.258 +* number, because the graph is *not* acyclic.
171.259 +*
171.260 +* RETURNS
171.261 +*
171.262 +* If the graph is acyclic and therefore all the vertices have been
171.263 +* assigned numbers, the routine glp_top_sort returns zero. Otherwise,
171.264 +* if the graph is not acyclic, the routine returns the number of
171.265 +* vertices which have not been numbered, i.e. for which num(i) = 0. */
171.266 +
171.267 +static int top_sort(glp_graph *G, int num[])
171.268 +{ glp_arc *a;
171.269 + int i, j, cnt, top, *stack, *indeg;
171.270 + /* allocate working arrays */
171.271 + indeg = xcalloc(1+G->nv, sizeof(int));
171.272 + stack = xcalloc(1+G->nv, sizeof(int));
171.273 + /* determine initial indegree of each vertex; push into the stack
171.274 + the vertices having zero indegree */
171.275 + top = 0;
171.276 + for (i = 1; i <= G->nv; i++)
171.277 + { num[i] = indeg[i] = 0;
171.278 + for (a = G->v[i]->in; a != NULL; a = a->h_next)
171.279 + indeg[i]++;
171.280 + if (indeg[i] == 0)
171.281 + stack[++top] = i;
171.282 + }
171.283 + /* assign numbers to vertices in the sorted order */
171.284 + cnt = 0;
171.285 + while (top > 0)
171.286 + { /* pull vertex i from the stack */
171.287 + i = stack[top--];
171.288 + /* it has zero indegree in the current graph */
171.289 + xassert(indeg[i] == 0);
171.290 + /* so assign it a next number */
171.291 + xassert(num[i] == 0);
171.292 + num[i] = ++cnt;
171.293 + /* remove vertex i from the current graph, update indegree of
171.294 + its adjacent vertices, and push into the stack new vertices
171.295 + whose indegree becomes zero */
171.296 + for (a = G->v[i]->out; a != NULL; a = a->t_next)
171.297 + { j = a->head->i;
171.298 + /* there exists arc (i->j) in the graph */
171.299 + xassert(indeg[j] > 0);
171.300 + indeg[j]--;
171.301 + if (indeg[j] == 0)
171.302 + stack[++top] = j;
171.303 + }
171.304 + }
171.305 + /* free working arrays */
171.306 + xfree(indeg);
171.307 + xfree(stack);
171.308 + return G->nv - cnt;
171.309 +}
171.310 +
171.311 +int glp_top_sort(glp_graph *G, int v_num)
171.312 +{ glp_vertex *v;
171.313 + int i, cnt, *num;
171.314 + if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
171.315 + xerror("glp_top_sort: v_num = %d; invalid offset\n", v_num);
171.316 + if (G->nv == 0)
171.317 + { cnt = 0;
171.318 + goto done;
171.319 + }
171.320 + num = xcalloc(1+G->nv, sizeof(int));
171.321 + cnt = top_sort(G, num);
171.322 + if (v_num >= 0)
171.323 + { for (i = 1; i <= G->nv; i++)
171.324 + { v = G->v[i];
171.325 + memcpy((char *)v->data + v_num, &num[i], sizeof(int));
171.326 + }
171.327 + }
171.328 + xfree(num);
171.329 +done: return cnt;
171.330 +}
171.331 +
171.332 +/* eof */
172.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
172.2 +++ b/src/glpapi17.c Mon Dec 06 13:09:21 2010 +0100
172.3 @@ -0,0 +1,1048 @@
172.4 +/* glpapi17.c (flow network problems) */
172.5 +
172.6 +/***********************************************************************
172.7 +* This code is part of GLPK (GNU Linear Programming Kit).
172.8 +*
172.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
172.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
172.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
172.12 +* E-mail: <mao@gnu.org>.
172.13 +*
172.14 +* GLPK is free software: you can redistribute it and/or modify it
172.15 +* under the terms of the GNU General Public License as published by
172.16 +* the Free Software Foundation, either version 3 of the License, or
172.17 +* (at your option) any later version.
172.18 +*
172.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
172.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
172.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
172.22 +* License for more details.
172.23 +*
172.24 +* You should have received a copy of the GNU General Public License
172.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
172.26 +***********************************************************************/
172.27 +
172.28 +#include "glpapi.h"
172.29 +#include "glpnet.h"
172.30 +
172.31 +/***********************************************************************
172.32 +* NAME
172.33 +*
172.34 +* glp_mincost_lp - convert minimum cost flow problem to LP
172.35 +*
172.36 +* SYNOPSIS
172.37 +*
172.38 +* void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names,
172.39 +* int v_rhs, int a_low, int a_cap, int a_cost);
172.40 +*
172.41 +* DESCRIPTION
172.42 +*
172.43 +* The routine glp_mincost_lp builds an LP problem, which corresponds
172.44 +* to the minimum cost flow problem on the specified network G. */
172.45 +
172.46 +void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names, int v_rhs,
172.47 + int a_low, int a_cap, int a_cost)
172.48 +{ glp_vertex *v;
172.49 + glp_arc *a;
172.50 + int i, j, type, ind[1+2];
172.51 + double rhs, low, cap, cost, val[1+2];
172.52 + if (!(names == GLP_ON || names == GLP_OFF))
172.53 + xerror("glp_mincost_lp: names = %d; invalid parameter\n",
172.54 + names);
172.55 + if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
172.56 + xerror("glp_mincost_lp: v_rhs = %d; invalid offset\n", v_rhs);
172.57 + if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
172.58 + xerror("glp_mincost_lp: a_low = %d; invalid offset\n", a_low);
172.59 + if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
172.60 + xerror("glp_mincost_lp: a_cap = %d; invalid offset\n", a_cap);
172.61 + if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
172.62 + xerror("glp_mincost_lp: a_cost = %d; invalid offset\n", a_cost)
172.63 + ;
172.64 + glp_erase_prob(lp);
172.65 + if (names) glp_set_prob_name(lp, G->name);
172.66 + if (G->nv > 0) glp_add_rows(lp, G->nv);
172.67 + for (i = 1; i <= G->nv; i++)
172.68 + { v = G->v[i];
172.69 + if (names) glp_set_row_name(lp, i, v->name);
172.70 + if (v_rhs >= 0)
172.71 + memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double));
172.72 + else
172.73 + rhs = 0.0;
172.74 + glp_set_row_bnds(lp, i, GLP_FX, rhs, rhs);
172.75 + }
172.76 + if (G->na > 0) glp_add_cols(lp, G->na);
172.77 + for (i = 1, j = 0; i <= G->nv; i++)
172.78 + { v = G->v[i];
172.79 + for (a = v->out; a != NULL; a = a->t_next)
172.80 + { j++;
172.81 + if (names)
172.82 + { char name[50+1];
172.83 + sprintf(name, "x[%d,%d]", a->tail->i, a->head->i);
172.84 + xassert(strlen(name) < sizeof(name));
172.85 + glp_set_col_name(lp, j, name);
172.86 + }
172.87 + if (a->tail->i != a->head->i)
172.88 + { ind[1] = a->tail->i, val[1] = +1.0;
172.89 + ind[2] = a->head->i, val[2] = -1.0;
172.90 + glp_set_mat_col(lp, j, 2, ind, val);
172.91 + }
172.92 + if (a_low >= 0)
172.93 + memcpy(&low, (char *)a->data + a_low, sizeof(double));
172.94 + else
172.95 + low = 0.0;
172.96 + if (a_cap >= 0)
172.97 + memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
172.98 + else
172.99 + cap = 1.0;
172.100 + if (cap == DBL_MAX)
172.101 + type = GLP_LO;
172.102 + else if (low != cap)
172.103 + type = GLP_DB;
172.104 + else
172.105 + type = GLP_FX;
172.106 + glp_set_col_bnds(lp, j, type, low, cap);
172.107 + if (a_cost >= 0)
172.108 + memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
172.109 + else
172.110 + cost = 0.0;
172.111 + glp_set_obj_coef(lp, j, cost);
172.112 + }
172.113 + }
172.114 + xassert(j == G->na);
172.115 + return;
172.116 +}
172.117 +
172.118 +/**********************************************************************/
172.119 +
172.120 +int glp_mincost_okalg(glp_graph *G, int v_rhs, int a_low, int a_cap,
172.121 + int a_cost, double *sol, int a_x, int v_pi)
172.122 +{ /* find minimum-cost flow with out-of-kilter algorithm */
172.123 + glp_vertex *v;
172.124 + glp_arc *a;
172.125 + int nv, na, i, k, s, t, *tail, *head, *low, *cap, *cost, *x, *pi,
172.126 + ret;
172.127 + double sum, temp;
172.128 + if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
172.129 + xerror("glp_mincost_okalg: v_rhs = %d; invalid offset\n",
172.130 + v_rhs);
172.131 + if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
172.132 + xerror("glp_mincost_okalg: a_low = %d; invalid offset\n",
172.133 + a_low);
172.134 + if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
172.135 + xerror("glp_mincost_okalg: a_cap = %d; invalid offset\n",
172.136 + a_cap);
172.137 + if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
172.138 + xerror("glp_mincost_okalg: a_cost = %d; invalid offset\n",
172.139 + a_cost);
172.140 + if (a_x >= 0 && a_x > G->a_size - (int)sizeof(double))
172.141 + xerror("glp_mincost_okalg: a_x = %d; invalid offset\n", a_x);
172.142 + if (v_pi >= 0 && v_pi > G->v_size - (int)sizeof(double))
172.143 + xerror("glp_mincost_okalg: v_pi = %d; invalid offset\n", v_pi);
172.144 + /* s is artificial source node */
172.145 + s = G->nv + 1;
172.146 + /* t is artificial sink node */
172.147 + t = s + 1;
172.148 + /* nv is the total number of nodes in the resulting network */
172.149 + nv = t;
172.150 + /* na is the total number of arcs in the resulting network */
172.151 + na = G->na + 1;
172.152 + for (i = 1; i <= G->nv; i++)
172.153 + { v = G->v[i];
172.154 + if (v_rhs >= 0)
172.155 + memcpy(&temp, (char *)v->data + v_rhs, sizeof(double));
172.156 + else
172.157 + temp = 0.0;
172.158 + if (temp != 0.0) na++;
172.159 + }
172.160 + /* allocate working arrays */
172.161 + tail = xcalloc(1+na, sizeof(int));
172.162 + head = xcalloc(1+na, sizeof(int));
172.163 + low = xcalloc(1+na, sizeof(int));
172.164 + cap = xcalloc(1+na, sizeof(int));
172.165 + cost = xcalloc(1+na, sizeof(int));
172.166 + x = xcalloc(1+na, sizeof(int));
172.167 + pi = xcalloc(1+nv, sizeof(int));
172.168 + /* construct the resulting network */
172.169 + k = 0;
172.170 + /* (original arcs) */
172.171 + for (i = 1; i <= G->nv; i++)
172.172 + { v = G->v[i];
172.173 + for (a = v->out; a != NULL; a = a->t_next)
172.174 + { k++;
172.175 + tail[k] = a->tail->i;
172.176 + head[k] = a->head->i;
172.177 + if (tail[k] == head[k])
172.178 + { ret = GLP_EDATA;
172.179 + goto done;
172.180 + }
172.181 + if (a_low >= 0)
172.182 + memcpy(&temp, (char *)a->data + a_low, sizeof(double));
172.183 + else
172.184 + temp = 0.0;
172.185 + if (!(0.0 <= temp && temp <= (double)INT_MAX &&
172.186 + temp == floor(temp)))
172.187 + { ret = GLP_EDATA;
172.188 + goto done;
172.189 + }
172.190 + low[k] = (int)temp;
172.191 + if (a_cap >= 0)
172.192 + memcpy(&temp, (char *)a->data + a_cap, sizeof(double));
172.193 + else
172.194 + temp = 1.0;
172.195 + if (!((double)low[k] <= temp && temp <= (double)INT_MAX &&
172.196 + temp == floor(temp)))
172.197 + { ret = GLP_EDATA;
172.198 + goto done;
172.199 + }
172.200 + cap[k] = (int)temp;
172.201 + if (a_cost >= 0)
172.202 + memcpy(&temp, (char *)a->data + a_cost, sizeof(double));
172.203 + else
172.204 + temp = 0.0;
172.205 + if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp)))
172.206 + { ret = GLP_EDATA;
172.207 + goto done;
172.208 + }
172.209 + cost[k] = (int)temp;
172.210 + }
172.211 + }
172.212 + /* (artificial arcs) */
172.213 + sum = 0.0;
172.214 + for (i = 1; i <= G->nv; i++)
172.215 + { v = G->v[i];
172.216 + if (v_rhs >= 0)
172.217 + memcpy(&temp, (char *)v->data + v_rhs, sizeof(double));
172.218 + else
172.219 + temp = 0.0;
172.220 + if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp)))
172.221 + { ret = GLP_EDATA;
172.222 + goto done;
172.223 + }
172.224 + if (temp > 0.0)
172.225 + { /* artificial arc from s to original source i */
172.226 + k++;
172.227 + tail[k] = s;
172.228 + head[k] = i;
172.229 + low[k] = cap[k] = (int)(+temp); /* supply */
172.230 + cost[k] = 0;
172.231 + sum += (double)temp;
172.232 + }
172.233 + else if (temp < 0.0)
172.234 + { /* artificial arc from original sink i to t */
172.235 + k++;
172.236 + tail[k] = i;
172.237 + head[k] = t;
172.238 + low[k] = cap[k] = (int)(-temp); /* demand */
172.239 + cost[k] = 0;
172.240 + }
172.241 + }
172.242 + /* (feedback arc from t to s) */
172.243 + k++;
172.244 + xassert(k == na);
172.245 + tail[k] = t;
172.246 + head[k] = s;
172.247 + if (sum > (double)INT_MAX)
172.248 + { ret = GLP_EDATA;
172.249 + goto done;
172.250 + }
172.251 + low[k] = cap[k] = (int)sum; /* total supply/demand */
172.252 + cost[k] = 0;
172.253 + /* find minimal-cost circulation in the resulting network */
172.254 + ret = okalg(nv, na, tail, head, low, cap, cost, x, pi);
172.255 + switch (ret)
172.256 + { case 0:
172.257 + /* optimal circulation found */
172.258 + ret = 0;
172.259 + break;
172.260 + case 1:
172.261 + /* no feasible circulation exists */
172.262 + ret = GLP_ENOPFS;
172.263 + break;
172.264 + case 2:
172.265 + /* integer overflow occured */
172.266 + ret = GLP_ERANGE;
172.267 + goto done;
172.268 + case 3:
172.269 + /* optimality test failed (logic error) */
172.270 + ret = GLP_EFAIL;
172.271 + goto done;
172.272 + default:
172.273 + xassert(ret != ret);
172.274 + }
172.275 + /* store solution components */
172.276 + /* (objective function = the total cost) */
172.277 + if (sol != NULL)
172.278 + { temp = 0.0;
172.279 + for (k = 1; k <= na; k++)
172.280 + temp += (double)cost[k] * (double)x[k];
172.281 + *sol = temp;
172.282 + }
172.283 + /* (arc flows) */
172.284 + if (a_x >= 0)
172.285 + { k = 0;
172.286 + for (i = 1; i <= G->nv; i++)
172.287 + { v = G->v[i];
172.288 + for (a = v->out; a != NULL; a = a->t_next)
172.289 + { temp = (double)x[++k];
172.290 + memcpy((char *)a->data + a_x, &temp, sizeof(double));
172.291 + }
172.292 + }
172.293 + }
172.294 + /* (node potentials = Lagrange multipliers) */
172.295 + if (v_pi >= 0)
172.296 + { for (i = 1; i <= G->nv; i++)
172.297 + { v = G->v[i];
172.298 + temp = - (double)pi[i];
172.299 + memcpy((char *)v->data + v_pi, &temp, sizeof(double));
172.300 + }
172.301 + }
172.302 +done: /* free working arrays */
172.303 + xfree(tail);
172.304 + xfree(head);
172.305 + xfree(low);
172.306 + xfree(cap);
172.307 + xfree(cost);
172.308 + xfree(x);
172.309 + xfree(pi);
172.310 + return ret;
172.311 +}
172.312 +
172.313 +/***********************************************************************
172.314 +* NAME
172.315 +*
172.316 +* glp_maxflow_lp - convert maximum flow problem to LP
172.317 +*
172.318 +* SYNOPSIS
172.319 +*
172.320 +* void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names, int s,
172.321 +* int t, int a_cap);
172.322 +*
172.323 +* DESCRIPTION
172.324 +*
172.325 +* The routine glp_maxflow_lp builds an LP problem, which corresponds
172.326 +* to the maximum flow problem on the specified network G. */
172.327 +
172.328 +void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names, int s,
172.329 + int t, int a_cap)
172.330 +{ glp_vertex *v;
172.331 + glp_arc *a;
172.332 + int i, j, type, ind[1+2];
172.333 + double cap, val[1+2];
172.334 + if (!(names == GLP_ON || names == GLP_OFF))
172.335 + xerror("glp_maxflow_lp: names = %d; invalid parameter\n",
172.336 + names);
172.337 + if (!(1 <= s && s <= G->nv))
172.338 + xerror("glp_maxflow_lp: s = %d; source node number out of rang"
172.339 + "e\n", s);
172.340 + if (!(1 <= t && t <= G->nv))
172.341 + xerror("glp_maxflow_lp: t = %d: sink node number out of range "
172.342 + "\n", t);
172.343 + if (s == t)
172.344 + xerror("glp_maxflow_lp: s = t = %d; source and sink nodes must"
172.345 + " be distinct\n", s);
172.346 + if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
172.347 + xerror("glp_maxflow_lp: a_cap = %d; invalid offset\n", a_cap);
172.348 + glp_erase_prob(lp);
172.349 + if (names) glp_set_prob_name(lp, G->name);
172.350 + glp_set_obj_dir(lp, GLP_MAX);
172.351 + glp_add_rows(lp, G->nv);
172.352 + for (i = 1; i <= G->nv; i++)
172.353 + { v = G->v[i];
172.354 + if (names) glp_set_row_name(lp, i, v->name);
172.355 + if (i == s)
172.356 + type = GLP_LO;
172.357 + else if (i == t)
172.358 + type = GLP_UP;
172.359 + else
172.360 + type = GLP_FX;
172.361 + glp_set_row_bnds(lp, i, type, 0.0, 0.0);
172.362 + }
172.363 + if (G->na > 0) glp_add_cols(lp, G->na);
172.364 + for (i = 1, j = 0; i <= G->nv; i++)
172.365 + { v = G->v[i];
172.366 + for (a = v->out; a != NULL; a = a->t_next)
172.367 + { j++;
172.368 + if (names)
172.369 + { char name[50+1];
172.370 + sprintf(name, "x[%d,%d]", a->tail->i, a->head->i);
172.371 + xassert(strlen(name) < sizeof(name));
172.372 + glp_set_col_name(lp, j, name);
172.373 + }
172.374 + if (a->tail->i != a->head->i)
172.375 + { ind[1] = a->tail->i, val[1] = +1.0;
172.376 + ind[2] = a->head->i, val[2] = -1.0;
172.377 + glp_set_mat_col(lp, j, 2, ind, val);
172.378 + }
172.379 + if (a_cap >= 0)
172.380 + memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
172.381 + else
172.382 + cap = 1.0;
172.383 + if (cap == DBL_MAX)
172.384 + type = GLP_LO;
172.385 + else if (cap != 0.0)
172.386 + type = GLP_DB;
172.387 + else
172.388 + type = GLP_FX;
172.389 + glp_set_col_bnds(lp, j, type, 0.0, cap);
172.390 + if (a->tail->i == s)
172.391 + glp_set_obj_coef(lp, j, +1.0);
172.392 + else if (a->head->i == s)
172.393 + glp_set_obj_coef(lp, j, -1.0);
172.394 + }
172.395 + }
172.396 + xassert(j == G->na);
172.397 + return;
172.398 +}
172.399 +
172.400 +int glp_maxflow_ffalg(glp_graph *G, int s, int t, int a_cap,
172.401 + double *sol, int a_x, int v_cut)
172.402 +{ /* find maximal flow with Ford-Fulkerson algorithm */
172.403 + glp_vertex *v;
172.404 + glp_arc *a;
172.405 + int nv, na, i, k, flag, *tail, *head, *cap, *x, ret;
172.406 + char *cut;
172.407 + double temp;
172.408 + if (!(1 <= s && s <= G->nv))
172.409 + xerror("glp_maxflow_ffalg: s = %d; source node number out of r"
172.410 + "ange\n", s);
172.411 + if (!(1 <= t && t <= G->nv))
172.412 + xerror("glp_maxflow_ffalg: t = %d: sink node number out of ran"
172.413 + "ge\n", t);
172.414 + if (s == t)
172.415 + xerror("glp_maxflow_ffalg: s = t = %d; source and sink nodes m"
172.416 + "ust be distinct\n", s);
172.417 + if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
172.418 + xerror("glp_maxflow_ffalg: a_cap = %d; invalid offset\n",
172.419 + a_cap);
172.420 + if (v_cut >= 0 && v_cut > G->v_size - (int)sizeof(int))
172.421 + xerror("glp_maxflow_ffalg: v_cut = %d; invalid offset\n",
172.422 + v_cut);
172.423 + /* allocate working arrays */
172.424 + nv = G->nv;
172.425 + na = G->na;
172.426 + tail = xcalloc(1+na, sizeof(int));
172.427 + head = xcalloc(1+na, sizeof(int));
172.428 + cap = xcalloc(1+na, sizeof(int));
172.429 + x = xcalloc(1+na, sizeof(int));
172.430 + if (v_cut < 0)
172.431 + cut = NULL;
172.432 + else
172.433 + cut = xcalloc(1+nv, sizeof(char));
172.434 + /* copy the flow network */
172.435 + k = 0;
172.436 + for (i = 1; i <= G->nv; i++)
172.437 + { v = G->v[i];
172.438 + for (a = v->out; a != NULL; a = a->t_next)
172.439 + { k++;
172.440 + tail[k] = a->tail->i;
172.441 + head[k] = a->head->i;
172.442 + if (tail[k] == head[k])
172.443 + { ret = GLP_EDATA;
172.444 + goto done;
172.445 + }
172.446 + if (a_cap >= 0)
172.447 + memcpy(&temp, (char *)a->data + a_cap, sizeof(double));
172.448 + else
172.449 + temp = 1.0;
172.450 + if (!(0.0 <= temp && temp <= (double)INT_MAX &&
172.451 + temp == floor(temp)))
172.452 + { ret = GLP_EDATA;
172.453 + goto done;
172.454 + }
172.455 + cap[k] = (int)temp;
172.456 + }
172.457 + }
172.458 + xassert(k == na);
172.459 + /* find maximal flow in the flow network */
172.460 + ffalg(nv, na, tail, head, s, t, cap, x, cut);
172.461 + ret = 0;
172.462 + /* store solution components */
172.463 + /* (objective function = total flow through the network) */
172.464 + if (sol != NULL)
172.465 + { temp = 0.0;
172.466 + for (k = 1; k <= na; k++)
172.467 + { if (tail[k] == s)
172.468 + temp += (double)x[k];
172.469 + else if (head[k] == s)
172.470 + temp -= (double)x[k];
172.471 + }
172.472 + *sol = temp;
172.473 + }
172.474 + /* (arc flows) */
172.475 + if (a_x >= 0)
172.476 + { k = 0;
172.477 + for (i = 1; i <= G->nv; i++)
172.478 + { v = G->v[i];
172.479 + for (a = v->out; a != NULL; a = a->t_next)
172.480 + { temp = (double)x[++k];
172.481 + memcpy((char *)a->data + a_x, &temp, sizeof(double));
172.482 + }
172.483 + }
172.484 + }
172.485 + /* (node flags) */
172.486 + if (v_cut >= 0)
172.487 + { for (i = 1; i <= G->nv; i++)
172.488 + { v = G->v[i];
172.489 + flag = cut[i];
172.490 + memcpy((char *)v->data + v_cut, &flag, sizeof(int));
172.491 + }
172.492 + }
172.493 +done: /* free working arrays */
172.494 + xfree(tail);
172.495 + xfree(head);
172.496 + xfree(cap);
172.497 + xfree(x);
172.498 + if (cut != NULL) xfree(cut);
172.499 + return ret;
172.500 +}
172.501 +
172.502 +/***********************************************************************
172.503 +* NAME
172.504 +*
172.505 +* glp_check_asnprob - check correctness of assignment problem data
172.506 +*
172.507 +* SYNOPSIS
172.508 +*
172.509 +* int glp_check_asnprob(glp_graph *G, int v_set);
172.510 +*
172.511 +* RETURNS
172.512 +*
172.513 +* If the specified assignment problem data are correct, the routine
172.514 +* glp_check_asnprob returns zero, otherwise, non-zero. */
172.515 +
172.516 +int glp_check_asnprob(glp_graph *G, int v_set)
172.517 +{ glp_vertex *v;
172.518 + int i, k, ret = 0;
172.519 + if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
172.520 + xerror("glp_check_asnprob: v_set = %d; invalid offset\n",
172.521 + v_set);
172.522 + for (i = 1; i <= G->nv; i++)
172.523 + { v = G->v[i];
172.524 + if (v_set >= 0)
172.525 + { memcpy(&k, (char *)v->data + v_set, sizeof(int));
172.526 + if (k == 0)
172.527 + { if (v->in != NULL)
172.528 + { ret = 1;
172.529 + break;
172.530 + }
172.531 + }
172.532 + else if (k == 1)
172.533 + { if (v->out != NULL)
172.534 + { ret = 2;
172.535 + break;
172.536 + }
172.537 + }
172.538 + else
172.539 + { ret = 3;
172.540 + break;
172.541 + }
172.542 + }
172.543 + else
172.544 + { if (v->in != NULL && v->out != NULL)
172.545 + { ret = 4;
172.546 + break;
172.547 + }
172.548 + }
172.549 + }
172.550 + return ret;
172.551 +}
172.552 +
172.553 +/***********************************************************************
172.554 +* NAME
172.555 +*
172.556 +* glp_asnprob_lp - convert assignment problem to LP
172.557 +*
172.558 +* SYNOPSIS
172.559 +*
172.560 +* int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names,
172.561 +* int v_set, int a_cost);
172.562 +*
172.563 +* DESCRIPTION
172.564 +*
172.565 +* The routine glp_asnprob_lp builds an LP problem, which corresponds
172.566 +* to the assignment problem on the specified graph G.
172.567 +*
172.568 +* RETURNS
172.569 +*
172.570 +* If the LP problem has been successfully built, the routine returns
172.571 +* zero, otherwise, non-zero. */
172.572 +
172.573 +int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names,
172.574 + int v_set, int a_cost)
172.575 +{ glp_vertex *v;
172.576 + glp_arc *a;
172.577 + int i, j, ret, ind[1+2];
172.578 + double cost, val[1+2];
172.579 + if (!(form == GLP_ASN_MIN || form == GLP_ASN_MAX ||
172.580 + form == GLP_ASN_MMP))
172.581 + xerror("glp_asnprob_lp: form = %d; invalid parameter\n",
172.582 + form);
172.583 + if (!(names == GLP_ON || names == GLP_OFF))
172.584 + xerror("glp_asnprob_lp: names = %d; invalid parameter\n",
172.585 + names);
172.586 + if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
172.587 + xerror("glp_asnprob_lp: v_set = %d; invalid offset\n",
172.588 + v_set);
172.589 + if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
172.590 + xerror("glp_asnprob_lp: a_cost = %d; invalid offset\n",
172.591 + a_cost);
172.592 + ret = glp_check_asnprob(G, v_set);
172.593 + if (ret != 0) goto done;
172.594 + glp_erase_prob(P);
172.595 + if (names) glp_set_prob_name(P, G->name);
172.596 + glp_set_obj_dir(P, form == GLP_ASN_MIN ? GLP_MIN : GLP_MAX);
172.597 + if (G->nv > 0) glp_add_rows(P, G->nv);
172.598 + for (i = 1; i <= G->nv; i++)
172.599 + { v = G->v[i];
172.600 + if (names) glp_set_row_name(P, i, v->name);
172.601 + glp_set_row_bnds(P, i, form == GLP_ASN_MMP ? GLP_UP : GLP_FX,
172.602 + 1.0, 1.0);
172.603 + }
172.604 + if (G->na > 0) glp_add_cols(P, G->na);
172.605 + for (i = 1, j = 0; i <= G->nv; i++)
172.606 + { v = G->v[i];
172.607 + for (a = v->out; a != NULL; a = a->t_next)
172.608 + { j++;
172.609 + if (names)
172.610 + { char name[50+1];
172.611 + sprintf(name, "x[%d,%d]", a->tail->i, a->head->i);
172.612 + xassert(strlen(name) < sizeof(name));
172.613 + glp_set_col_name(P, j, name);
172.614 + }
172.615 + ind[1] = a->tail->i, val[1] = +1.0;
172.616 + ind[2] = a->head->i, val[2] = +1.0;
172.617 + glp_set_mat_col(P, j, 2, ind, val);
172.618 + glp_set_col_bnds(P, j, GLP_DB, 0.0, 1.0);
172.619 + if (a_cost >= 0)
172.620 + memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
172.621 + else
172.622 + cost = 1.0;
172.623 + glp_set_obj_coef(P, j, cost);
172.624 + }
172.625 + }
172.626 + xassert(j == G->na);
172.627 +done: return ret;
172.628 +}
172.629 +
172.630 +/**********************************************************************/
172.631 +
172.632 +int glp_asnprob_okalg(int form, glp_graph *G, int v_set, int a_cost,
172.633 + double *sol, int a_x)
172.634 +{ /* solve assignment problem with out-of-kilter algorithm */
172.635 + glp_vertex *v;
172.636 + glp_arc *a;
172.637 + int nv, na, i, k, *tail, *head, *low, *cap, *cost, *x, *pi, ret;
172.638 + double temp;
172.639 + if (!(form == GLP_ASN_MIN || form == GLP_ASN_MAX ||
172.640 + form == GLP_ASN_MMP))
172.641 + xerror("glp_asnprob_okalg: form = %d; invalid parameter\n",
172.642 + form);
172.643 + if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
172.644 + xerror("glp_asnprob_okalg: v_set = %d; invalid offset\n",
172.645 + v_set);
172.646 + if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
172.647 + xerror("glp_asnprob_okalg: a_cost = %d; invalid offset\n",
172.648 + a_cost);
172.649 + if (a_x >= 0 && a_x > G->a_size - (int)sizeof(int))
172.650 + xerror("glp_asnprob_okalg: a_x = %d; invalid offset\n", a_x);
172.651 + if (glp_check_asnprob(G, v_set))
172.652 + return GLP_EDATA;
172.653 + /* nv is the total number of nodes in the resulting network */
172.654 + nv = G->nv + 1;
172.655 + /* na is the total number of arcs in the resulting network */
172.656 + na = G->na + G->nv;
172.657 + /* allocate working arrays */
172.658 + tail = xcalloc(1+na, sizeof(int));
172.659 + head = xcalloc(1+na, sizeof(int));
172.660 + low = xcalloc(1+na, sizeof(int));
172.661 + cap = xcalloc(1+na, sizeof(int));
172.662 + cost = xcalloc(1+na, sizeof(int));
172.663 + x = xcalloc(1+na, sizeof(int));
172.664 + pi = xcalloc(1+nv, sizeof(int));
172.665 + /* construct the resulting network */
172.666 + k = 0;
172.667 + /* (original arcs) */
172.668 + for (i = 1; i <= G->nv; i++)
172.669 + { v = G->v[i];
172.670 + for (a = v->out; a != NULL; a = a->t_next)
172.671 + { k++;
172.672 + tail[k] = a->tail->i;
172.673 + head[k] = a->head->i;
172.674 + low[k] = 0;
172.675 + cap[k] = 1;
172.676 + if (a_cost >= 0)
172.677 + memcpy(&temp, (char *)a->data + a_cost, sizeof(double));
172.678 + else
172.679 + temp = 1.0;
172.680 + if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp)))
172.681 + { ret = GLP_EDATA;
172.682 + goto done;
172.683 + }
172.684 + cost[k] = (int)temp;
172.685 + if (form != GLP_ASN_MIN) cost[k] = - cost[k];
172.686 + }
172.687 + }
172.688 + /* (artificial arcs) */
172.689 + for (i = 1; i <= G->nv; i++)
172.690 + { v = G->v[i];
172.691 + k++;
172.692 + if (v->out == NULL)
172.693 + tail[k] = i, head[k] = nv;
172.694 + else if (v->in == NULL)
172.695 + tail[k] = nv, head[k] = i;
172.696 + else
172.697 + xassert(v != v);
172.698 + low[k] = (form == GLP_ASN_MMP ? 0 : 1);
172.699 + cap[k] = 1;
172.700 + cost[k] = 0;
172.701 + }
172.702 + xassert(k == na);
172.703 + /* find minimal-cost circulation in the resulting network */
172.704 + ret = okalg(nv, na, tail, head, low, cap, cost, x, pi);
172.705 + switch (ret)
172.706 + { case 0:
172.707 + /* optimal circulation found */
172.708 + ret = 0;
172.709 + break;
172.710 + case 1:
172.711 + /* no feasible circulation exists */
172.712 + ret = GLP_ENOPFS;
172.713 + break;
172.714 + case 2:
172.715 + /* integer overflow occured */
172.716 + ret = GLP_ERANGE;
172.717 + goto done;
172.718 + case 3:
172.719 + /* optimality test failed (logic error) */
172.720 + ret = GLP_EFAIL;
172.721 + goto done;
172.722 + default:
172.723 + xassert(ret != ret);
172.724 + }
172.725 + /* store solution components */
172.726 + /* (objective function = the total cost) */
172.727 + if (sol != NULL)
172.728 + { temp = 0.0;
172.729 + for (k = 1; k <= na; k++)
172.730 + temp += (double)cost[k] * (double)x[k];
172.731 + if (form != GLP_ASN_MIN) temp = - temp;
172.732 + *sol = temp;
172.733 + }
172.734 + /* (arc flows) */
172.735 + if (a_x >= 0)
172.736 + { k = 0;
172.737 + for (i = 1; i <= G->nv; i++)
172.738 + { v = G->v[i];
172.739 + for (a = v->out; a != NULL; a = a->t_next)
172.740 + { k++;
172.741 + if (ret == 0)
172.742 + xassert(x[k] == 0 || x[k] == 1);
172.743 + memcpy((char *)a->data + a_x, &x[k], sizeof(int));
172.744 + }
172.745 + }
172.746 + }
172.747 +done: /* free working arrays */
172.748 + xfree(tail);
172.749 + xfree(head);
172.750 + xfree(low);
172.751 + xfree(cap);
172.752 + xfree(cost);
172.753 + xfree(x);
172.754 + xfree(pi);
172.755 + return ret;
172.756 +}
172.757 +
172.758 +/***********************************************************************
172.759 +* NAME
172.760 +*
172.761 +* glp_asnprob_hall - find bipartite matching of maximum cardinality
172.762 +*
172.763 +* SYNOPSIS
172.764 +*
172.765 +* int glp_asnprob_hall(glp_graph *G, int v_set, int a_x);
172.766 +*
172.767 +* DESCRIPTION
172.768 +*
172.769 +* The routine glp_asnprob_hall finds a matching of maximal cardinality
172.770 +* in the specified bipartite graph G. It uses a version of the Fortran
172.771 +* routine MC21A developed by I.S.Duff [1], which implements Hall's
172.772 +* algorithm [2].
172.773 +*
172.774 +* RETURNS
172.775 +*
172.776 +* The routine glp_asnprob_hall returns the cardinality of the matching
172.777 +* found. However, if the specified graph is incorrect (as detected by
172.778 +* the routine glp_check_asnprob), the routine returns negative value.
172.779 +*
172.780 +* REFERENCES
172.781 +*
172.782 +* 1. I.S.Duff, Algorithm 575: Permutations for zero-free diagonal, ACM
172.783 +* Trans. on Math. Softw. 7 (1981), 387-390.
172.784 +*
172.785 +* 2. M.Hall, "An Algorithm for distinct representatives," Amer. Math.
172.786 +* Monthly 63 (1956), 716-717. */
172.787 +
172.788 +int glp_asnprob_hall(glp_graph *G, int v_set, int a_x)
172.789 +{ glp_vertex *v;
172.790 + glp_arc *a;
172.791 + int card, i, k, loc, n, n1, n2, xij;
172.792 + int *num, *icn, *ip, *lenr, *iperm, *pr, *arp, *cv, *out;
172.793 + if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
172.794 + xerror("glp_asnprob_hall: v_set = %d; invalid offset\n",
172.795 + v_set);
172.796 + if (a_x >= 0 && a_x > G->a_size - (int)sizeof(int))
172.797 + xerror("glp_asnprob_hall: a_x = %d; invalid offset\n", a_x);
172.798 + if (glp_check_asnprob(G, v_set))
172.799 + return -1;
172.800 + /* determine the number of vertices in sets R and S and renumber
172.801 + vertices in S which correspond to columns of the matrix; skip
172.802 + all isolated vertices */
172.803 + num = xcalloc(1+G->nv, sizeof(int));
172.804 + n1 = n2 = 0;
172.805 + for (i = 1; i <= G->nv; i++)
172.806 + { v = G->v[i];
172.807 + if (v->in == NULL && v->out != NULL)
172.808 + n1++, num[i] = 0; /* vertex in R */
172.809 + else if (v->in != NULL && v->out == NULL)
172.810 + n2++, num[i] = n2; /* vertex in S */
172.811 + else
172.812 + { xassert(v->in == NULL && v->out == NULL);
172.813 + num[i] = -1; /* isolated vertex */
172.814 + }
172.815 + }
172.816 + /* the matrix must be square, thus, if it has more columns than
172.817 + rows, extra rows will be just empty, and vice versa */
172.818 + n = (n1 >= n2 ? n1 : n2);
172.819 + /* allocate working arrays */
172.820 + icn = xcalloc(1+G->na, sizeof(int));
172.821 + ip = xcalloc(1+n, sizeof(int));
172.822 + lenr = xcalloc(1+n, sizeof(int));
172.823 + iperm = xcalloc(1+n, sizeof(int));
172.824 + pr = xcalloc(1+n, sizeof(int));
172.825 + arp = xcalloc(1+n, sizeof(int));
172.826 + cv = xcalloc(1+n, sizeof(int));
172.827 + out = xcalloc(1+n, sizeof(int));
172.828 + /* build the adjacency matrix of the bipartite graph in row-wise
172.829 + format (rows are vertices in R, columns are vertices in S) */
172.830 + k = 0, loc = 1;
172.831 + for (i = 1; i <= G->nv; i++)
172.832 + { if (num[i] != 0) continue;
172.833 + /* vertex i in R */
172.834 + ip[++k] = loc;
172.835 + v = G->v[i];
172.836 + for (a = v->out; a != NULL; a = a->t_next)
172.837 + { xassert(num[a->head->i] != 0);
172.838 + icn[loc++] = num[a->head->i];
172.839 + }
172.840 + lenr[k] = loc - ip[k];
172.841 + }
172.842 + xassert(loc-1 == G->na);
172.843 + /* make all extra rows empty (all extra columns are empty due to
172.844 + the row-wise format used) */
172.845 + for (k++; k <= n; k++)
172.846 + ip[k] = loc, lenr[k] = 0;
172.847 + /* find a row permutation that maximizes the number of non-zeros
172.848 + on the main diagonal */
172.849 + card = mc21a(n, icn, ip, lenr, iperm, pr, arp, cv, out);
172.850 +#if 1 /* 18/II-2010 */
172.851 + /* FIXED: if card = n, arp remains clobbered on exit */
172.852 + for (i = 1; i <= n; i++)
172.853 + arp[i] = 0;
172.854 + for (i = 1; i <= card; i++)
172.855 + { k = iperm[i];
172.856 + xassert(1 <= k && k <= n);
172.857 + xassert(arp[k] == 0);
172.858 + arp[k] = i;
172.859 + }
172.860 +#endif
172.861 + /* store solution, if necessary */
172.862 + if (a_x < 0) goto skip;
172.863 + k = 0;
172.864 + for (i = 1; i <= G->nv; i++)
172.865 + { if (num[i] != 0) continue;
172.866 + /* vertex i in R */
172.867 + k++;
172.868 + v = G->v[i];
172.869 + for (a = v->out; a != NULL; a = a->t_next)
172.870 + { /* arp[k] is the number of matched column or zero */
172.871 + if (arp[k] == num[a->head->i])
172.872 + { xassert(arp[k] != 0);
172.873 + xij = 1;
172.874 + }
172.875 + else
172.876 + xij = 0;
172.877 + memcpy((char *)a->data + a_x, &xij, sizeof(int));
172.878 + }
172.879 + }
172.880 +skip: /* free working arrays */
172.881 + xfree(num);
172.882 + xfree(icn);
172.883 + xfree(ip);
172.884 + xfree(lenr);
172.885 + xfree(iperm);
172.886 + xfree(pr);
172.887 + xfree(arp);
172.888 + xfree(cv);
172.889 + xfree(out);
172.890 + return card;
172.891 +}
172.892 +
172.893 +/***********************************************************************
172.894 +* NAME
172.895 +*
172.896 +* glp_cpp - solve critical path problem
172.897 +*
172.898 +* SYNOPSIS
172.899 +*
172.900 +* double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls);
172.901 +*
172.902 +* DESCRIPTION
172.903 +*
172.904 +* The routine glp_cpp solves the critical path problem represented in
172.905 +* the form of the project network.
172.906 +*
172.907 +* The parameter G is a pointer to the graph object, which specifies
172.908 +* the project network. This graph must be acyclic. Multiple arcs are
172.909 +* allowed being considered as single arcs.
172.910 +*
172.911 +* The parameter v_t specifies an offset of the field of type double
172.912 +* in the vertex data block, which contains time t[i] >= 0 needed to
172.913 +* perform corresponding job j. If v_t < 0, it is assumed that t[i] = 1
172.914 +* for all jobs.
172.915 +*
172.916 +* The parameter v_es specifies an offset of the field of type double
172.917 +* in the vertex data block, to which the routine stores earliest start
172.918 +* time for corresponding job. If v_es < 0, this time is not stored.
172.919 +*
172.920 +* The parameter v_ls specifies an offset of the field of type double
172.921 +* in the vertex data block, to which the routine stores latest start
172.922 +* time for corresponding job. If v_ls < 0, this time is not stored.
172.923 +*
172.924 +* RETURNS
172.925 +*
172.926 +* The routine glp_cpp returns the minimal project duration, that is,
172.927 +* minimal time needed to perform all jobs in the project. */
172.928 +
172.929 +static void sorting(glp_graph *G, int list[]);
172.930 +
172.931 +double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls)
172.932 +{ glp_vertex *v;
172.933 + glp_arc *a;
172.934 + int i, j, k, nv, *list;
172.935 + double temp, total, *t, *es, *ls;
172.936 + if (v_t >= 0 && v_t > G->v_size - (int)sizeof(double))
172.937 + xerror("glp_cpp: v_t = %d; invalid offset\n", v_t);
172.938 + if (v_es >= 0 && v_es > G->v_size - (int)sizeof(double))
172.939 + xerror("glp_cpp: v_es = %d; invalid offset\n", v_es);
172.940 + if (v_ls >= 0 && v_ls > G->v_size - (int)sizeof(double))
172.941 + xerror("glp_cpp: v_ls = %d; invalid offset\n", v_ls);
172.942 + nv = G->nv;
172.943 + if (nv == 0)
172.944 + { total = 0.0;
172.945 + goto done;
172.946 + }
172.947 + /* allocate working arrays */
172.948 + t = xcalloc(1+nv, sizeof(double));
172.949 + es = xcalloc(1+nv, sizeof(double));
172.950 + ls = xcalloc(1+nv, sizeof(double));
172.951 + list = xcalloc(1+nv, sizeof(int));
172.952 + /* retrieve job times */
172.953 + for (i = 1; i <= nv; i++)
172.954 + { v = G->v[i];
172.955 + if (v_t >= 0)
172.956 + { memcpy(&t[i], (char *)v->data + v_t, sizeof(double));
172.957 + if (t[i] < 0.0)
172.958 + xerror("glp_cpp: t[%d] = %g; invalid time\n", i, t[i]);
172.959 + }
172.960 + else
172.961 + t[i] = 1.0;
172.962 + }
172.963 + /* perform topological sorting to determine the list of nodes
172.964 + (jobs) such that if list[k] = i and list[kk] = j and there
172.965 + exists arc (i->j), then k < kk */
172.966 + sorting(G, list);
172.967 + /* FORWARD PASS */
172.968 + /* determine earliest start times */
172.969 + for (k = 1; k <= nv; k++)
172.970 + { j = list[k];
172.971 + es[j] = 0.0;
172.972 + for (a = G->v[j]->in; a != NULL; a = a->h_next)
172.973 + { i = a->tail->i;
172.974 + /* there exists arc (i->j) in the project network */
172.975 + temp = es[i] + t[i];
172.976 + if (es[j] < temp) es[j] = temp;
172.977 + }
172.978 + }
172.979 + /* determine the minimal project duration */
172.980 + total = 0.0;
172.981 + for (i = 1; i <= nv; i++)
172.982 + { temp = es[i] + t[i];
172.983 + if (total < temp) total = temp;
172.984 + }
172.985 + /* BACKWARD PASS */
172.986 + /* determine latest start times */
172.987 + for (k = nv; k >= 1; k--)
172.988 + { i = list[k];
172.989 + ls[i] = total - t[i];
172.990 + for (a = G->v[i]->out; a != NULL; a = a->t_next)
172.991 + { j = a->head->i;
172.992 + /* there exists arc (i->j) in the project network */
172.993 + temp = ls[j] - t[i];
172.994 + if (ls[i] > temp) ls[i] = temp;
172.995 + }
172.996 + /* avoid possible round-off errors */
172.997 + if (ls[i] < es[i]) ls[i] = es[i];
172.998 + }
172.999 + /* store results, if necessary */
172.1000 + if (v_es >= 0)
172.1001 + { for (i = 1; i <= nv; i++)
172.1002 + { v = G->v[i];
172.1003 + memcpy((char *)v->data + v_es, &es[i], sizeof(double));
172.1004 + }
172.1005 + }
172.1006 + if (v_ls >= 0)
172.1007 + { for (i = 1; i <= nv; i++)
172.1008 + { v = G->v[i];
172.1009 + memcpy((char *)v->data + v_ls, &ls[i], sizeof(double));
172.1010 + }
172.1011 + }
172.1012 + /* free working arrays */
172.1013 + xfree(t);
172.1014 + xfree(es);
172.1015 + xfree(ls);
172.1016 + xfree(list);
172.1017 +done: return total;
172.1018 +}
172.1019 +
172.1020 +static void sorting(glp_graph *G, int list[])
172.1021 +{ /* perform topological sorting to determine the list of nodes
172.1022 + (jobs) such that if list[k] = i and list[kk] = j and there
172.1023 + exists arc (i->j), then k < kk */
172.1024 + int i, k, nv, v_size, *num;
172.1025 + void **save;
172.1026 + nv = G->nv;
172.1027 + v_size = G->v_size;
172.1028 + save = xcalloc(1+nv, sizeof(void *));
172.1029 + num = xcalloc(1+nv, sizeof(int));
172.1030 + G->v_size = sizeof(int);
172.1031 + for (i = 1; i <= nv; i++)
172.1032 + { save[i] = G->v[i]->data;
172.1033 + G->v[i]->data = &num[i];
172.1034 + list[i] = 0;
172.1035 + }
172.1036 + if (glp_top_sort(G, 0) != 0)
172.1037 + xerror("glp_cpp: project network is not acyclic\n");
172.1038 + G->v_size = v_size;
172.1039 + for (i = 1; i <= nv; i++)
172.1040 + { G->v[i]->data = save[i];
172.1041 + k = num[i];
172.1042 + xassert(1 <= k && k <= nv);
172.1043 + xassert(list[k] == 0);
172.1044 + list[k] = i;
172.1045 + }
172.1046 + xfree(save);
172.1047 + xfree(num);
172.1048 + return;
172.1049 +}
172.1050 +
172.1051 +/* eof */
173.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
173.2 +++ b/src/glpapi18.c Mon Dec 06 13:09:21 2010 +0100
173.3 @@ -0,0 +1,122 @@
173.4 +/* glpapi18.c (maximum clique problem) */
173.5 +
173.6 +/***********************************************************************
173.7 +* This code is part of GLPK (GNU Linear Programming Kit).
173.8 +*
173.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
173.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
173.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
173.12 +* E-mail: <mao@gnu.org>.
173.13 +*
173.14 +* GLPK is free software: you can redistribute it and/or modify it
173.15 +* under the terms of the GNU General Public License as published by
173.16 +* the Free Software Foundation, either version 3 of the License, or
173.17 +* (at your option) any later version.
173.18 +*
173.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
173.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
173.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
173.22 +* License for more details.
173.23 +*
173.24 +* You should have received a copy of the GNU General Public License
173.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
173.26 +***********************************************************************/
173.27 +
173.28 +#include "glpapi.h"
173.29 +#include "glpnet.h"
173.30 +
173.31 +static void set_edge(int nv, unsigned char a[], int i, int j)
173.32 +{ int k;
173.33 + xassert(1 <= j && j < i && i <= nv);
173.34 + k = ((i - 1) * (i - 2)) / 2 + (j - 1);
173.35 + a[k / CHAR_BIT] |=
173.36 + (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT));
173.37 + return;
173.38 +}
173.39 +
173.40 +int glp_wclique_exact(glp_graph *G, int v_wgt, double *sol, int v_set)
173.41 +{ /* find maximum weight clique with exact algorithm */
173.42 + glp_arc *e;
173.43 + int i, j, k, len, x, *w, *ind, ret = 0;
173.44 + unsigned char *a;
173.45 + double s, t;
173.46 + if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double))
173.47 + xerror("glp_wclique_exact: v_wgt = %d; invalid parameter\n",
173.48 + v_wgt);
173.49 + if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
173.50 + xerror("glp_wclique_exact: v_set = %d; invalid parameter\n",
173.51 + v_set);
173.52 + if (G->nv == 0)
173.53 + { /* empty graph has only empty clique */
173.54 + if (sol != NULL) *sol = 0.0;
173.55 + return 0;
173.56 + }
173.57 + /* allocate working arrays */
173.58 + w = xcalloc(1+G->nv, sizeof(int));
173.59 + ind = xcalloc(1+G->nv, sizeof(int));
173.60 + len = G->nv; /* # vertices */
173.61 + len = len * (len - 1) / 2; /* # entries in lower triangle */
173.62 + len = (len + (CHAR_BIT - 1)) / CHAR_BIT; /* # bytes needed */
173.63 + a = xcalloc(len, sizeof(char));
173.64 + memset(a, 0, len * sizeof(char));
173.65 + /* determine vertex weights */
173.66 + s = 0.0;
173.67 + for (i = 1; i <= G->nv; i++)
173.68 + { if (v_wgt >= 0)
173.69 + { memcpy(&t, (char *)G->v[i]->data + v_wgt, sizeof(double));
173.70 + if (!(0.0 <= t && t <= (double)INT_MAX && t == floor(t)))
173.71 + { ret = GLP_EDATA;
173.72 + goto done;
173.73 + }
173.74 + w[i] = (int)t;
173.75 + }
173.76 + else
173.77 + w[i] = 1;
173.78 + s += (double)w[i];
173.79 + }
173.80 + if (s > (double)INT_MAX)
173.81 + { ret = GLP_EDATA;
173.82 + goto done;
173.83 + }
173.84 + /* build the adjacency matrix */
173.85 + for (i = 1; i <= G->nv; i++)
173.86 + { for (e = G->v[i]->in; e != NULL; e = e->h_next)
173.87 + { j = e->tail->i;
173.88 + /* there exists edge (j,i) in the graph */
173.89 + if (i > j) set_edge(G->nv, a, i, j);
173.90 + }
173.91 + for (e = G->v[i]->out; e != NULL; e = e->t_next)
173.92 + { j = e->head->i;
173.93 + /* there exists edge (i,j) in the graph */
173.94 + if (i > j) set_edge(G->nv, a, i, j);
173.95 + }
173.96 + }
173.97 + /* find maximum weight clique in the graph */
173.98 + len = wclique(G->nv, w, a, ind);
173.99 + /* compute the clique weight */
173.100 + s = 0.0;
173.101 + for (k = 1; k <= len; k++)
173.102 + { i = ind[k];
173.103 + xassert(1 <= i && i <= G->nv);
173.104 + s += (double)w[i];
173.105 + }
173.106 + if (sol != NULL) *sol = s;
173.107 + /* mark vertices included in the clique */
173.108 + if (v_set >= 0)
173.109 + { x = 0;
173.110 + for (i = 1; i <= G->nv; i++)
173.111 + memcpy((char *)G->v[i]->data + v_set, &x, sizeof(int));
173.112 + x = 1;
173.113 + for (k = 1; k <= len; k++)
173.114 + { i = ind[k];
173.115 + memcpy((char *)G->v[i]->data + v_set, &x, sizeof(int));
173.116 + }
173.117 + }
173.118 +done: /* free working arrays */
173.119 + xfree(w);
173.120 + xfree(ind);
173.121 + xfree(a);
173.122 + return ret;
173.123 +}
173.124 +
173.125 +/* eof */
174.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
174.2 +++ b/src/glpapi19.c Mon Dec 06 13:09:21 2010 +0100
174.3 @@ -0,0 +1,1196 @@
174.4 +/* glpapi19.c (stand-alone LP/MIP solver) */
174.5 +
174.6 +/***********************************************************************
174.7 +* This code is part of GLPK (GNU Linear Programming Kit).
174.8 +*
174.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
174.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
174.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
174.12 +* E-mail: <mao@gnu.org>.
174.13 +*
174.14 +* GLPK is free software: you can redistribute it and/or modify it
174.15 +* under the terms of the GNU General Public License as published by
174.16 +* the Free Software Foundation, either version 3 of the License, or
174.17 +* (at your option) any later version.
174.18 +*
174.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
174.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
174.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
174.22 +* License for more details.
174.23 +*
174.24 +* You should have received a copy of the GNU General Public License
174.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
174.26 +***********************************************************************/
174.27 +
174.28 +#include "glpapi.h"
174.29 +#include "glpgmp.h"
174.30 +
174.31 +struct csa
174.32 +{ /* common storage area */
174.33 + glp_prob *prob;
174.34 + /* LP/MIP problem object */
174.35 + glp_bfcp bfcp;
174.36 + /* basis factorization control parameters */
174.37 + glp_smcp smcp;
174.38 + /* simplex method control parameters */
174.39 + glp_iptcp iptcp;
174.40 + /* interior-point method control parameters */
174.41 + glp_iocp iocp;
174.42 + /* integer optimizer control parameters */
174.43 + glp_tran *tran;
174.44 + /* model translator workspace */
174.45 + glp_graph *graph;
174.46 + /* network problem object */
174.47 + int format;
174.48 + /* problem file format: */
174.49 +#define FMT_MPS_DECK 1 /* fixed MPS */
174.50 +#define FMT_MPS_FILE 2 /* free MPS */
174.51 +#define FMT_LP 3 /* CPLEX LP */
174.52 +#define FMT_GLP 4 /* GLPK LP/MIP */
174.53 +#define FMT_MATHPROG 5 /* MathProg */
174.54 +#define FMT_MIN_COST 6 /* DIMACS min-cost flow */
174.55 +#define FMT_MAX_FLOW 7 /* DIMACS maximum flow */
174.56 + const char *in_file;
174.57 + /* name of input problem file */
174.58 +#define DATA_MAX 10
174.59 + /* maximal number of input data files */
174.60 + int ndf;
174.61 + /* number of input data files specified */
174.62 + const char *in_data[1+DATA_MAX];
174.63 + /* name(s) of input data file(s) */
174.64 + const char *out_dpy;
174.65 + /* name of output file to send display output; NULL means the
174.66 + display output is sent to the terminal */
174.67 + int seed;
174.68 + /* seed value to be passed to the MathProg translator; initially
174.69 + set to 1; 0x80000000 means the value is omitted */
174.70 + int solution;
174.71 + /* solution type flag: */
174.72 +#define SOL_BASIC 1 /* basic */
174.73 +#define SOL_INTERIOR 2 /* interior-point */
174.74 +#define SOL_INTEGER 3 /* mixed integer */
174.75 + const char *in_res;
174.76 + /* name of input solution file in raw format */
174.77 + int dir;
174.78 + /* optimization direction flag:
174.79 + 0 - not specified
174.80 + GLP_MIN - minimization
174.81 + GLP_MAX - maximization */
174.82 + int scale;
174.83 + /* automatic problem scaling flag */
174.84 + const char *out_sol;
174.85 + /* name of output solution file in printable format */
174.86 + const char *out_res;
174.87 + /* name of output solution file in raw format */
174.88 + const char *out_ranges;
174.89 + /* name of output file to write sensitivity analysis report */
174.90 + int check;
174.91 + /* input data checking flag; no solution is performed */
174.92 + const char *new_name;
174.93 + /* new name to be assigned to the problem */
174.94 + const char *out_mps;
174.95 + /* name of output problem file in fixed MPS format */
174.96 + const char *out_freemps;
174.97 + /* name of output problem file in free MPS format */
174.98 + const char *out_cpxlp;
174.99 + /* name of output problem file in CPLEX LP format */
174.100 + const char *out_glp;
174.101 + /* name of output problem file in GLPK format */
174.102 + const char *out_pb;
174.103 + /* name of output problem file in OPB format */
174.104 + const char *out_npb;
174.105 + /* name of output problem file in normalized OPB format */
174.106 + const char *log_file;
174.107 + /* name of output file to hardcopy terminal output */
174.108 + int crash;
174.109 + /* initial basis option: */
174.110 +#define USE_STD_BASIS 1 /* use standard basis */
174.111 +#define USE_ADV_BASIS 2 /* use advanced basis */
174.112 +#define USE_CPX_BASIS 3 /* use Bixby's basis */
174.113 +#define USE_INI_BASIS 4 /* use initial basis from ini_file */
174.114 + const char *ini_file;
174.115 + /* name of input file containing initial basis */
174.116 + int exact;
174.117 + /* flag to use glp_exact rather than glp_simplex */
174.118 + int xcheck;
174.119 + /* flag to check final basis with glp_exact */
174.120 + int nomip;
174.121 + /* flag to consider MIP as pure LP */
174.122 +};
174.123 +
174.124 +static void print_help(const char *my_name)
174.125 +{ /* print help information */
174.126 + xprintf("Usage: %s [options...] filename\n", my_name);
174.127 + xprintf("\n");
174.128 + xprintf("General options:\n");
174.129 + xprintf(" --mps read LP/MIP problem in fixed MPS fo"
174.130 + "rmat\n");
174.131 + xprintf(" --freemps read LP/MIP problem in free MPS for"
174.132 + "mat (default)\n");
174.133 + xprintf(" --lp read LP/MIP problem in CPLEX LP for"
174.134 + "mat\n");
174.135 + xprintf(" --glp read LP/MIP problem in GLPK format "
174.136 + "\n");
174.137 + xprintf(" --math read LP/MIP model written in GNU Ma"
174.138 + "thProg modeling\n");
174.139 + xprintf(" language\n");
174.140 + xprintf(" -m filename, --model filename\n");
174.141 + xprintf(" read model section and optional dat"
174.142 + "a section from\n");
174.143 + xprintf(" filename (same as --math)\n");
174.144 + xprintf(" -d filename, --data filename\n");
174.145 + xprintf(" read data section from filename (fo"
174.146 + "r --math only);\n");
174.147 + xprintf(" if model file also has data section"
174.148 + ", it is ignored\n");
174.149 + xprintf(" -y filename, --display filename\n");
174.150 + xprintf(" send display output to filename (fo"
174.151 + "r --math only);\n");
174.152 + xprintf(" by default the output is sent to te"
174.153 + "rminal\n");
174.154 + xprintf(" --seed value initialize pseudo-random number gen"
174.155 + "erator used in\n");
174.156 + xprintf(" MathProg model with specified seed "
174.157 + "(any integer);\n");
174.158 + xprintf(" if seed value is ?, some random see"
174.159 + "d will be used\n");
174.160 + xprintf(" --mincost read min-cost flow problem in DIMAC"
174.161 + "S format\n");
174.162 + xprintf(" --maxflow read maximum flow problem in DIMACS"
174.163 + " format\n");
174.164 + xprintf(" --simplex use simplex method (default)\n");
174.165 + xprintf(" --interior use interior point method (LP only)"
174.166 + "\n");
174.167 + xprintf(" -r filename, --read filename\n");
174.168 + xprintf(" read solution from filename rather "
174.169 + "to find it with\n");
174.170 + xprintf(" the solver\n");
174.171 + xprintf(" --min minimization\n");
174.172 + xprintf(" --max maximization\n");
174.173 + xprintf(" --scale scale problem (default)\n");
174.174 + xprintf(" --noscale do not scale problem\n");
174.175 + xprintf(" -o filename, --output filename\n");
174.176 + xprintf(" write solution to filename in print"
174.177 + "able format\n");
174.178 + xprintf(" -w filename, --write filename\n");
174.179 + xprintf(" write solution to filename in plain"
174.180 + " text format\n");
174.181 + xprintf(" --ranges filename\n");
174.182 + xprintf(" write sensitivity analysis report t"
174.183 + "o filename in\n");
174.184 + xprintf(" printable format (simplex only)\n");
174.185 + xprintf(" --tmlim nnn limit solution time to nnn seconds "
174.186 + "\n");
174.187 + xprintf(" --memlim nnn limit available memory to nnn megab"
174.188 + "ytes\n");
174.189 + xprintf(" --check do not solve problem, check input d"
174.190 + "ata only\n");
174.191 + xprintf(" --name probname change problem name to probname\n");
174.192 + xprintf(" --wmps filename write problem to filename in fixed "
174.193 + "MPS format\n");
174.194 + xprintf(" --wfreemps filename\n");
174.195 + xprintf(" write problem to filename in free M"
174.196 + "PS format\n");
174.197 + xprintf(" --wlp filename write problem to filename in CPLEX "
174.198 + "LP format\n");
174.199 + xprintf(" --wglp filename write problem to filename in GLPK f"
174.200 + "ormat\n");
174.201 +#if 0
174.202 + xprintf(" --wpb filename write problem to filename in OPB fo"
174.203 + "rmat\n");
174.204 + xprintf(" --wnpb filename write problem to filename in normal"
174.205 + "ized OPB format\n");
174.206 +#endif
174.207 + xprintf(" --log filename write copy of terminal output to fi"
174.208 + "lename\n");
174.209 + xprintf(" -h, --help display this help information and e"
174.210 + "xit\n");
174.211 + xprintf(" -v, --version display program version and exit\n")
174.212 + ;
174.213 + xprintf("\n");
174.214 + xprintf("LP basis factorization options:\n");
174.215 + xprintf(" --luf LU + Forrest-Tomlin update\n");
174.216 + xprintf(" (faster, less stable; default)\n");
174.217 + xprintf(" --cbg LU + Schur complement + Bartels-Gol"
174.218 + "ub update\n");
174.219 + xprintf(" (slower, more stable)\n");
174.220 + xprintf(" --cgr LU + Schur complement + Givens rota"
174.221 + "tion update\n");
174.222 + xprintf(" (slower, more stable)\n");
174.223 + xprintf("\n");
174.224 + xprintf("Options specific to simplex solver:\n");
174.225 + xprintf(" --primal use primal simplex (default)\n");
174.226 + xprintf(" --dual use dual simplex\n");
174.227 + xprintf(" --std use standard initial basis of all s"
174.228 + "lacks\n");
174.229 + xprintf(" --adv use advanced initial basis (default"
174.230 + ")\n");
174.231 + xprintf(" --bib use Bixby's initial basis\n");
174.232 + xprintf(" --ini filename use as initial basis previously sav"
174.233 + "ed with -w\n");
174.234 + xprintf(" (disables LP presolver)\n");
174.235 + xprintf(" --steep use steepest edge technique (defaul"
174.236 + "t)\n");
174.237 + xprintf(" --nosteep use standard \"textbook\" pricing\n"
174.238 + );
174.239 + xprintf(" --relax use Harris' two-pass ratio test (de"
174.240 + "fault)\n");
174.241 + xprintf(" --norelax use standard \"textbook\" ratio tes"
174.242 + "t\n");
174.243 + xprintf(" --presol use presolver (default; assumes --s"
174.244 + "cale and --adv)\n");
174.245 + xprintf(" --nopresol do not use presolver\n");
174.246 + xprintf(" --exact use simplex method based on exact a"
174.247 + "rithmetic\n");
174.248 + xprintf(" --xcheck check final basis using exact arith"
174.249 + "metic\n");
174.250 + xprintf("\n");
174.251 + xprintf("Options specific to interior-point solver:\n");
174.252 + xprintf(" --nord use natural (original) ordering\n");
174.253 + xprintf(" --qmd use quotient minimum degree orderin"
174.254 + "g\n");
174.255 + xprintf(" --amd use approximate minimum degree orde"
174.256 + "ring (default)\n");
174.257 + xprintf(" --symamd use approximate minimum degree orde"
174.258 + "ring\n");
174.259 + xprintf("\n");
174.260 + xprintf("Options specific to MIP solver:\n");
174.261 + xprintf(" --nomip consider all integer variables as c"
174.262 + "ontinuous\n");
174.263 + xprintf(" (allows solving MIP as pure LP)\n");
174.264 + xprintf(" --first branch on first integer variable\n")
174.265 + ;
174.266 + xprintf(" --last branch on last integer variable\n");
174.267 + xprintf(" --mostf branch on most fractional variable "
174.268 + "\n");
174.269 + xprintf(" --drtom branch using heuristic by Driebeck "
174.270 + "and Tomlin\n");
174.271 + xprintf(" (default)\n");
174.272 + xprintf(" --pcost branch using hybrid pseudocost heur"
174.273 + "istic (may be\n");
174.274 + xprintf(" useful for hard instances)\n");
174.275 + xprintf(" --dfs backtrack using depth first search "
174.276 + "\n");
174.277 + xprintf(" --bfs backtrack using breadth first searc"
174.278 + "h\n");
174.279 + xprintf(" --bestp backtrack using the best projection"
174.280 + " heuristic\n");
174.281 + xprintf(" --bestb backtrack using node with best loca"
174.282 + "l bound\n");
174.283 + xprintf(" (default)\n");
174.284 + xprintf(" --intopt use MIP presolver (default)\n");
174.285 + xprintf(" --nointopt do not use MIP presolver\n");
174.286 + xprintf(" --binarize replace general integer variables b"
174.287 + "y binary ones\n");
174.288 + xprintf(" (assumes --intopt)\n");
174.289 + xprintf(" --fpump apply feasibility pump heuristic\n")
174.290 + ;
174.291 + xprintf(" --gomory generate Gomory's mixed integer cut"
174.292 + "s\n");
174.293 + xprintf(" --mir generate MIR (mixed integer roundin"
174.294 + "g) cuts\n");
174.295 + xprintf(" --cover generate mixed cover cuts\n");
174.296 + xprintf(" --clique generate clique cuts\n");
174.297 + xprintf(" --cuts generate all cuts above\n");
174.298 + xprintf(" --mipgap tol set relative mip gap tolerance to t"
174.299 + "ol\n");
174.300 + xprintf("\n");
174.301 + xprintf("For description of the MPS and CPLEX LP formats see Refe"
174.302 + "rence Manual.\n");
174.303 + xprintf("For description of the modeling language see \"GLPK: Mod"
174.304 + "eling Language\n");
174.305 + xprintf("GNU MathProg\". Both documents are included in the GLPK "
174.306 + "distribution.\n");
174.307 + xprintf("\n");
174.308 + xprintf("See GLPK web page at <http://www.gnu.org/software/glpk/g"
174.309 + "lpk.html>.\n");
174.310 + xprintf("\n");
174.311 + xprintf("Please report bugs to <bug-glpk@gnu.org>.\n");
174.312 + return;
174.313 +}
174.314 +
174.315 +static void print_version(int briefly)
174.316 +{ /* print version information */
174.317 + xprintf("GLPSOL: GLPK LP/MIP Solver, v%s\n", glp_version());
174.318 + if (briefly) goto done;
174.319 + xprintf("\n");
174.320 + xprintf("Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, "
174.321 + "2007, 2008,\n");
174.322 + xprintf("2009, 2010 Andrew Makhorin, Department for Applied Infor"
174.323 + "matics, Moscow\n");
174.324 + xprintf("Aviation Institute, Moscow, Russia. All rights reserved."
174.325 + "\n");
174.326 + xprintf("\n");
174.327 + xprintf("This program has ABSOLUTELY NO WARRANTY.\n");
174.328 + xprintf("\n");
174.329 + xprintf("This program is free software; you may re-distribute it "
174.330 + "under the terms\n");
174.331 + xprintf("of the GNU General Public License version 3 or later.\n")
174.332 + ;
174.333 +done: return;
174.334 +}
174.335 +
174.336 +static int parse_cmdline(struct csa *csa, int argc, const char *argv[])
174.337 +{ /* parse command-line parameters */
174.338 + int k;
174.339 +#define p(str) (strcmp(argv[k], str) == 0)
174.340 + for (k = 1; k < argc; k++)
174.341 + { if (p("--mps"))
174.342 + csa->format = FMT_MPS_DECK;
174.343 + else if (p("--freemps"))
174.344 + csa->format = FMT_MPS_FILE;
174.345 + else if (p("--lp") || p("--cpxlp"))
174.346 + csa->format = FMT_LP;
174.347 + else if (p("--glp"))
174.348 + csa->format = FMT_GLP;
174.349 + else if (p("--math") || p("-m") || p("--model"))
174.350 + csa->format = FMT_MATHPROG;
174.351 + else if (p("-d") || p("--data"))
174.352 + { k++;
174.353 + if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
174.354 + { xprintf("No input data file specified\n");
174.355 + return 1;
174.356 + }
174.357 + if (csa->ndf == DATA_MAX)
174.358 + { xprintf("Too many input data files\n");
174.359 + return 1;
174.360 + }
174.361 + csa->in_data[++(csa->ndf)] = argv[k];
174.362 + }
174.363 + else if (p("-y") || p("--display"))
174.364 + { k++;
174.365 + if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
174.366 + { xprintf("No display output file specified\n");
174.367 + return 1;
174.368 + }
174.369 + if (csa->out_dpy != NULL)
174.370 + { xprintf("Only one display output file allowed\n");
174.371 + return 1;
174.372 + }
174.373 + csa->out_dpy = argv[k];
174.374 + }
174.375 + else if (p("--seed"))
174.376 + { k++;
174.377 + if (k == argc || argv[k][0] == '\0' ||
174.378 + argv[k][0] == '-' && !isdigit((unsigned char)argv[k][1]))
174.379 + { xprintf("No seed value specified\n");
174.380 + return 1;
174.381 + }
174.382 + if (strcmp(argv[k], "?") == 0)
174.383 + csa->seed = 0x80000000;
174.384 + else if (str2int(argv[k], &csa->seed))
174.385 + { xprintf("Invalid seed value `%s'\n", argv[k]);
174.386 + return 1;
174.387 + }
174.388 + }
174.389 + else if (p("--mincost"))
174.390 + csa->format = FMT_MIN_COST;
174.391 + else if (p("--maxflow"))
174.392 + csa->format = FMT_MAX_FLOW;
174.393 + else if (p("--simplex"))
174.394 + csa->solution = SOL_BASIC;
174.395 + else if (p("--interior"))
174.396 + csa->solution = SOL_INTERIOR;
174.397 +#if 1 /* 28/V-2010 */
174.398 + else if (p("--alien"))
174.399 + csa->iocp.alien = GLP_ON;
174.400 +#endif
174.401 + else if (p("-r") || p("--read"))
174.402 + { k++;
174.403 + if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
174.404 + { xprintf("No input solution file specified\n");
174.405 + return 1;
174.406 + }
174.407 + if (csa->in_res != NULL)
174.408 + { xprintf("Only one input solution file allowed\n");
174.409 + return 1;
174.410 + }
174.411 + csa->in_res = argv[k];
174.412 + }
174.413 + else if (p("--min"))
174.414 + csa->dir = GLP_MIN;
174.415 + else if (p("--max"))
174.416 + csa->dir = GLP_MAX;
174.417 + else if (p("--scale"))
174.418 + csa->scale = 1;
174.419 + else if (p("--noscale"))
174.420 + csa->scale = 0;
174.421 + else if (p("-o") || p("--output"))
174.422 + { k++;
174.423 + if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
174.424 + { xprintf("No output solution file specified\n");
174.425 + return 1;
174.426 + }
174.427 + if (csa->out_sol != NULL)
174.428 + { xprintf("Only one output solution file allowed\n");
174.429 + return 1;
174.430 + }
174.431 + csa->out_sol = argv[k];
174.432 + }
174.433 + else if (p("-w") || p("--write"))
174.434 + { k++;
174.435 + if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
174.436 + { xprintf("No output solution file specified\n");
174.437 + return 1;
174.438 + }
174.439 + if (csa->out_res != NULL)
174.440 + { xprintf("Only one output solution file allowed\n");
174.441 + return 1;
174.442 + }
174.443 + csa->out_res = argv[k];
174.444 + }
174.445 + else if (p("--ranges") || p("--bounds"))
174.446 + { k++;
174.447 + if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
174.448 + { xprintf("No output file specified to write sensitivity a"
174.449 + "nalysis report\n");
174.450 + return 1;
174.451 + }
174.452 + if (csa->out_ranges != NULL)
174.453 + { xprintf("Only one output file allowed to write sensitivi"
174.454 + "ty analysis report\n");
174.455 + return 1;
174.456 + }
174.457 + csa->out_ranges = argv[k];
174.458 + }
174.459 + else if (p("--tmlim"))
174.460 + { int tm_lim;
174.461 + k++;
174.462 + if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
174.463 + { xprintf("No time limit specified\n");
174.464 + return 1;
174.465 + }
174.466 + if (str2int(argv[k], &tm_lim) || tm_lim < 0)
174.467 + { xprintf("Invalid time limit `%s'\n", argv[k]);
174.468 + return 1;
174.469 + }
174.470 + if (tm_lim <= INT_MAX / 1000)
174.471 + csa->smcp.tm_lim = csa->iocp.tm_lim = 1000 * tm_lim;
174.472 + else
174.473 + csa->smcp.tm_lim = csa->iocp.tm_lim = INT_MAX;
174.474 + }
174.475 + else if (p("--memlim"))
174.476 + { int mem_lim;
174.477 + k++;
174.478 + if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
174.479 + { xprintf("No memory limit specified\n");
174.480 + return 1;
174.481 + }
174.482 + if (str2int(argv[k], &mem_lim) || mem_lim < 1)
174.483 + { xprintf("Invalid memory limit `%s'\n", argv[k]);
174.484 + return 1;
174.485 + }
174.486 + glp_mem_limit(mem_lim);
174.487 + }
174.488 + else if (p("--check"))
174.489 + csa->check = 1;
174.490 + else if (p("--name"))
174.491 + { k++;
174.492 + if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
174.493 + { xprintf("No problem name specified\n");
174.494 + return 1;
174.495 + }
174.496 + if (csa->new_name != NULL)
174.497 + { xprintf("Only one problem name allowed\n");
174.498 + return 1;
174.499 + }
174.500 + csa->new_name = argv[k];
174.501 + }
174.502 + else if (p("--wmps"))
174.503 + { k++;
174.504 + if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
174.505 + { xprintf("No fixed MPS output file specified\n");
174.506 + return 1;
174.507 + }
174.508 + if (csa->out_mps != NULL)
174.509 + { xprintf("Only one fixed MPS output file allowed\n");
174.510 + return 1;
174.511 + }
174.512 + csa->out_mps = argv[k];
174.513 + }
174.514 + else if (p("--wfreemps"))
174.515 + { k++;
174.516 + if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
174.517 + { xprintf("No free MPS output file specified\n");
174.518 + return 1;
174.519 + }
174.520 + if (csa->out_freemps != NULL)
174.521 + { xprintf("Only one free MPS output file allowed\n");
174.522 + return 1;
174.523 + }
174.524 + csa->out_freemps = argv[k];
174.525 + }
174.526 + else if (p("--wlp") || p("--wcpxlp") || p("--wlpt"))
174.527 + { k++;
174.528 + if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
174.529 + { xprintf("No CPLEX LP output file specified\n");
174.530 + return 1;
174.531 + }
174.532 + if (csa->out_cpxlp != NULL)
174.533 + { xprintf("Only one CPLEX LP output file allowed\n");
174.534 + return 1;
174.535 + }
174.536 + csa->out_cpxlp = argv[k];
174.537 + }
174.538 + else if (p("--wglp"))
174.539 + { k++;
174.540 + if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
174.541 + { xprintf("No GLPK LP/MIP output file specified\n");
174.542 + return 1;
174.543 + }
174.544 + if (csa->out_glp != NULL)
174.545 + { xprintf("Only one GLPK LP/MIP output file allowed\n");
174.546 + return 1;
174.547 + }
174.548 + csa->out_glp = argv[k];
174.549 + }
174.550 + else if (p("--wpb"))
174.551 + { k++;
174.552 + if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
174.553 + { xprintf("No problem output file specified\n");
174.554 + return 1;
174.555 + }
174.556 + if (csa->out_pb != NULL)
174.557 + { xprintf("Only one OPB output file allowed\n");
174.558 + return 1;
174.559 + }
174.560 + csa->out_pb = argv[k];
174.561 + }
174.562 + else if (p("--wnpb"))
174.563 + { k++;
174.564 + if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
174.565 + { xprintf("No problem output file specified\n");
174.566 + return 1;
174.567 + }
174.568 + if (csa->out_npb != NULL)
174.569 + { xprintf("Only one normalized OPB output file allowed\n");
174.570 + return 1;
174.571 + }
174.572 + csa->out_npb = argv[k];
174.573 + }
174.574 + else if (p("--log"))
174.575 + { k++;
174.576 + if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
174.577 + { xprintf("No log file specified\n");
174.578 + return 1;
174.579 + }
174.580 + if (csa->log_file != NULL)
174.581 + { xprintf("Only one log file allowed\n");
174.582 + return 1;
174.583 + }
174.584 + csa->log_file = argv[k];
174.585 + }
174.586 + else if (p("-h") || p("--help"))
174.587 + { print_help(argv[0]);
174.588 + return -1;
174.589 + }
174.590 + else if (p("-v") || p("--version"))
174.591 + { print_version(0);
174.592 + return -1;
174.593 + }
174.594 + else if (p("--luf"))
174.595 + csa->bfcp.type = GLP_BF_FT;
174.596 + else if (p("--cbg"))
174.597 + csa->bfcp.type = GLP_BF_BG;
174.598 + else if (p("--cgr"))
174.599 + csa->bfcp.type = GLP_BF_GR;
174.600 + else if (p("--primal"))
174.601 + csa->smcp.meth = GLP_PRIMAL;
174.602 + else if (p("--dual"))
174.603 + csa->smcp.meth = GLP_DUAL;
174.604 + else if (p("--std"))
174.605 + csa->crash = USE_STD_BASIS;
174.606 + else if (p("--adv"))
174.607 + csa->crash = USE_ADV_BASIS;
174.608 + else if (p("--bib"))
174.609 + csa->crash = USE_CPX_BASIS;
174.610 + else if (p("--ini"))
174.611 + { csa->crash = USE_INI_BASIS;
174.612 + csa->smcp.presolve = GLP_OFF;
174.613 + k++;
174.614 + if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
174.615 + { xprintf("No initial basis file specified\n");
174.616 + return 1;
174.617 + }
174.618 + if (csa->ini_file != NULL)
174.619 + { xprintf("Only one initial basis file allowed\n");
174.620 + return 1;
174.621 + }
174.622 + csa->ini_file = argv[k];
174.623 + }
174.624 + else if (p("--steep"))
174.625 + csa->smcp.pricing = GLP_PT_PSE;
174.626 + else if (p("--nosteep"))
174.627 + csa->smcp.pricing = GLP_PT_STD;
174.628 + else if (p("--relax"))
174.629 + csa->smcp.r_test = GLP_RT_HAR;
174.630 + else if (p("--norelax"))
174.631 + csa->smcp.r_test = GLP_RT_STD;
174.632 + else if (p("--presol"))
174.633 + csa->smcp.presolve = GLP_ON;
174.634 + else if (p("--nopresol"))
174.635 + csa->smcp.presolve = GLP_OFF;
174.636 + else if (p("--exact"))
174.637 + csa->exact = 1;
174.638 + else if (p("--xcheck"))
174.639 + csa->xcheck = 1;
174.640 + else if (p("--nord"))
174.641 + csa->iptcp.ord_alg = GLP_ORD_NONE;
174.642 + else if (p("--qmd"))
174.643 + csa->iptcp.ord_alg = GLP_ORD_QMD;
174.644 + else if (p("--amd"))
174.645 + csa->iptcp.ord_alg = GLP_ORD_AMD;
174.646 + else if (p("--symamd"))
174.647 + csa->iptcp.ord_alg = GLP_ORD_SYMAMD;
174.648 + else if (p("--nomip"))
174.649 + csa->nomip = 1;
174.650 + else if (p("--first"))
174.651 + csa->iocp.br_tech = GLP_BR_FFV;
174.652 + else if (p("--last"))
174.653 + csa->iocp.br_tech = GLP_BR_LFV;
174.654 + else if (p("--drtom"))
174.655 + csa->iocp.br_tech = GLP_BR_DTH;
174.656 + else if (p("--mostf"))
174.657 + csa->iocp.br_tech = GLP_BR_MFV;
174.658 + else if (p("--pcost"))
174.659 + csa->iocp.br_tech = GLP_BR_PCH;
174.660 + else if (p("--dfs"))
174.661 + csa->iocp.bt_tech = GLP_BT_DFS;
174.662 + else if (p("--bfs"))
174.663 + csa->iocp.bt_tech = GLP_BT_BFS;
174.664 + else if (p("--bestp"))
174.665 + csa->iocp.bt_tech = GLP_BT_BPH;
174.666 + else if (p("--bestb"))
174.667 + csa->iocp.bt_tech = GLP_BT_BLB;
174.668 + else if (p("--intopt"))
174.669 + csa->iocp.presolve = GLP_ON;
174.670 + else if (p("--nointopt"))
174.671 + csa->iocp.presolve = GLP_OFF;
174.672 + else if (p("--binarize"))
174.673 + csa->iocp.presolve = csa->iocp.binarize = GLP_ON;
174.674 + else if (p("--fpump"))
174.675 + csa->iocp.fp_heur = GLP_ON;
174.676 + else if (p("--gomory"))
174.677 + csa->iocp.gmi_cuts = GLP_ON;
174.678 + else if (p("--mir"))
174.679 + csa->iocp.mir_cuts = GLP_ON;
174.680 + else if (p("--cover"))
174.681 + csa->iocp.cov_cuts = GLP_ON;
174.682 + else if (p("--clique"))
174.683 + csa->iocp.clq_cuts = GLP_ON;
174.684 + else if (p("--cuts"))
174.685 + csa->iocp.gmi_cuts = csa->iocp.mir_cuts =
174.686 + csa->iocp.cov_cuts = csa->iocp.clq_cuts = GLP_ON;
174.687 + else if (p("--mipgap"))
174.688 + { double mip_gap;
174.689 + k++;
174.690 + if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
174.691 + { xprintf("No relative gap tolerance specified\n");
174.692 + return 1;
174.693 + }
174.694 + if (str2num(argv[k], &mip_gap) || mip_gap < 0.0)
174.695 + { xprintf("Invalid relative mip gap tolerance `%s'\n",
174.696 + argv[k]);
174.697 + return 1;
174.698 + }
174.699 + csa->iocp.mip_gap = mip_gap;
174.700 + }
174.701 + else if (argv[k][0] == '-' ||
174.702 + (argv[k][0] == '-' && argv[k][1] == '-'))
174.703 + { xprintf("Invalid option `%s'; try %s --help\n",
174.704 + argv[k], argv[0]);
174.705 + return 1;
174.706 + }
174.707 + else
174.708 + { if (csa->in_file != NULL)
174.709 + { xprintf("Only one input problem file allowed\n");
174.710 + return 1;
174.711 + }
174.712 + csa->in_file = argv[k];
174.713 + }
174.714 + }
174.715 +#undef p
174.716 + return 0;
174.717 +}
174.718 +
174.719 +typedef struct { double rhs, pi; } v_data;
174.720 +typedef struct { double low, cap, cost, x; } a_data;
174.721 +
174.722 +int glp_main(int argc, const char *argv[])
174.723 +{ /* stand-alone LP/MIP solver */
174.724 + struct csa _csa, *csa = &_csa;
174.725 + int ret;
174.726 + glp_long start;
174.727 + /* perform initialization */
174.728 + csa->prob = glp_create_prob();
174.729 + glp_get_bfcp(csa->prob, &csa->bfcp);
174.730 + glp_init_smcp(&csa->smcp);
174.731 + csa->smcp.presolve = GLP_ON;
174.732 + glp_init_iptcp(&csa->iptcp);
174.733 + glp_init_iocp(&csa->iocp);
174.734 + csa->iocp.presolve = GLP_ON;
174.735 + csa->tran = NULL;
174.736 + csa->graph = NULL;
174.737 + csa->format = FMT_MPS_FILE;
174.738 + csa->in_file = NULL;
174.739 + csa->ndf = 0;
174.740 + csa->out_dpy = NULL;
174.741 + csa->seed = 1;
174.742 + csa->solution = SOL_BASIC;
174.743 + csa->in_res = NULL;
174.744 + csa->dir = 0;
174.745 + csa->scale = 1;
174.746 + csa->out_sol = NULL;
174.747 + csa->out_res = NULL;
174.748 + csa->out_ranges = NULL;
174.749 + csa->check = 0;
174.750 + csa->new_name = NULL;
174.751 + csa->out_mps = NULL;
174.752 + csa->out_freemps = NULL;
174.753 + csa->out_cpxlp = NULL;
174.754 + csa->out_glp = NULL;
174.755 + csa->out_pb = NULL;
174.756 + csa->out_npb = NULL;
174.757 + csa->log_file = NULL;
174.758 + csa->crash = USE_ADV_BASIS;
174.759 + csa->ini_file = NULL;
174.760 + csa->exact = 0;
174.761 + csa->xcheck = 0;
174.762 + csa->nomip = 0;
174.763 + /* parse command-line parameters */
174.764 + ret = parse_cmdline(csa, argc, argv);
174.765 + if (ret < 0)
174.766 + { ret = EXIT_SUCCESS;
174.767 + goto done;
174.768 + }
174.769 + if (ret > 0)
174.770 + { ret = EXIT_FAILURE;
174.771 + goto done;
174.772 + }
174.773 + /*--------------------------------------------------------------*/
174.774 + /* remove all output files specified in the command line */
174.775 + if (csa->out_dpy != NULL) remove(csa->out_dpy);
174.776 + if (csa->out_sol != NULL) remove(csa->out_sol);
174.777 + if (csa->out_res != NULL) remove(csa->out_res);
174.778 + if (csa->out_ranges != NULL) remove(csa->out_ranges);
174.779 + if (csa->out_mps != NULL) remove(csa->out_mps);
174.780 + if (csa->out_freemps != NULL) remove(csa->out_freemps);
174.781 + if (csa->out_cpxlp != NULL) remove(csa->out_cpxlp);
174.782 + if (csa->out_glp != NULL) remove(csa->out_glp);
174.783 + if (csa->out_pb != NULL) remove(csa->out_pb);
174.784 + if (csa->out_npb != NULL) remove(csa->out_npb);
174.785 + if (csa->log_file != NULL) remove(csa->log_file);
174.786 + /*--------------------------------------------------------------*/
174.787 + /* open log file, if required */
174.788 + if (csa->log_file != NULL)
174.789 + { if (glp_open_tee(csa->log_file))
174.790 + { xprintf("Unable to create log file\n");
174.791 + ret = EXIT_FAILURE;
174.792 + goto done;
174.793 + }
174.794 + }
174.795 + /*--------------------------------------------------------------*/
174.796 + /* print version information */
174.797 + print_version(1);
174.798 + /*--------------------------------------------------------------*/
174.799 + /* print parameters specified in the command line */
174.800 + if (argc > 1)
174.801 + { int k, len = INT_MAX;
174.802 + xprintf("Parameter(s) specified in the command line:");
174.803 + for (k = 1; k < argc; k++)
174.804 + { if (len > 72)
174.805 + xprintf("\n"), len = 0;
174.806 + xprintf(" %s", argv[k]);
174.807 + len += 1 + strlen(argv[k]);
174.808 + }
174.809 + xprintf("\n");
174.810 + }
174.811 + /*--------------------------------------------------------------*/
174.812 + /* read problem data from the input file */
174.813 + if (csa->in_file == NULL)
174.814 + { xprintf("No input problem file specified; try %s --help\n",
174.815 + argv[0]);
174.816 + ret = EXIT_FAILURE;
174.817 + goto done;
174.818 + }
174.819 + if (csa->format == FMT_MPS_DECK)
174.820 + { ret = glp_read_mps(csa->prob, GLP_MPS_DECK, NULL,
174.821 + csa->in_file);
174.822 + if (ret != 0)
174.823 +err1: { xprintf("MPS file processing error\n");
174.824 + ret = EXIT_FAILURE;
174.825 + goto done;
174.826 + }
174.827 + }
174.828 + else if (csa->format == FMT_MPS_FILE)
174.829 + { ret = glp_read_mps(csa->prob, GLP_MPS_FILE, NULL,
174.830 + csa->in_file);
174.831 + if (ret != 0) goto err1;
174.832 + }
174.833 + else if (csa->format == FMT_LP)
174.834 + { ret = glp_read_lp(csa->prob, NULL, csa->in_file);
174.835 + if (ret != 0)
174.836 + { xprintf("CPLEX LP file processing error\n");
174.837 + ret = EXIT_FAILURE;
174.838 + goto done;
174.839 + }
174.840 + }
174.841 + else if (csa->format == FMT_GLP)
174.842 + { ret = glp_read_prob(csa->prob, 0, csa->in_file);
174.843 + if (ret != 0)
174.844 + { xprintf("GLPK LP/MIP file processing error\n");
174.845 + ret = EXIT_FAILURE;
174.846 + goto done;
174.847 + }
174.848 + }
174.849 + else if (csa->format == FMT_MATHPROG)
174.850 + { int k;
174.851 + /* allocate the translator workspace */
174.852 + csa->tran = glp_mpl_alloc_wksp();
174.853 + /* set seed value */
174.854 + if (csa->seed == 0x80000000)
174.855 + { csa->seed = glp_time().lo;
174.856 + xprintf("Seed value %d will be used\n", csa->seed);
174.857 + }
174.858 + _glp_mpl_init_rand(csa->tran, csa->seed);
174.859 + /* read model section and optional data section */
174.860 + if (glp_mpl_read_model(csa->tran, csa->in_file, csa->ndf > 0))
174.861 +err2: { xprintf("MathProg model processing error\n");
174.862 + ret = EXIT_FAILURE;
174.863 + goto done;
174.864 + }
174.865 + /* read optional data section(s), if necessary */
174.866 + for (k = 1; k <= csa->ndf; k++)
174.867 + { if (glp_mpl_read_data(csa->tran, csa->in_data[k]))
174.868 + goto err2;
174.869 + }
174.870 + /* generate the model */
174.871 + if (glp_mpl_generate(csa->tran, csa->out_dpy)) goto err2;
174.872 + /* build the problem instance from the model */
174.873 + glp_mpl_build_prob(csa->tran, csa->prob);
174.874 + }
174.875 + else if (csa->format == FMT_MIN_COST)
174.876 + { csa->graph = glp_create_graph(sizeof(v_data), sizeof(a_data));
174.877 + ret = glp_read_mincost(csa->graph, offsetof(v_data, rhs),
174.878 + offsetof(a_data, low), offsetof(a_data, cap),
174.879 + offsetof(a_data, cost), csa->in_file);
174.880 + if (ret != 0)
174.881 + { xprintf("DIMACS file processing error\n");
174.882 + ret = EXIT_FAILURE;
174.883 + goto done;
174.884 + }
174.885 + glp_mincost_lp(csa->prob, csa->graph, GLP_ON,
174.886 + offsetof(v_data, rhs), offsetof(a_data, low),
174.887 + offsetof(a_data, cap), offsetof(a_data, cost));
174.888 + glp_set_prob_name(csa->prob, csa->in_file);
174.889 + }
174.890 + else if (csa->format == FMT_MAX_FLOW)
174.891 + { int s, t;
174.892 + csa->graph = glp_create_graph(sizeof(v_data), sizeof(a_data));
174.893 + ret = glp_read_maxflow(csa->graph, &s, &t,
174.894 + offsetof(a_data, cap), csa->in_file);
174.895 + if (ret != 0)
174.896 + { xprintf("DIMACS file processing error\n");
174.897 + ret = EXIT_FAILURE;
174.898 + goto done;
174.899 + }
174.900 + glp_maxflow_lp(csa->prob, csa->graph, GLP_ON, s, t,
174.901 + offsetof(a_data, cap));
174.902 + glp_set_prob_name(csa->prob, csa->in_file);
174.903 + }
174.904 + else
174.905 + xassert(csa != csa);
174.906 + /*--------------------------------------------------------------*/
174.907 + /* change problem name, if required */
174.908 + if (csa->new_name != NULL)
174.909 + glp_set_prob_name(csa->prob, csa->new_name);
174.910 + /* change optimization direction, if required */
174.911 + if (csa->dir != 0)
174.912 + glp_set_obj_dir(csa->prob, csa->dir);
174.913 + /* sort elements of the constraint matrix */
174.914 + glp_sort_matrix(csa->prob);
174.915 + /*--------------------------------------------------------------*/
174.916 + /* write problem data in fixed MPS format, if required */
174.917 + if (csa->out_mps != NULL)
174.918 + { ret = glp_write_mps(csa->prob, GLP_MPS_DECK, NULL,
174.919 + csa->out_mps);
174.920 + if (ret != 0)
174.921 + { xprintf("Unable to write problem in fixed MPS format\n");
174.922 + ret = EXIT_FAILURE;
174.923 + goto done;
174.924 + }
174.925 + }
174.926 + /* write problem data in free MPS format, if required */
174.927 + if (csa->out_freemps != NULL)
174.928 + { ret = glp_write_mps(csa->prob, GLP_MPS_FILE, NULL,
174.929 + csa->out_freemps);
174.930 + if (ret != 0)
174.931 + { xprintf("Unable to write problem in free MPS format\n");
174.932 + ret = EXIT_FAILURE;
174.933 + goto done;
174.934 + }
174.935 + }
174.936 + /* write problem data in CPLEX LP format, if required */
174.937 + if (csa->out_cpxlp != NULL)
174.938 + { ret = glp_write_lp(csa->prob, NULL, csa->out_cpxlp);
174.939 + if (ret != 0)
174.940 + { xprintf("Unable to write problem in CPLEX LP format\n");
174.941 + ret = EXIT_FAILURE;
174.942 + goto done;
174.943 + }
174.944 + }
174.945 + /* write problem data in GLPK format, if required */
174.946 + if (csa->out_glp != NULL)
174.947 + { ret = glp_write_prob(csa->prob, 0, csa->out_glp);
174.948 + if (ret != 0)
174.949 + { xprintf("Unable to write problem in GLPK format\n");
174.950 + ret = EXIT_FAILURE;
174.951 + goto done;
174.952 + }
174.953 + }
174.954 + /* write problem data in OPB format, if required */
174.955 + if (csa->out_pb != NULL)
174.956 + { ret = lpx_write_pb(csa->prob, csa->out_pb, 0, 0);
174.957 + if (ret != 0)
174.958 + { xprintf("Unable to write problem in OPB format\n");
174.959 + ret = EXIT_FAILURE;
174.960 + goto done;
174.961 + }
174.962 + }
174.963 + /* write problem data in normalized OPB format, if required */
174.964 + if (csa->out_npb != NULL)
174.965 + { ret = lpx_write_pb(csa->prob, csa->out_npb, 1, 1);
174.966 + if (ret != 0)
174.967 + { xprintf(
174.968 + "Unable to write problem in normalized OPB format\n");
174.969 + ret = EXIT_FAILURE;
174.970 + goto done;
174.971 + }
174.972 + }
174.973 + /*--------------------------------------------------------------*/
174.974 + /* if only problem data check is required, skip computations */
174.975 + if (csa->check)
174.976 + { ret = EXIT_SUCCESS;
174.977 + goto done;
174.978 + }
174.979 + /*--------------------------------------------------------------*/
174.980 + /* determine the solution type */
174.981 + if (!csa->nomip &&
174.982 + glp_get_num_int(csa->prob) + glp_get_num_bin(csa->prob) > 0)
174.983 + { if (csa->solution == SOL_INTERIOR)
174.984 + { xprintf("Interior-point method is not able to solve MIP pro"
174.985 + "blem; use --simplex\n");
174.986 + ret = EXIT_FAILURE;
174.987 + goto done;
174.988 + }
174.989 + csa->solution = SOL_INTEGER;
174.990 + }
174.991 + /*--------------------------------------------------------------*/
174.992 + /* if solution is provided, read it and skip computations */
174.993 + if (csa->in_res != NULL)
174.994 + { if (csa->solution == SOL_BASIC)
174.995 + ret = glp_read_sol(csa->prob, csa->in_res);
174.996 + else if (csa->solution == SOL_INTERIOR)
174.997 + ret = glp_read_ipt(csa->prob, csa->in_res);
174.998 + else if (csa->solution == SOL_INTEGER)
174.999 + ret = glp_read_mip(csa->prob, csa->in_res);
174.1000 + else
174.1001 + xassert(csa != csa);
174.1002 + if (ret != 0)
174.1003 + { xprintf("Unable to read problem solution\n");
174.1004 + ret = EXIT_FAILURE;
174.1005 + goto done;
174.1006 + }
174.1007 + goto skip;
174.1008 + }
174.1009 + /*--------------------------------------------------------------*/
174.1010 + /* scale the problem data, if required */
174.1011 + if (csa->scale)
174.1012 + { if (csa->solution == SOL_BASIC && !csa->smcp.presolve ||
174.1013 + csa->solution == SOL_INTERIOR ||
174.1014 + csa->solution == SOL_INTEGER && !csa->iocp.presolve)
174.1015 + glp_scale_prob(csa->prob, GLP_SF_AUTO);
174.1016 + }
174.1017 + /*--------------------------------------------------------------*/
174.1018 + /* construct starting LP basis */
174.1019 + if (csa->solution == SOL_BASIC && !csa->smcp.presolve ||
174.1020 + csa->solution == SOL_INTEGER && !csa->iocp.presolve)
174.1021 + { if (csa->crash == USE_STD_BASIS)
174.1022 + glp_std_basis(csa->prob);
174.1023 + else if (csa->crash == USE_ADV_BASIS)
174.1024 + glp_adv_basis(csa->prob, 0);
174.1025 + else if (csa->crash == USE_CPX_BASIS)
174.1026 + glp_cpx_basis(csa->prob);
174.1027 + else if (csa->crash == USE_INI_BASIS)
174.1028 + { ret = glp_read_sol(csa->prob, csa->ini_file);
174.1029 + if (ret != 0)
174.1030 + { xprintf("Unable to read initial basis\n");
174.1031 + ret = EXIT_FAILURE;
174.1032 + goto done;
174.1033 + }
174.1034 + }
174.1035 + else
174.1036 + xassert(csa != csa);
174.1037 + }
174.1038 + /*--------------------------------------------------------------*/
174.1039 + /* solve the problem */
174.1040 + start = xtime();
174.1041 + if (csa->solution == SOL_BASIC)
174.1042 + { if (!csa->exact)
174.1043 + { glp_set_bfcp(csa->prob, &csa->bfcp);
174.1044 + glp_simplex(csa->prob, &csa->smcp);
174.1045 + if (csa->xcheck)
174.1046 + { if (csa->smcp.presolve &&
174.1047 + glp_get_status(csa->prob) != GLP_OPT)
174.1048 + xprintf("If you need to check final basis for non-opt"
174.1049 + "imal solution, use --nopresol\n");
174.1050 + else
174.1051 + glp_exact(csa->prob, &csa->smcp);
174.1052 + }
174.1053 + if (csa->out_sol != NULL || csa->out_res != NULL)
174.1054 + { if (csa->smcp.presolve &&
174.1055 + glp_get_status(csa->prob) != GLP_OPT)
174.1056 + xprintf("If you need actual output for non-optimal solut"
174.1057 + "ion, use --nopresol\n");
174.1058 + }
174.1059 + }
174.1060 + else
174.1061 + glp_exact(csa->prob, &csa->smcp);
174.1062 + }
174.1063 + else if (csa->solution == SOL_INTERIOR)
174.1064 + glp_interior(csa->prob, &csa->iptcp);
174.1065 + else if (csa->solution == SOL_INTEGER)
174.1066 + { if (!csa->iocp.presolve)
174.1067 + { glp_set_bfcp(csa->prob, &csa->bfcp);
174.1068 + glp_simplex(csa->prob, &csa->smcp);
174.1069 + }
174.1070 +#if 0
174.1071 + csa->iocp.msg_lev = GLP_MSG_DBG;
174.1072 + csa->iocp.pp_tech = GLP_PP_NONE;
174.1073 +#endif
174.1074 + glp_intopt(csa->prob, &csa->iocp);
174.1075 + }
174.1076 + else
174.1077 + xassert(csa != csa);
174.1078 + /*--------------------------------------------------------------*/
174.1079 + /* display statistics */
174.1080 + xprintf("Time used: %.1f secs\n", xdifftime(xtime(), start));
174.1081 + { glp_long tpeak;
174.1082 + char buf[50];
174.1083 + glp_mem_usage(NULL, NULL, NULL, &tpeak);
174.1084 + xprintf("Memory used: %.1f Mb (%s bytes)\n",
174.1085 + xltod(tpeak) / 1048576.0, xltoa(tpeak, buf));
174.1086 + }
174.1087 + /*--------------------------------------------------------------*/
174.1088 +skip: /* postsolve the model, if necessary */
174.1089 + if (csa->tran != NULL)
174.1090 + { if (csa->solution == SOL_BASIC)
174.1091 + ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_SOL);
174.1092 + else if (csa->solution == SOL_INTERIOR)
174.1093 + ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_IPT);
174.1094 + else if (csa->solution == SOL_INTEGER)
174.1095 + ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_MIP);
174.1096 + else
174.1097 + xassert(csa != csa);
174.1098 + if (ret != 0)
174.1099 + { xprintf("Model postsolving error\n");
174.1100 + ret = EXIT_FAILURE;
174.1101 + goto done;
174.1102 + }
174.1103 + }
174.1104 + /*--------------------------------------------------------------*/
174.1105 + /* write problem solution in printable format, if required */
174.1106 + if (csa->out_sol != NULL)
174.1107 + { if (csa->solution == SOL_BASIC)
174.1108 + ret = lpx_print_sol(csa->prob, csa->out_sol);
174.1109 + else if (csa->solution == SOL_INTERIOR)
174.1110 + ret = lpx_print_ips(csa->prob, csa->out_sol);
174.1111 + else if (csa->solution == SOL_INTEGER)
174.1112 + ret = lpx_print_mip(csa->prob, csa->out_sol);
174.1113 + else
174.1114 + xassert(csa != csa);
174.1115 + if (ret != 0)
174.1116 + { xprintf("Unable to write problem solution\n");
174.1117 + ret = EXIT_FAILURE;
174.1118 + goto done;
174.1119 + }
174.1120 + }
174.1121 + /* write problem solution in printable format, if required */
174.1122 + if (csa->out_res != NULL)
174.1123 + { if (csa->solution == SOL_BASIC)
174.1124 + ret = glp_write_sol(csa->prob, csa->out_res);
174.1125 + else if (csa->solution == SOL_INTERIOR)
174.1126 + ret = glp_write_ipt(csa->prob, csa->out_res);
174.1127 + else if (csa->solution == SOL_INTEGER)
174.1128 + ret = glp_write_mip(csa->prob, csa->out_res);
174.1129 + else
174.1130 + xassert(csa != csa);
174.1131 + if (ret != 0)
174.1132 + { xprintf("Unable to write problem solution\n");
174.1133 + ret = EXIT_FAILURE;
174.1134 + goto done;
174.1135 + }
174.1136 + }
174.1137 + /* write sensitivity analysis report, if required */
174.1138 + if (csa->out_ranges != NULL)
174.1139 + { if (csa->solution == SOL_BASIC)
174.1140 + { if (glp_get_status(csa->prob) == GLP_OPT)
174.1141 + { if (glp_bf_exists(csa->prob))
174.1142 +ranges: { ret = glp_print_ranges(csa->prob, 0, NULL, 0,
174.1143 + csa->out_ranges);
174.1144 + if (ret != 0)
174.1145 + { xprintf("Unable to write sensitivity analysis repo"
174.1146 + "rt\n");
174.1147 + ret = EXIT_FAILURE;
174.1148 + goto done;
174.1149 + }
174.1150 + }
174.1151 + else
174.1152 + { ret = glp_factorize(csa->prob);
174.1153 + if (ret == 0) goto ranges;
174.1154 + xprintf("Cannot produce sensitivity analysis report d"
174.1155 + "ue to error in basis factorization (glp_factorize"
174.1156 + " returned %d); try --nopresol\n", ret);
174.1157 + }
174.1158 + }
174.1159 + else
174.1160 + xprintf("Cannot produce sensitivity analysis report for "
174.1161 + "non-optimal basic solution\n");
174.1162 + }
174.1163 + else
174.1164 + xprintf("Cannot produce sensitivity analysis report for int"
174.1165 + "erior-point or MIP solution\n");
174.1166 + }
174.1167 + /*--------------------------------------------------------------*/
174.1168 + /* all seems to be ok */
174.1169 + ret = EXIT_SUCCESS;
174.1170 + /*--------------------------------------------------------------*/
174.1171 +done: /* delete the LP/MIP problem object */
174.1172 + if (csa->prob != NULL)
174.1173 + glp_delete_prob(csa->prob);
174.1174 + /* free the translator workspace, if necessary */
174.1175 + if (csa->tran != NULL)
174.1176 + glp_mpl_free_wksp(csa->tran);
174.1177 + /* delete the network problem object, if necessary */
174.1178 + if (csa->graph != NULL)
174.1179 + glp_delete_graph(csa->graph);
174.1180 + xassert(gmp_pool_count() == 0);
174.1181 + gmp_free_mem();
174.1182 + /* close log file, if necessary */
174.1183 + if (csa->log_file != NULL) glp_close_tee();
174.1184 + /* check that no memory blocks are still allocated */
174.1185 + { int count;
174.1186 + glp_long total;
174.1187 + glp_mem_usage(&count, NULL, &total, NULL);
174.1188 + if (count != 0)
174.1189 + xerror("Error: %d memory block(s) were lost\n", count);
174.1190 + xassert(count == 0);
174.1191 + xassert(total.lo == 0 && total.hi == 0);
174.1192 + }
174.1193 + /* free the GLPK environment */
174.1194 + glp_free_env();
174.1195 + /* return to the control program */
174.1196 + return ret;
174.1197 +}
174.1198 +
174.1199 +/* eof */
175.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
175.2 +++ b/src/glpavl.c Mon Dec 06 13:09:21 2010 +0100
175.3 @@ -0,0 +1,357 @@
175.4 +/* glpavl.c (binary search tree) */
175.5 +
175.6 +/***********************************************************************
175.7 +* This code is part of GLPK (GNU Linear Programming Kit).
175.8 +*
175.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
175.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
175.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
175.12 +* E-mail: <mao@gnu.org>.
175.13 +*
175.14 +* GLPK is free software: you can redistribute it and/or modify it
175.15 +* under the terms of the GNU General Public License as published by
175.16 +* the Free Software Foundation, either version 3 of the License, or
175.17 +* (at your option) any later version.
175.18 +*
175.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
175.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
175.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
175.22 +* License for more details.
175.23 +*
175.24 +* You should have received a copy of the GNU General Public License
175.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
175.26 +***********************************************************************/
175.27 +
175.28 +#include "glpavl.h"
175.29 +
175.30 +AVL *avl_create_tree(int (*fcmp)(void *info, const void *key1,
175.31 + const void *key2), void *info)
175.32 +{ /* create AVL tree */
175.33 + AVL *tree;
175.34 + tree = xmalloc(sizeof(AVL));
175.35 + tree->pool = dmp_create_pool();
175.36 + tree->root = NULL;
175.37 + tree->fcmp = fcmp;
175.38 + tree->info = info;
175.39 + tree->size = 0;
175.40 + tree->height = 0;
175.41 + return tree;
175.42 +}
175.43 +
175.44 +int avl_strcmp(void *info, const void *key1, const void *key2)
175.45 +{ /* compare character string keys */
175.46 + xassert(info == info);
175.47 + return strcmp(key1, key2);
175.48 +}
175.49 +
175.50 +static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node);
175.51 +
175.52 +AVLNODE *avl_insert_node(AVL *tree, const void *key)
175.53 +{ /* insert new node into AVL tree */
175.54 + AVLNODE *p, *q, *r;
175.55 + short int flag;
175.56 + /* find an appropriate point for insertion */
175.57 + p = NULL; q = tree->root;
175.58 + while (q != NULL)
175.59 + { p = q;
175.60 + if (tree->fcmp(tree->info, key, p->key) <= 0)
175.61 + { flag = 0;
175.62 + q = p->left;
175.63 + p->rank++;
175.64 + }
175.65 + else
175.66 + { flag = 1;
175.67 + q = p->right;
175.68 + }
175.69 + }
175.70 + /* create new node and insert it into the tree */
175.71 + r = dmp_get_atom(tree->pool, sizeof(AVLNODE));
175.72 + r->key = key; r->type = 0; r->link = NULL;
175.73 + r->rank = 1; r->up = p;
175.74 + r->flag = (short int)(p == NULL ? 0 : flag);
175.75 + r->bal = 0; r->left = NULL; r->right = NULL;
175.76 + tree->size++;
175.77 + if (p == NULL)
175.78 + tree->root = r;
175.79 + else
175.80 + if (flag == 0) p->left = r; else p->right = r;
175.81 + /* go upstairs to the root and correct all subtrees affected by
175.82 + insertion */
175.83 + while (p != NULL)
175.84 + { if (flag == 0)
175.85 + { /* the height of the left subtree of [p] is increased */
175.86 + if (p->bal > 0)
175.87 + { p->bal = 0;
175.88 + break;
175.89 + }
175.90 + if (p->bal < 0)
175.91 + { rotate_subtree(tree, p);
175.92 + break;
175.93 + }
175.94 + p->bal = -1; flag = p->flag; p = p->up;
175.95 + }
175.96 + else
175.97 + { /* the height of the right subtree of [p] is increased */
175.98 + if (p->bal < 0)
175.99 + { p->bal = 0;
175.100 + break;
175.101 + }
175.102 + if (p->bal > 0)
175.103 + { rotate_subtree(tree, p);
175.104 + break;
175.105 + }
175.106 + p->bal = +1; flag = p->flag; p = p->up;
175.107 + }
175.108 + }
175.109 + /* if the root has been reached, the height of the entire tree is
175.110 + increased */
175.111 + if (p == NULL) tree->height++;
175.112 + return r;
175.113 +}
175.114 +
175.115 +void avl_set_node_type(AVLNODE *node, int type)
175.116 +{ /* assign the type field of specified node */
175.117 + node->type = type;
175.118 + return;
175.119 +}
175.120 +
175.121 +void avl_set_node_link(AVLNODE *node, void *link)
175.122 +{ /* assign the link field of specified node */
175.123 + node->link = link;
175.124 + return;
175.125 +}
175.126 +
175.127 +AVLNODE *avl_find_node(AVL *tree, const void *key)
175.128 +{ /* find node in AVL tree */
175.129 + AVLNODE *p;
175.130 + int c;
175.131 + p = tree->root;
175.132 + while (p != NULL)
175.133 + { c = tree->fcmp(tree->info, key, p->key);
175.134 + if (c == 0) break;
175.135 + p = (c < 0 ? p->left : p->right);
175.136 + }
175.137 + return p;
175.138 +}
175.139 +
175.140 +int avl_get_node_type(AVLNODE *node)
175.141 +{ /* retrieve the type field of specified node */
175.142 + return node->type;
175.143 +}
175.144 +
175.145 +void *avl_get_node_link(AVLNODE *node)
175.146 +{ /* retrieve the link field of specified node */
175.147 + return node->link;
175.148 +}
175.149 +
175.150 +static AVLNODE *find_next_node(AVL *tree, AVLNODE *node)
175.151 +{ /* find next node in AVL tree */
175.152 + AVLNODE *p, *q;
175.153 + if (tree->root == NULL) return NULL;
175.154 + p = node;
175.155 + q = (p == NULL ? tree->root : p->right);
175.156 + if (q == NULL)
175.157 + { /* go upstairs from the left subtree */
175.158 + for (;;)
175.159 + { q = p->up;
175.160 + if (q == NULL) break;
175.161 + if (p->flag == 0) break;
175.162 + p = q;
175.163 + }
175.164 + }
175.165 + else
175.166 + { /* go downstairs into the right subtree */
175.167 + for (;;)
175.168 + { p = q->left;
175.169 + if (p == NULL) break;
175.170 + q = p;
175.171 + }
175.172 + }
175.173 + return q;
175.174 +}
175.175 +
175.176 +void avl_delete_node(AVL *tree, AVLNODE *node)
175.177 +{ /* delete specified node from AVL tree */
175.178 + AVLNODE *f, *p, *q, *r, *s, *x, *y;
175.179 + short int flag;
175.180 + p = node;
175.181 + /* if both subtrees of the specified node are non-empty, the node
175.182 + should be interchanged with the next one, at least one subtree
175.183 + of which is always empty */
175.184 + if (p->left == NULL || p->right == NULL) goto skip;
175.185 + f = p->up; q = p->left;
175.186 + r = find_next_node(tree, p); s = r->right;
175.187 + if (p->right == r)
175.188 + { if (f == NULL)
175.189 + tree->root = r;
175.190 + else
175.191 + if (p->flag == 0) f->left = r; else f->right = r;
175.192 + r->rank = p->rank; r->up = f;
175.193 + r->flag = p->flag; r->bal = p->bal;
175.194 + r->left = q; r->right = p;
175.195 + q->up = r;
175.196 + p->rank = 1; p->up = r; p->flag = 1;
175.197 + p->bal = (short int)(s == NULL ? 0 : +1);
175.198 + p->left = NULL; p->right = s;
175.199 + if (s != NULL) s->up = p;
175.200 + }
175.201 + else
175.202 + { x = p->right; y = r->up;
175.203 + if (f == NULL)
175.204 + tree->root = r;
175.205 + else
175.206 + if (p->flag == 0) f->left = r; else f->right = r;
175.207 + r->rank = p->rank; r->up = f;
175.208 + r->flag = p->flag; r->bal = p->bal;
175.209 + r->left = q; r->right = x;
175.210 + q->up = r; x->up = r; y->left = p;
175.211 + p->rank = 1; p->up = y; p->flag = 0;
175.212 + p->bal = (short int)(s == NULL ? 0 : +1);
175.213 + p->left = NULL; p->right = s;
175.214 + if (s != NULL) s->up = p;
175.215 + }
175.216 +skip: /* now the specified node [p] has at least one empty subtree;
175.217 + go upstairs to the root and adjust the rank field of all nodes
175.218 + affected by deletion */
175.219 + q = p; f = q->up;
175.220 + while (f != NULL)
175.221 + { if (q->flag == 0) f->rank--;
175.222 + q = f; f = q->up;
175.223 + }
175.224 + /* delete the specified node from the tree */
175.225 + f = p->up; flag = p->flag;
175.226 + q = p->left != NULL ? p->left : p->right;
175.227 + if (f == NULL)
175.228 + tree->root = q;
175.229 + else
175.230 + if (flag == 0) f->left = q; else f->right = q;
175.231 + if (q != NULL) q->up = f, q->flag = flag;
175.232 + tree->size--;
175.233 + /* go upstairs to the root and correct all subtrees affected by
175.234 + deletion */
175.235 + while (f != NULL)
175.236 + { if (flag == 0)
175.237 + { /* the height of the left subtree of [f] is decreased */
175.238 + if (f->bal == 0)
175.239 + { f->bal = +1;
175.240 + break;
175.241 + }
175.242 + if (f->bal < 0)
175.243 + f->bal = 0;
175.244 + else
175.245 + { f = rotate_subtree(tree, f);
175.246 + if (f->bal < 0) break;
175.247 + }
175.248 + flag = f->flag; f = f->up;
175.249 + }
175.250 + else
175.251 + { /* the height of the right subtree of [f] is decreased */
175.252 + if (f->bal == 0)
175.253 + { f->bal = -1;
175.254 + break;
175.255 + }
175.256 + if (f->bal > 0)
175.257 + f->bal = 0;
175.258 + else
175.259 + { f = rotate_subtree(tree, f);
175.260 + if (f->bal > 0) break;
175.261 + }
175.262 + flag = f->flag; f = f->up;
175.263 + }
175.264 + }
175.265 + /* if the root has been reached, the height of the entire tree is
175.266 + decreased */
175.267 + if (f == NULL) tree->height--;
175.268 + /* returns the deleted node to the memory pool */
175.269 + dmp_free_atom(tree->pool, p, sizeof(AVLNODE));
175.270 + return;
175.271 +}
175.272 +
175.273 +static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node)
175.274 +{ /* restore balance of AVL subtree */
175.275 + AVLNODE *f, *p, *q, *r, *x, *y;
175.276 + xassert(node != NULL);
175.277 + p = node;
175.278 + if (p->bal < 0)
175.279 + { /* perform negative (left) rotation */
175.280 + f = p->up; q = p->left; r = q->right;
175.281 + if (q->bal <= 0)
175.282 + { /* perform single negative rotation */
175.283 + if (f == NULL)
175.284 + tree->root = q;
175.285 + else
175.286 + if (p->flag == 0) f->left = q; else f->right = q;
175.287 + p->rank -= q->rank;
175.288 + q->up = f; q->flag = p->flag; q->bal++; q->right = p;
175.289 + p->up = q; p->flag = 1;
175.290 + p->bal = (short int)(-q->bal); p->left = r;
175.291 + if (r != NULL) r->up = p, r->flag = 0;
175.292 + node = q;
175.293 + }
175.294 + else
175.295 + { /* perform double negative rotation */
175.296 + x = r->left; y = r->right;
175.297 + if (f == NULL)
175.298 + tree->root = r;
175.299 + else
175.300 + if (p->flag == 0) f->left = r; else f->right = r;
175.301 + p->rank -= (q->rank + r->rank);
175.302 + r->rank += q->rank;
175.303 + p->bal = (short int)(r->bal >= 0 ? 0 : +1);
175.304 + q->bal = (short int)(r->bal <= 0 ? 0 : -1);
175.305 + r->up = f; r->flag = p->flag; r->bal = 0;
175.306 + r->left = q; r->right = p;
175.307 + p->up = r; p->flag = 1; p->left = y;
175.308 + q->up = r; q->flag = 0; q->right = x;
175.309 + if (x != NULL) x->up = q, x->flag = 1;
175.310 + if (y != NULL) y->up = p, y->flag = 0;
175.311 + node = r;
175.312 + }
175.313 + }
175.314 + else
175.315 + { /* perform positive (right) rotation */
175.316 + f = p->up; q = p->right; r = q->left;
175.317 + if (q->bal >= 0)
175.318 + { /* perform single positive rotation */
175.319 + if (f == NULL)
175.320 + tree->root = q;
175.321 + else
175.322 + if (p->flag == 0) f->left = q; else f->right = q;
175.323 + q->rank += p->rank;
175.324 + q->up = f; q->flag = p->flag; q->bal--; q->left = p;
175.325 + p->up = q; p->flag = 0;
175.326 + p->bal = (short int)(-q->bal); p->right = r;
175.327 + if (r != NULL) r->up = p, r->flag = 1;
175.328 + node = q;
175.329 + }
175.330 + else
175.331 + { /* perform double positive rotation */
175.332 + x = r->left; y = r->right;
175.333 + if (f == NULL)
175.334 + tree->root = r;
175.335 + else
175.336 + if (p->flag == 0) f->left = r; else f->right = r;
175.337 + q->rank -= r->rank;
175.338 + r->rank += p->rank;
175.339 + p->bal = (short int)(r->bal <= 0 ? 0 : -1);
175.340 + q->bal = (short int)(r->bal >= 0 ? 0 : +1);
175.341 + r->up = f; r->flag = p->flag; r->bal = 0;
175.342 + r->left = p; r->right = q;
175.343 + p->up = r; p->flag = 0; p->right = x;
175.344 + q->up = r; q->flag = 1; q->left = y;
175.345 + if (x != NULL) x->up = p, x->flag = 1;
175.346 + if (y != NULL) y->up = q, y->flag = 0;
175.347 + node = r;
175.348 + }
175.349 + }
175.350 + return node;
175.351 +}
175.352 +
175.353 +void avl_delete_tree(AVL *tree)
175.354 +{ /* delete AVL tree */
175.355 + dmp_delete_pool(tree->pool);
175.356 + xfree(tree);
175.357 + return;
175.358 +}
175.359 +
175.360 +/* eof */
176.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
176.2 +++ b/src/glpavl.h Mon Dec 06 13:09:21 2010 +0100
176.3 @@ -0,0 +1,123 @@
176.4 +/* glpavl.h (binary search tree) */
176.5 +
176.6 +/***********************************************************************
176.7 +* This code is part of GLPK (GNU Linear Programming Kit).
176.8 +*
176.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
176.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
176.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
176.12 +* E-mail: <mao@gnu.org>.
176.13 +*
176.14 +* GLPK is free software: you can redistribute it and/or modify it
176.15 +* under the terms of the GNU General Public License as published by
176.16 +* the Free Software Foundation, either version 3 of the License, or
176.17 +* (at your option) any later version.
176.18 +*
176.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
176.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
176.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
176.22 +* License for more details.
176.23 +*
176.24 +* You should have received a copy of the GNU General Public License
176.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
176.26 +***********************************************************************/
176.27 +
176.28 +#ifndef GLPAVL_H
176.29 +#define GLPAVL_H
176.30 +
176.31 +#include "glpdmp.h"
176.32 +
176.33 +typedef struct AVL AVL;
176.34 +typedef struct AVLNODE AVLNODE;
176.35 +
176.36 +struct AVL
176.37 +{ /* AVL tree (Adelson-Velsky & Landis binary search tree) */
176.38 + DMP *pool;
176.39 + /* memory pool for allocating nodes */
176.40 + AVLNODE *root;
176.41 + /* pointer to the root node */
176.42 + int (*fcmp)(void *info, const void *key1, const void *key2);
176.43 + /* application-defined key comparison routine */
176.44 + void *info;
176.45 + /* transit pointer passed to the routine fcmp */
176.46 + int size;
176.47 + /* the tree size (the total number of nodes) */
176.48 + int height;
176.49 + /* the tree height */
176.50 +};
176.51 +
176.52 +struct AVLNODE
176.53 +{ /* node of AVL tree */
176.54 + const void *key;
176.55 + /* pointer to the node key (data structure for representing keys
176.56 + is supplied by the application) */
176.57 + int rank;
176.58 + /* node rank = relative position of the node in its own subtree =
176.59 + the number of nodes in the left subtree plus one */
176.60 + int type;
176.61 + /* reserved for the application specific information */
176.62 + void *link;
176.63 + /* reserved for the application specific information */
176.64 + AVLNODE *up;
176.65 + /* pointer to the parent node */
176.66 + short int flag;
176.67 + /* node flag:
176.68 + 0 - this node is the left child of its parent (or this node is
176.69 + the root of the tree and has no parent)
176.70 + 1 - this node is the right child of its parent */
176.71 + short int bal;
176.72 + /* node balance = the difference between heights of the right and
176.73 + left subtrees:
176.74 + -1 - the left subtree is higher than the right one;
176.75 + 0 - the left and right subtrees have the same height;
176.76 + +1 - the left subtree is lower than the right one */
176.77 + AVLNODE *left;
176.78 + /* pointer to the root of the left subtree */
176.79 + AVLNODE *right;
176.80 + /* pointer to the root of the right subtree */
176.81 +};
176.82 +
176.83 +#define avl_create_tree _glp_avl_create_tree
176.84 +AVL *avl_create_tree(int (*fcmp)(void *info, const void *key1,
176.85 + const void *key2), void *info);
176.86 +/* create AVL tree */
176.87 +
176.88 +#define avl_strcmp _glp_avl_strcmp
176.89 +int avl_strcmp(void *info, const void *key1, const void *key2);
176.90 +/* compare character string keys */
176.91 +
176.92 +#define avl_insert_node _glp_avl_insert_node
176.93 +AVLNODE *avl_insert_node(AVL *tree, const void *key);
176.94 +/* insert new node into AVL tree */
176.95 +
176.96 +#define avl_set_node_type _glp_avl_set_node_type
176.97 +void avl_set_node_type(AVLNODE *node, int type);
176.98 +/* assign the type field of specified node */
176.99 +
176.100 +#define avl_set_node_link _glp_avl_set_node_link
176.101 +void avl_set_node_link(AVLNODE *node, void *link);
176.102 +/* assign the link field of specified node */
176.103 +
176.104 +#define avl_find_node _glp_avl_find_node
176.105 +AVLNODE *avl_find_node(AVL *tree, const void *key);
176.106 +/* find node in AVL tree */
176.107 +
176.108 +#define avl_get_node_type _glp_avl_get_node_type
176.109 +int avl_get_node_type(AVLNODE *node);
176.110 +/* retrieve the type field of specified node */
176.111 +
176.112 +#define avl_get_node_link _glp_avl_get_node_link
176.113 +void *avl_get_node_link(AVLNODE *node);
176.114 +/* retrieve the link field of specified node */
176.115 +
176.116 +#define avl_delete_node _glp_avl_delete_node
176.117 +void avl_delete_node(AVL *tree, AVLNODE *node);
176.118 +/* delete specified node from AVL tree */
176.119 +
176.120 +#define avl_delete_tree _glp_avl_delete_tree
176.121 +void avl_delete_tree(AVL *tree);
176.122 +/* delete AVL tree */
176.123 +
176.124 +#endif
176.125 +
176.126 +/* eof */
177.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
177.2 +++ b/src/glpbfd.c Mon Dec 06 13:09:21 2010 +0100
177.3 @@ -0,0 +1,481 @@
177.4 +/* glpbfd.c (LP basis factorization driver) */
177.5 +
177.6 +/***********************************************************************
177.7 +* This code is part of GLPK (GNU Linear Programming Kit).
177.8 +*
177.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
177.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
177.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
177.12 +* E-mail: <mao@gnu.org>.
177.13 +*
177.14 +* GLPK is free software: you can redistribute it and/or modify it
177.15 +* under the terms of the GNU General Public License as published by
177.16 +* the Free Software Foundation, either version 3 of the License, or
177.17 +* (at your option) any later version.
177.18 +*
177.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
177.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
177.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
177.22 +* License for more details.
177.23 +*
177.24 +* You should have received a copy of the GNU General Public License
177.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
177.26 +***********************************************************************/
177.27 +
177.28 +typedef struct BFD BFD;
177.29 +
177.30 +#define GLPBFD_PRIVATE
177.31 +#include "glpapi.h"
177.32 +#include "glpfhv.h"
177.33 +#include "glplpf.h"
177.34 +
177.35 +/* CAUTION: DO NOT CHANGE THE LIMIT BELOW */
177.36 +
177.37 +#define M_MAX 100000000 /* = 100*10^6 */
177.38 +/* maximal order of the basis matrix */
177.39 +
177.40 +struct BFD
177.41 +{ /* LP basis factorization */
177.42 + int valid;
177.43 + /* factorization is valid only if this flag is set */
177.44 + int type;
177.45 + /* factorization type:
177.46 + GLP_BF_FT - LUF + Forrest-Tomlin
177.47 + GLP_BF_BG - LUF + Schur compl. + Bartels-Golub
177.48 + GLP_BF_GR - LUF + Schur compl. + Givens rotation */
177.49 + FHV *fhv;
177.50 + /* LP basis factorization (GLP_BF_FT) */
177.51 + LPF *lpf;
177.52 + /* LP basis factorization (GLP_BF_BG, GLP_BF_GR) */
177.53 + int lu_size; /* luf.sv_size */
177.54 + double piv_tol; /* luf.piv_tol */
177.55 + int piv_lim; /* luf.piv_lim */
177.56 + int suhl; /* luf.suhl */
177.57 + double eps_tol; /* luf.eps_tol */
177.58 + double max_gro; /* luf.max_gro */
177.59 + int nfs_max; /* fhv.hh_max */
177.60 + double upd_tol; /* fhv.upd_tol */
177.61 + int nrs_max; /* lpf.n_max */
177.62 + int rs_size; /* lpf.v_size */
177.63 + /* internal control parameters */
177.64 + int upd_lim;
177.65 + /* the factorization update limit */
177.66 + int upd_cnt;
177.67 + /* the factorization update count */
177.68 +};
177.69 +
177.70 +/***********************************************************************
177.71 +* NAME
177.72 +*
177.73 +* bfd_create_it - create LP basis factorization
177.74 +*
177.75 +* SYNOPSIS
177.76 +*
177.77 +* #include "glpbfd.h"
177.78 +* BFD *bfd_create_it(void);
177.79 +*
177.80 +* DESCRIPTION
177.81 +*
177.82 +* The routine bfd_create_it creates a program object, which represents
177.83 +* a factorization of LP basis.
177.84 +*
177.85 +* RETURNS
177.86 +*
177.87 +* The routine bfd_create_it returns a pointer to the object created. */
177.88 +
177.89 +BFD *bfd_create_it(void)
177.90 +{ BFD *bfd;
177.91 + bfd = xmalloc(sizeof(BFD));
177.92 + bfd->valid = 0;
177.93 + bfd->type = GLP_BF_FT;
177.94 + bfd->fhv = NULL;
177.95 + bfd->lpf = NULL;
177.96 + bfd->lu_size = 0;
177.97 + bfd->piv_tol = 0.10;
177.98 + bfd->piv_lim = 4;
177.99 + bfd->suhl = 1;
177.100 + bfd->eps_tol = 1e-15;
177.101 + bfd->max_gro = 1e+10;
177.102 + bfd->nfs_max = 100;
177.103 + bfd->upd_tol = 1e-6;
177.104 + bfd->nrs_max = 100;
177.105 + bfd->rs_size = 1000;
177.106 + bfd->upd_lim = -1;
177.107 + bfd->upd_cnt = 0;
177.108 + return bfd;
177.109 +}
177.110 +
177.111 +/**********************************************************************/
177.112 +
177.113 +void bfd_set_parm(BFD *bfd, const void *_parm)
177.114 +{ /* change LP basis factorization control parameters */
177.115 + const glp_bfcp *parm = _parm;
177.116 + xassert(bfd != NULL);
177.117 + bfd->type = parm->type;
177.118 + bfd->lu_size = parm->lu_size;
177.119 + bfd->piv_tol = parm->piv_tol;
177.120 + bfd->piv_lim = parm->piv_lim;
177.121 + bfd->suhl = parm->suhl;
177.122 + bfd->eps_tol = parm->eps_tol;
177.123 + bfd->max_gro = parm->max_gro;
177.124 + bfd->nfs_max = parm->nfs_max;
177.125 + bfd->upd_tol = parm->upd_tol;
177.126 + bfd->nrs_max = parm->nrs_max;
177.127 + bfd->rs_size = parm->rs_size;
177.128 + return;
177.129 +}
177.130 +
177.131 +/***********************************************************************
177.132 +* NAME
177.133 +*
177.134 +* bfd_factorize - compute LP basis factorization
177.135 +*
177.136 +* SYNOPSIS
177.137 +*
177.138 +* #include "glpbfd.h"
177.139 +* int bfd_factorize(BFD *bfd, int m, int bh[], int (*col)(void *info,
177.140 +* int j, int ind[], double val[]), void *info);
177.141 +*
177.142 +* DESCRIPTION
177.143 +*
177.144 +* The routine bfd_factorize computes the factorization of the basis
177.145 +* matrix B specified by the routine col.
177.146 +*
177.147 +* The parameter bfd specified the basis factorization data structure
177.148 +* created with the routine bfd_create_it.
177.149 +*
177.150 +* The parameter m specifies the order of B, m > 0.
177.151 +*
177.152 +* The array bh specifies the basis header: bh[j], 1 <= j <= m, is the
177.153 +* number of j-th column of B in some original matrix. The array bh is
177.154 +* optional and can be specified as NULL.
177.155 +*
177.156 +* The formal routine col specifies the matrix B to be factorized. To
177.157 +* obtain j-th column of A the routine bfd_factorize calls the routine
177.158 +* col with the parameter j (1 <= j <= n). In response the routine col
177.159 +* should store row indices and numerical values of non-zero elements
177.160 +* of j-th column of B to locations ind[1,...,len] and val[1,...,len],
177.161 +* respectively, where len is the number of non-zeros in j-th column
177.162 +* returned on exit. Neither zero nor duplicate elements are allowed.
177.163 +*
177.164 +* The parameter info is a transit pointer passed to the routine col.
177.165 +*
177.166 +* RETURNS
177.167 +*
177.168 +* 0 The factorization has been successfully computed.
177.169 +*
177.170 +* BFD_ESING
177.171 +* The specified matrix is singular within the working precision.
177.172 +*
177.173 +* BFD_ECOND
177.174 +* The specified matrix is ill-conditioned.
177.175 +*
177.176 +* For more details see comments to the routine luf_factorize. */
177.177 +
177.178 +int bfd_factorize(BFD *bfd, int m, const int bh[], int (*col)
177.179 + (void *info, int j, int ind[], double val[]), void *info)
177.180 +{ LUF *luf;
177.181 + int nov, ret;
177.182 + xassert(bfd != NULL);
177.183 + xassert(1 <= m && m <= M_MAX);
177.184 + /* invalidate the factorization */
177.185 + bfd->valid = 0;
177.186 + /* create the factorization, if necessary */
177.187 + nov = 0;
177.188 + switch (bfd->type)
177.189 + { case GLP_BF_FT:
177.190 + if (bfd->lpf != NULL)
177.191 + lpf_delete_it(bfd->lpf), bfd->lpf = NULL;
177.192 + if (bfd->fhv == NULL)
177.193 + bfd->fhv = fhv_create_it(), nov = 1;
177.194 + break;
177.195 + case GLP_BF_BG:
177.196 + case GLP_BF_GR:
177.197 + if (bfd->fhv != NULL)
177.198 + fhv_delete_it(bfd->fhv), bfd->fhv = NULL;
177.199 + if (bfd->lpf == NULL)
177.200 + bfd->lpf = lpf_create_it(), nov = 1;
177.201 + break;
177.202 + default:
177.203 + xassert(bfd != bfd);
177.204 + }
177.205 + /* set control parameters specific to LUF */
177.206 + if (bfd->fhv != NULL)
177.207 + luf = bfd->fhv->luf;
177.208 + else if (bfd->lpf != NULL)
177.209 + luf = bfd->lpf->luf;
177.210 + else
177.211 + xassert(bfd != bfd);
177.212 + if (nov) luf->new_sva = bfd->lu_size;
177.213 + luf->piv_tol = bfd->piv_tol;
177.214 + luf->piv_lim = bfd->piv_lim;
177.215 + luf->suhl = bfd->suhl;
177.216 + luf->eps_tol = bfd->eps_tol;
177.217 + luf->max_gro = bfd->max_gro;
177.218 + /* set control parameters specific to FHV */
177.219 + if (bfd->fhv != NULL)
177.220 + { if (nov) bfd->fhv->hh_max = bfd->nfs_max;
177.221 + bfd->fhv->upd_tol = bfd->upd_tol;
177.222 + }
177.223 + /* set control parameters specific to LPF */
177.224 + if (bfd->lpf != NULL)
177.225 + { if (nov) bfd->lpf->n_max = bfd->nrs_max;
177.226 + if (nov) bfd->lpf->v_size = bfd->rs_size;
177.227 + }
177.228 + /* try to factorize the basis matrix */
177.229 + if (bfd->fhv != NULL)
177.230 + { switch (fhv_factorize(bfd->fhv, m, col, info))
177.231 + { case 0:
177.232 + break;
177.233 + case FHV_ESING:
177.234 + ret = BFD_ESING;
177.235 + goto done;
177.236 + case FHV_ECOND:
177.237 + ret = BFD_ECOND;
177.238 + goto done;
177.239 + default:
177.240 + xassert(bfd != bfd);
177.241 + }
177.242 + }
177.243 + else if (bfd->lpf != NULL)
177.244 + { switch (lpf_factorize(bfd->lpf, m, bh, col, info))
177.245 + { case 0:
177.246 + /* set the Schur complement update type */
177.247 + switch (bfd->type)
177.248 + { case GLP_BF_BG:
177.249 + /* Bartels-Golub update */
177.250 + bfd->lpf->scf->t_opt = SCF_TBG;
177.251 + break;
177.252 + case GLP_BF_GR:
177.253 + /* Givens rotation update */
177.254 + bfd->lpf->scf->t_opt = SCF_TGR;
177.255 + break;
177.256 + default:
177.257 + xassert(bfd != bfd);
177.258 + }
177.259 + break;
177.260 + case LPF_ESING:
177.261 + ret = BFD_ESING;
177.262 + goto done;
177.263 + case LPF_ECOND:
177.264 + ret = BFD_ECOND;
177.265 + goto done;
177.266 + default:
177.267 + xassert(bfd != bfd);
177.268 + }
177.269 + }
177.270 + else
177.271 + xassert(bfd != bfd);
177.272 + /* the basis matrix has been successfully factorized */
177.273 + bfd->valid = 1;
177.274 + bfd->upd_cnt = 0;
177.275 + ret = 0;
177.276 +done: /* return to the calling program */
177.277 + return ret;
177.278 +}
177.279 +
177.280 +/***********************************************************************
177.281 +* NAME
177.282 +*
177.283 +* bfd_ftran - perform forward transformation (solve system B*x = b)
177.284 +*
177.285 +* SYNOPSIS
177.286 +*
177.287 +* #include "glpbfd.h"
177.288 +* void bfd_ftran(BFD *bfd, double x[]);
177.289 +*
177.290 +* DESCRIPTION
177.291 +*
177.292 +* The routine bfd_ftran performs forward transformation, i.e. solves
177.293 +* the system B*x = b, where B is the basis matrix, x is the vector of
177.294 +* unknowns to be computed, b is the vector of right-hand sides.
177.295 +*
177.296 +* On entry elements of the vector b should be stored in dense format
177.297 +* in locations x[1], ..., x[m], where m is the number of rows. On exit
177.298 +* the routine stores elements of the vector x in the same locations. */
177.299 +
177.300 +void bfd_ftran(BFD *bfd, double x[])
177.301 +{ xassert(bfd != NULL);
177.302 + xassert(bfd->valid);
177.303 + if (bfd->fhv != NULL)
177.304 + fhv_ftran(bfd->fhv, x);
177.305 + else if (bfd->lpf != NULL)
177.306 + lpf_ftran(bfd->lpf, x);
177.307 + else
177.308 + xassert(bfd != bfd);
177.309 + return;
177.310 +}
177.311 +
177.312 +/***********************************************************************
177.313 +* NAME
177.314 +*
177.315 +* bfd_btran - perform backward transformation (solve system B'*x = b)
177.316 +*
177.317 +* SYNOPSIS
177.318 +*
177.319 +* #include "glpbfd.h"
177.320 +* void bfd_btran(BFD *bfd, double x[]);
177.321 +*
177.322 +* DESCRIPTION
177.323 +*
177.324 +* The routine bfd_btran performs backward transformation, i.e. solves
177.325 +* the system B'*x = b, where B' is a matrix transposed to the basis
177.326 +* matrix B, x is the vector of unknowns to be computed, b is the vector
177.327 +* of right-hand sides.
177.328 +*
177.329 +* On entry elements of the vector b should be stored in dense format
177.330 +* in locations x[1], ..., x[m], where m is the number of rows. On exit
177.331 +* the routine stores elements of the vector x in the same locations. */
177.332 +
177.333 +void bfd_btran(BFD *bfd, double x[])
177.334 +{ xassert(bfd != NULL);
177.335 + xassert(bfd->valid);
177.336 + if (bfd->fhv != NULL)
177.337 + fhv_btran(bfd->fhv, x);
177.338 + else if (bfd->lpf != NULL)
177.339 + lpf_btran(bfd->lpf, x);
177.340 + else
177.341 + xassert(bfd != bfd);
177.342 + return;
177.343 +}
177.344 +
177.345 +/***********************************************************************
177.346 +* NAME
177.347 +*
177.348 +* bfd_update_it - update LP basis factorization
177.349 +*
177.350 +* SYNOPSIS
177.351 +*
177.352 +* #include "glpbfd.h"
177.353 +* int bfd_update_it(BFD *bfd, int j, int bh, int len, const int ind[],
177.354 +* const double val[]);
177.355 +*
177.356 +* DESCRIPTION
177.357 +*
177.358 +* The routine bfd_update_it updates the factorization of the basis
177.359 +* matrix B after replacing its j-th column by a new vector.
177.360 +*
177.361 +* The parameter j specifies the number of column of B, which has been
177.362 +* replaced, 1 <= j <= m, where m is the order of B.
177.363 +*
177.364 +* The parameter bh specifies the basis header entry for the new column
177.365 +* of B, which is the number of the new column in some original matrix.
177.366 +* This parameter is optional and can be specified as 0.
177.367 +*
177.368 +* Row indices and numerical values of non-zero elements of the new
177.369 +* column of B should be placed in locations ind[1], ..., ind[len] and
177.370 +* val[1], ..., val[len], resp., where len is the number of non-zeros
177.371 +* in the column. Neither zero nor duplicate elements are allowed.
177.372 +*
177.373 +* RETURNS
177.374 +*
177.375 +* 0 The factorization has been successfully updated.
177.376 +*
177.377 +* BFD_ESING
177.378 +* New basis matrix is singular within the working precision.
177.379 +*
177.380 +* BFD_ECHECK
177.381 +* The factorization is inaccurate.
177.382 +*
177.383 +* BFD_ELIMIT
177.384 +* Factorization update limit has been reached.
177.385 +*
177.386 +* BFD_EROOM
177.387 +* Overflow of the sparse vector area.
177.388 +*
177.389 +* In case of non-zero return code the factorization becomes invalid.
177.390 +* It should not be used until it has been recomputed with the routine
177.391 +* bfd_factorize. */
177.392 +
177.393 +int bfd_update_it(BFD *bfd, int j, int bh, int len, const int ind[],
177.394 + const double val[])
177.395 +{ int ret;
177.396 + xassert(bfd != NULL);
177.397 + xassert(bfd->valid);
177.398 + /* try to update the factorization */
177.399 + if (bfd->fhv != NULL)
177.400 + { switch (fhv_update_it(bfd->fhv, j, len, ind, val))
177.401 + { case 0:
177.402 + break;
177.403 + case FHV_ESING:
177.404 + bfd->valid = 0;
177.405 + ret = BFD_ESING;
177.406 + goto done;
177.407 + case FHV_ECHECK:
177.408 + bfd->valid = 0;
177.409 + ret = BFD_ECHECK;
177.410 + goto done;
177.411 + case FHV_ELIMIT:
177.412 + bfd->valid = 0;
177.413 + ret = BFD_ELIMIT;
177.414 + goto done;
177.415 + case FHV_EROOM:
177.416 + bfd->valid = 0;
177.417 + ret = BFD_EROOM;
177.418 + goto done;
177.419 + default:
177.420 + xassert(bfd != bfd);
177.421 + }
177.422 + }
177.423 + else if (bfd->lpf != NULL)
177.424 + { switch (lpf_update_it(bfd->lpf, j, bh, len, ind, val))
177.425 + { case 0:
177.426 + break;
177.427 + case LPF_ESING:
177.428 + bfd->valid = 0;
177.429 + ret = BFD_ESING;
177.430 + goto done;
177.431 + case LPF_ELIMIT:
177.432 + bfd->valid = 0;
177.433 + ret = BFD_ELIMIT;
177.434 + goto done;
177.435 + default:
177.436 + xassert(bfd != bfd);
177.437 + }
177.438 + }
177.439 + else
177.440 + xassert(bfd != bfd);
177.441 + /* the factorization has been successfully updated */
177.442 + /* increase the update count */
177.443 + bfd->upd_cnt++;
177.444 + ret = 0;
177.445 +done: /* return to the calling program */
177.446 + return ret;
177.447 +}
177.448 +
177.449 +/**********************************************************************/
177.450 +
177.451 +int bfd_get_count(BFD *bfd)
177.452 +{ /* determine factorization update count */
177.453 + xassert(bfd != NULL);
177.454 + xassert(bfd->valid);
177.455 + return bfd->upd_cnt;
177.456 +}
177.457 +
177.458 +/***********************************************************************
177.459 +* NAME
177.460 +*
177.461 +* bfd_delete_it - delete LP basis factorization
177.462 +*
177.463 +* SYNOPSIS
177.464 +*
177.465 +* #include "glpbfd.h"
177.466 +* void bfd_delete_it(BFD *bfd);
177.467 +*
177.468 +* DESCRIPTION
177.469 +*
177.470 +* The routine bfd_delete_it deletes LP basis factorization specified
177.471 +* by the parameter fhv and frees all memory allocated to this program
177.472 +* object. */
177.473 +
177.474 +void bfd_delete_it(BFD *bfd)
177.475 +{ xassert(bfd != NULL);
177.476 + if (bfd->fhv != NULL)
177.477 + fhv_delete_it(bfd->fhv);
177.478 + if (bfd->lpf != NULL)
177.479 + lpf_delete_it(bfd->lpf);
177.480 + xfree(bfd);
177.481 + return;
177.482 +}
177.483 +
177.484 +/* eof */
178.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
178.2 +++ b/src/glpbfd.h Mon Dec 06 13:09:21 2010 +0100
178.3 @@ -0,0 +1,75 @@
178.4 +/* glpbfd.h (LP basis factorization driver) */
178.5 +
178.6 +/***********************************************************************
178.7 +* This code is part of GLPK (GNU Linear Programming Kit).
178.8 +*
178.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
178.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
178.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
178.12 +* E-mail: <mao@gnu.org>.
178.13 +*
178.14 +* GLPK is free software: you can redistribute it and/or modify it
178.15 +* under the terms of the GNU General Public License as published by
178.16 +* the Free Software Foundation, either version 3 of the License, or
178.17 +* (at your option) any later version.
178.18 +*
178.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
178.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
178.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
178.22 +* License for more details.
178.23 +*
178.24 +* You should have received a copy of the GNU General Public License
178.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
178.26 +***********************************************************************/
178.27 +
178.28 +#ifndef GLPBFD_H
178.29 +#define GLPBFD_H
178.30 +
178.31 +#ifndef GLPBFD_PRIVATE
178.32 +typedef struct { double _opaque_bfd[100]; } BFD;
178.33 +#endif
178.34 +
178.35 +/* return codes: */
178.36 +#define BFD_ESING 1 /* singular matrix */
178.37 +#define BFD_ECOND 2 /* ill-conditioned matrix */
178.38 +#define BFD_ECHECK 3 /* insufficient accuracy */
178.39 +#define BFD_ELIMIT 4 /* update limit reached */
178.40 +#define BFD_EROOM 5 /* SVA overflow */
178.41 +
178.42 +#define bfd_create_it _glp_bfd_create_it
178.43 +BFD *bfd_create_it(void);
178.44 +/* create LP basis factorization */
178.45 +
178.46 +#define bfd_set_parm _glp_bfd_set_parm
178.47 +void bfd_set_parm(BFD *bfd, const void *parm);
178.48 +/* change LP basis factorization control parameters */
178.49 +
178.50 +#define bfd_factorize _glp_bfd_factorize
178.51 +int bfd_factorize(BFD *bfd, int m, const int bh[], int (*col)
178.52 + (void *info, int j, int ind[], double val[]), void *info);
178.53 +/* compute LP basis factorization */
178.54 +
178.55 +#define bfd_ftran _glp_bfd_ftran
178.56 +void bfd_ftran(BFD *bfd, double x[]);
178.57 +/* perform forward transformation (solve system B*x = b) */
178.58 +
178.59 +#define bfd_btran _glp_bfd_btran
178.60 +void bfd_btran(BFD *bfd, double x[]);
178.61 +/* perform backward transformation (solve system B'*x = b) */
178.62 +
178.63 +#define bfd_update_it _glp_bfd_update_it
178.64 +int bfd_update_it(BFD *bfd, int j, int bh, int len, const int ind[],
178.65 + const double val[]);
178.66 +/* update LP basis factorization */
178.67 +
178.68 +#define bfd_get_count _glp_bfd_get_count
178.69 +int bfd_get_count(BFD *bfd);
178.70 +/* determine factorization update count */
178.71 +
178.72 +#define bfd_delete_it _glp_bfd_delete_it
178.73 +void bfd_delete_it(BFD *bfd);
178.74 +/* delete LP basis factorization */
178.75 +
178.76 +#endif
178.77 +
178.78 +/* eof */
179.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
179.2 +++ b/src/glpbfx.c Mon Dec 06 13:09:21 2010 +0100
179.3 @@ -0,0 +1,91 @@
179.4 +/* glpbfx.c */
179.5 +
179.6 +/***********************************************************************
179.7 +* This code is part of GLPK (GNU Linear Programming Kit).
179.8 +*
179.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
179.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
179.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
179.12 +* E-mail: <mao@gnu.org>.
179.13 +*
179.14 +* GLPK is free software: you can redistribute it and/or modify it
179.15 +* under the terms of the GNU General Public License as published by
179.16 +* the Free Software Foundation, either version 3 of the License, or
179.17 +* (at your option) any later version.
179.18 +*
179.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
179.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
179.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
179.22 +* License for more details.
179.23 +*
179.24 +* You should have received a copy of the GNU General Public License
179.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
179.26 +***********************************************************************/
179.27 +
179.28 +typedef struct BFX BFX;
179.29 +#define GLPBFX_DEFINED
179.30 +#include "glpbfx.h"
179.31 +#include "glpenv.h"
179.32 +#include "glplux.h"
179.33 +
179.34 +struct BFX
179.35 +{ int valid;
179.36 + LUX *lux;
179.37 +};
179.38 +
179.39 +BFX *bfx_create_binv(void)
179.40 +{ /* create factorization of the basis matrix */
179.41 + BFX *bfx;
179.42 + bfx = xmalloc(sizeof(BFX));
179.43 + bfx->valid = 0;
179.44 + bfx->lux = NULL;
179.45 + return bfx;
179.46 +}
179.47 +
179.48 +int bfx_factorize(BFX *binv, int m, int (*col)(void *info, int j,
179.49 + int ind[], mpq_t val[]), void *info)
179.50 +{ /* compute factorization of the basis matrix */
179.51 + int ret;
179.52 + xassert(m > 0);
179.53 + if (binv->lux != NULL && binv->lux->n != m)
179.54 + { lux_delete(binv->lux);
179.55 + binv->lux = NULL;
179.56 + }
179.57 + if (binv->lux == NULL)
179.58 + binv->lux = lux_create(m);
179.59 + ret = lux_decomp(binv->lux, col, info);
179.60 + binv->valid = (ret == 0);
179.61 + return ret;
179.62 +}
179.63 +
179.64 +void bfx_ftran(BFX *binv, mpq_t x[], int save)
179.65 +{ /* perform forward transformation (FTRAN) */
179.66 + xassert(binv->valid);
179.67 + lux_solve(binv->lux, 0, x);
179.68 + xassert(save == save);
179.69 + return;
179.70 +}
179.71 +
179.72 +void bfx_btran(BFX *binv, mpq_t x[])
179.73 +{ /* perform backward transformation (BTRAN) */
179.74 + xassert(binv->valid);
179.75 + lux_solve(binv->lux, 1, x);
179.76 + return;
179.77 +}
179.78 +
179.79 +int bfx_update(BFX *binv, int j)
179.80 +{ /* update factorization of the basis matrix */
179.81 + xassert(binv->valid);
179.82 + xassert(1 <= j && j <= binv->lux->n);
179.83 + return 1;
179.84 +}
179.85 +
179.86 +void bfx_delete_binv(BFX *binv)
179.87 +{ /* delete factorization of the basis matrix */
179.88 + if (binv->lux != NULL)
179.89 + lux_delete(binv->lux);
179.90 + xfree(binv);
179.91 + return;
179.92 +}
179.93 +
179.94 +/* eof */
180.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
180.2 +++ b/src/glpbfx.h Mon Dec 06 13:09:21 2010 +0100
180.3 @@ -0,0 +1,71 @@
180.4 +/* glpbfx.h (basis factorization interface, bignum arithmetic) */
180.5 +
180.6 +/***********************************************************************
180.7 +* This code is part of GLPK (GNU Linear Programming Kit).
180.8 +*
180.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
180.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
180.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
180.12 +* E-mail: <mao@gnu.org>.
180.13 +*
180.14 +* GLPK is free software: you can redistribute it and/or modify it
180.15 +* under the terms of the GNU General Public License as published by
180.16 +* the Free Software Foundation, either version 3 of the License, or
180.17 +* (at your option) any later version.
180.18 +*
180.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
180.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
180.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
180.22 +* License for more details.
180.23 +*
180.24 +* You should have received a copy of the GNU General Public License
180.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
180.26 +***********************************************************************/
180.27 +
180.28 +#ifndef GLPBFX_H
180.29 +#define GLPBFX_H
180.30 +
180.31 +#include "glpgmp.h"
180.32 +
180.33 +#ifndef GLPBFX_DEFINED
180.34 +#define GLPBFX_DEFINED
180.35 +typedef struct { double _opaque_bfx; } BFX;
180.36 +#endif
180.37 +
180.38 +#define bfx_create_binv _glp_bfx_create_binv
180.39 +#define bfx_is_valid _glp_bfx_is_valid
180.40 +#define bfx_invalidate _glp_bfx_invalidate
180.41 +#define bfx_factorize _glp_bfx_factorize
180.42 +#define bfx_ftran _glp_bfx_ftran
180.43 +#define bfx_btran _glp_bfx_btran
180.44 +#define bfx_update _glp_bfx_update
180.45 +#define bfx_delete_binv _glp_bfx_delete_binv
180.46 +
180.47 +BFX *bfx_create_binv(void);
180.48 +/* create factorization of the basis matrix */
180.49 +
180.50 +int bfx_is_valid(BFX *binv);
180.51 +/* check if factorization is valid */
180.52 +
180.53 +void bfx_invalidate(BFX *binv);
180.54 +/* invalidate factorization of the basis matrix */
180.55 +
180.56 +int bfx_factorize(BFX *binv, int m, int (*col)(void *info, int j,
180.57 + int ind[], mpq_t val[]), void *info);
180.58 +/* compute factorization of the basis matrix */
180.59 +
180.60 +void bfx_ftran(BFX *binv, mpq_t x[], int save);
180.61 +/* perform forward transformation (FTRAN) */
180.62 +
180.63 +void bfx_btran(BFX *binv, mpq_t x[]);
180.64 +/* perform backward transformation (BTRAN) */
180.65 +
180.66 +int bfx_update(BFX *binv, int j);
180.67 +/* update factorization of the basis matrix */
180.68 +
180.69 +void bfx_delete_binv(BFX *binv);
180.70 +/* delete factorization of the basis matrix */
180.71 +
180.72 +#endif
180.73 +
180.74 +/* eof */
181.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
181.2 +++ b/src/glpcpx.c Mon Dec 06 13:09:21 2010 +0100
181.3 @@ -0,0 +1,1239 @@
181.4 +/* glpcpx.c (CPLEX LP format routines) */
181.5 +
181.6 +/***********************************************************************
181.7 +* This code is part of GLPK (GNU Linear Programming Kit).
181.8 +*
181.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
181.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
181.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
181.12 +* E-mail: <mao@gnu.org>.
181.13 +*
181.14 +* GLPK is free software: you can redistribute it and/or modify it
181.15 +* under the terms of the GNU General Public License as published by
181.16 +* the Free Software Foundation, either version 3 of the License, or
181.17 +* (at your option) any later version.
181.18 +*
181.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
181.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
181.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
181.22 +* License for more details.
181.23 +*
181.24 +* You should have received a copy of the GNU General Public License
181.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
181.26 +***********************************************************************/
181.27 +
181.28 +#include "glpapi.h"
181.29 +
181.30 +/***********************************************************************
181.31 +* NAME
181.32 +*
181.33 +* glp_init_cpxcp - initialize CPLEX LP format control parameters
181.34 +*
181.35 +* SYNOPSIS
181.36 +*
181.37 +* void glp_init_cpxcp(glp_cpxcp *parm):
181.38 +*
181.39 +* The routine glp_init_cpxcp initializes control parameters used by
181.40 +* the CPLEX LP input/output routines glp_read_lp and glp_write_lp with
181.41 +* default values.
181.42 +*
181.43 +* Default values of the control parameters are stored in the glp_cpxcp
181.44 +* structure, which the parameter parm points to. */
181.45 +
181.46 +void glp_init_cpxcp(glp_cpxcp *parm)
181.47 +{ xassert(parm != NULL);
181.48 + return;
181.49 +}
181.50 +
181.51 +static void check_parm(const char *func, const glp_cpxcp *parm)
181.52 +{ /* check control parameters */
181.53 + xassert(func != NULL);
181.54 + xassert(parm != NULL);
181.55 + return;
181.56 +}
181.57 +
181.58 +/***********************************************************************
181.59 +* NAME
181.60 +*
181.61 +* glp_read_lp - read problem data in CPLEX LP format
181.62 +*
181.63 +* SYNOPSIS
181.64 +*
181.65 +* int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char
181.66 +* *fname);
181.67 +*
181.68 +* DESCRIPTION
181.69 +*
181.70 +* The routine glp_read_lp reads problem data in CPLEX LP format from
181.71 +* a text file.
181.72 +*
181.73 +* The parameter parm is a pointer to the structure glp_cpxcp, which
181.74 +* specifies control parameters used by the routine. If parm is NULL,
181.75 +* the routine uses default settings.
181.76 +*
181.77 +* The character string fname specifies a name of the text file to be
181.78 +* read.
181.79 +*
181.80 +* Note that before reading data the current content of the problem
181.81 +* object is completely erased with the routine glp_erase_prob.
181.82 +*
181.83 +* RETURNS
181.84 +*
181.85 +* If the operation was successful, the routine glp_read_lp returns
181.86 +* zero. Otherwise, it prints an error message and returns non-zero. */
181.87 +
181.88 +struct csa
181.89 +{ /* common storage area */
181.90 + glp_prob *P;
181.91 + /* LP/MIP problem object */
181.92 + const glp_cpxcp *parm;
181.93 + /* pointer to control parameters */
181.94 + const char *fname;
181.95 + /* name of input CPLEX LP file */
181.96 + XFILE *fp;
181.97 + /* stream assigned to input CPLEX LP file */
181.98 + jmp_buf jump;
181.99 + /* label for go to in case of error */
181.100 + int count;
181.101 + /* line count */
181.102 + int c;
181.103 + /* current character or XEOF */
181.104 + int token;
181.105 + /* current token: */
181.106 +#define T_EOF 0x00 /* end of file */
181.107 +#define T_MINIMIZE 0x01 /* keyword 'minimize' */
181.108 +#define T_MAXIMIZE 0x02 /* keyword 'maximize' */
181.109 +#define T_SUBJECT_TO 0x03 /* keyword 'subject to' */
181.110 +#define T_BOUNDS 0x04 /* keyword 'bounds' */
181.111 +#define T_GENERAL 0x05 /* keyword 'general' */
181.112 +#define T_INTEGER 0x06 /* keyword 'integer' */
181.113 +#define T_BINARY 0x07 /* keyword 'binary' */
181.114 +#define T_END 0x08 /* keyword 'end' */
181.115 +#define T_NAME 0x09 /* symbolic name */
181.116 +#define T_NUMBER 0x0A /* numeric constant */
181.117 +#define T_PLUS 0x0B /* delimiter '+' */
181.118 +#define T_MINUS 0x0C /* delimiter '-' */
181.119 +#define T_COLON 0x0D /* delimiter ':' */
181.120 +#define T_LE 0x0E /* delimiter '<=' */
181.121 +#define T_GE 0x0F /* delimiter '>=' */
181.122 +#define T_EQ 0x10 /* delimiter '=' */
181.123 + char image[255+1];
181.124 + /* image of current token */
181.125 + int imlen;
181.126 + /* length of token image */
181.127 + double value;
181.128 + /* value of numeric constant */
181.129 + int n_max;
181.130 + /* length of the following five arrays (enlarged automatically,
181.131 + if necessary) */
181.132 + int *ind; /* int ind[1+n_max]; */
181.133 + double *val; /* double val[1+n_max]; */
181.134 + char *flag; /* char flag[1+n_max]; */
181.135 + /* working arrays used to construct linear forms */
181.136 + double *lb; /* double lb[1+n_max]; */
181.137 + double *ub; /* double ub[1+n_max]; */
181.138 + /* lower and upper bounds of variables (columns) */
181.139 +};
181.140 +
181.141 +#define CHAR_SET "!\"#$%&()/,.;?@_`'{}|~"
181.142 +/* characters, which may appear in symbolic names */
181.143 +
181.144 +static void error(struct csa *csa, const char *fmt, ...)
181.145 +{ /* print error message and terminate processing */
181.146 + va_list arg;
181.147 + xprintf("%s:%d: ", csa->fname, csa->count);
181.148 + va_start(arg, fmt);
181.149 + xvprintf(fmt, arg);
181.150 + va_end(arg);
181.151 + longjmp(csa->jump, 1);
181.152 + /* no return */
181.153 +}
181.154 +
181.155 +static void warning(struct csa *csa, const char *fmt, ...)
181.156 +{ /* print warning message and continue processing */
181.157 + va_list arg;
181.158 + xprintf("%s:%d: warning: ", csa->fname, csa->count);
181.159 + va_start(arg, fmt);
181.160 + xvprintf(fmt, arg);
181.161 + va_end(arg);
181.162 + return;
181.163 +}
181.164 +
181.165 +static void read_char(struct csa *csa)
181.166 +{ /* read next character from input file */
181.167 + int c;
181.168 + xassert(csa->c != XEOF);
181.169 + if (csa->c == '\n') csa->count++;
181.170 + c = xfgetc(csa->fp);
181.171 + if (c < 0)
181.172 + { if (xferror(csa->fp))
181.173 + error(csa, "read error - %s\n", xerrmsg());
181.174 + else if (csa->c == '\n')
181.175 + { csa->count--;
181.176 + c = XEOF;
181.177 + }
181.178 + else
181.179 + { warning(csa, "missing final end of line\n");
181.180 + c = '\n';
181.181 + }
181.182 + }
181.183 + else if (c == '\n')
181.184 + ;
181.185 + else if (isspace(c))
181.186 + c = ' ';
181.187 + else if (iscntrl(c))
181.188 + error(csa, "invalid control character 0x%02X\n", c);
181.189 + csa->c = c;
181.190 + return;
181.191 +}
181.192 +
181.193 +static void add_char(struct csa *csa)
181.194 +{ /* append current character to current token */
181.195 + if (csa->imlen == sizeof(csa->image)-1)
181.196 + error(csa, "token `%.15s...' too long\n", csa->image);
181.197 + csa->image[csa->imlen++] = (char)csa->c;
181.198 + csa->image[csa->imlen] = '\0';
181.199 + read_char(csa);
181.200 + return;
181.201 +}
181.202 +
181.203 +static int the_same(char *s1, char *s2)
181.204 +{ /* compare two character strings ignoring case sensitivity */
181.205 + for (; *s1 != '\0'; s1++, s2++)
181.206 + { if (tolower((unsigned char)*s1) != tolower((unsigned char)*s2))
181.207 + return 0;
181.208 + }
181.209 + return 1;
181.210 +}
181.211 +
181.212 +static void scan_token(struct csa *csa)
181.213 +{ /* scan next token */
181.214 + int flag;
181.215 + csa->token = -1;
181.216 + csa->image[0] = '\0';
181.217 + csa->imlen = 0;
181.218 + csa->value = 0.0;
181.219 +loop: flag = 0;
181.220 + /* skip non-significant characters */
181.221 + while (csa->c == ' ') read_char(csa);
181.222 + /* recognize and scan current token */
181.223 + if (csa->c == XEOF)
181.224 + csa->token = T_EOF;
181.225 + else if (csa->c == '\n')
181.226 + { read_char(csa);
181.227 + /* if the next character is letter, it may begin a keyword */
181.228 + if (isalpha(csa->c))
181.229 + { flag = 1;
181.230 + goto name;
181.231 + }
181.232 + goto loop;
181.233 + }
181.234 + else if (csa->c == '\\')
181.235 + { /* comment; ignore everything until end-of-line */
181.236 + while (csa->c != '\n') read_char(csa);
181.237 + goto loop;
181.238 + }
181.239 + else if (isalpha(csa->c) || csa->c != '.' && strchr(CHAR_SET,
181.240 + csa->c) != NULL)
181.241 +name: { /* symbolic name */
181.242 + csa->token = T_NAME;
181.243 + while (isalnum(csa->c) || strchr(CHAR_SET, csa->c) != NULL)
181.244 + add_char(csa);
181.245 + if (flag)
181.246 + { /* check for keyword */
181.247 + if (the_same(csa->image, "minimize"))
181.248 + csa->token = T_MINIMIZE;
181.249 + else if (the_same(csa->image, "minimum"))
181.250 + csa->token = T_MINIMIZE;
181.251 + else if (the_same(csa->image, "min"))
181.252 + csa->token = T_MINIMIZE;
181.253 + else if (the_same(csa->image, "maximize"))
181.254 + csa->token = T_MAXIMIZE;
181.255 + else if (the_same(csa->image, "maximum"))
181.256 + csa->token = T_MAXIMIZE;
181.257 + else if (the_same(csa->image, "max"))
181.258 + csa->token = T_MAXIMIZE;
181.259 + else if (the_same(csa->image, "subject"))
181.260 + { if (csa->c == ' ')
181.261 + { read_char(csa);
181.262 + if (tolower(csa->c) == 't')
181.263 + { csa->token = T_SUBJECT_TO;
181.264 + csa->image[csa->imlen++] = ' ';
181.265 + csa->image[csa->imlen] = '\0';
181.266 + add_char(csa);
181.267 + if (tolower(csa->c) != 'o')
181.268 + error(csa, "keyword `subject to' incomplete\n");
181.269 + add_char(csa);
181.270 + if (isalpha(csa->c))
181.271 + error(csa, "keyword `%s%c...' not recognized\n",
181.272 + csa->image, csa->c);
181.273 + }
181.274 + }
181.275 + }
181.276 + else if (the_same(csa->image, "such"))
181.277 + { if (csa->c == ' ')
181.278 + { read_char(csa);
181.279 + if (tolower(csa->c) == 't')
181.280 + { csa->token = T_SUBJECT_TO;
181.281 + csa->image[csa->imlen++] = ' ';
181.282 + csa->image[csa->imlen] = '\0';
181.283 + add_char(csa);
181.284 + if (tolower(csa->c) != 'h')
181.285 +err: error(csa, "keyword `such that' incomplete\n");
181.286 + add_char(csa);
181.287 + if (tolower(csa->c) != 'a') goto err;
181.288 + add_char(csa);
181.289 + if (tolower(csa->c) != 't') goto err;
181.290 + add_char(csa);
181.291 + if (isalpha(csa->c))
181.292 + error(csa, "keyword `%s%c...' not recognized\n",
181.293 + csa->image, csa->c);
181.294 + }
181.295 + }
181.296 + }
181.297 + else if (the_same(csa->image, "st"))
181.298 + csa->token = T_SUBJECT_TO;
181.299 + else if (the_same(csa->image, "s.t."))
181.300 + csa->token = T_SUBJECT_TO;
181.301 + else if (the_same(csa->image, "st."))
181.302 + csa->token = T_SUBJECT_TO;
181.303 + else if (the_same(csa->image, "bounds"))
181.304 + csa->token = T_BOUNDS;
181.305 + else if (the_same(csa->image, "bound"))
181.306 + csa->token = T_BOUNDS;
181.307 + else if (the_same(csa->image, "general"))
181.308 + csa->token = T_GENERAL;
181.309 + else if (the_same(csa->image, "generals"))
181.310 + csa->token = T_GENERAL;
181.311 + else if (the_same(csa->image, "gen"))
181.312 + csa->token = T_GENERAL;
181.313 + else if (the_same(csa->image, "integer"))
181.314 + csa->token = T_INTEGER;
181.315 + else if (the_same(csa->image, "integers"))
181.316 + csa->token = T_INTEGER;
181.317 + else if (the_same(csa->image, "int"))
181.318 + csa->token = T_INTEGER;
181.319 + else if (the_same(csa->image, "binary"))
181.320 + csa->token = T_BINARY;
181.321 + else if (the_same(csa->image, "binaries"))
181.322 + csa->token = T_BINARY;
181.323 + else if (the_same(csa->image, "bin"))
181.324 + csa->token = T_BINARY;
181.325 + else if (the_same(csa->image, "end"))
181.326 + csa->token = T_END;
181.327 + }
181.328 + }
181.329 + else if (isdigit(csa->c) || csa->c == '.')
181.330 + { /* numeric constant */
181.331 + csa->token = T_NUMBER;
181.332 + /* scan integer part */
181.333 + while (isdigit(csa->c)) add_char(csa);
181.334 + /* scan optional fractional part (it is mandatory, if there is
181.335 + no integer part) */
181.336 + if (csa->c == '.')
181.337 + { add_char(csa);
181.338 + if (csa->imlen == 1 && !isdigit(csa->c))
181.339 + error(csa, "invalid use of decimal point\n");
181.340 + while (isdigit(csa->c)) add_char(csa);
181.341 + }
181.342 + /* scan optional decimal exponent */
181.343 + if (csa->c == 'e' || csa->c == 'E')
181.344 + { add_char(csa);
181.345 + if (csa->c == '+' || csa->c == '-') add_char(csa);
181.346 + if (!isdigit(csa->c))
181.347 + error(csa, "numeric constant `%s' incomplete\n",
181.348 + csa->image);
181.349 + while (isdigit(csa->c)) add_char(csa);
181.350 + }
181.351 + /* convert the numeric constant to floating-point */
181.352 + if (str2num(csa->image, &csa->value))
181.353 + error(csa, "numeric constant `%s' out of range\n",
181.354 + csa->image);
181.355 + }
181.356 + else if (csa->c == '+')
181.357 + csa->token = T_PLUS, add_char(csa);
181.358 + else if (csa->c == '-')
181.359 + csa->token = T_MINUS, add_char(csa);
181.360 + else if (csa->c == ':')
181.361 + csa->token = T_COLON, add_char(csa);
181.362 + else if (csa->c == '<')
181.363 + { csa->token = T_LE, add_char(csa);
181.364 + if (csa->c == '=') add_char(csa);
181.365 + }
181.366 + else if (csa->c == '>')
181.367 + { csa->token = T_GE, add_char(csa);
181.368 + if (csa->c == '=') add_char(csa);
181.369 + }
181.370 + else if (csa->c == '=')
181.371 + { csa->token = T_EQ, add_char(csa);
181.372 + if (csa->c == '<')
181.373 + csa->token = T_LE, add_char(csa);
181.374 + else if (csa->c == '>')
181.375 + csa->token = T_GE, add_char(csa);
181.376 + }
181.377 + else
181.378 + error(csa, "character `%c' not recognized\n", csa->c);
181.379 + /* skip non-significant characters */
181.380 + while (csa->c == ' ') read_char(csa);
181.381 + return;
181.382 +}
181.383 +
181.384 +static int find_col(struct csa *csa, char *name)
181.385 +{ /* find column by its symbolic name */
181.386 + int j;
181.387 + j = glp_find_col(csa->P, name);
181.388 + if (j == 0)
181.389 + { /* not found; create new column */
181.390 + j = glp_add_cols(csa->P, 1);
181.391 + glp_set_col_name(csa->P, j, name);
181.392 + /* enlarge working arrays, if necessary */
181.393 + if (csa->n_max < j)
181.394 + { int n_max = csa->n_max;
181.395 + int *ind = csa->ind;
181.396 + double *val = csa->val;
181.397 + char *flag = csa->flag;
181.398 + double *lb = csa->lb;
181.399 + double *ub = csa->ub;
181.400 + csa->n_max += csa->n_max;
181.401 + csa->ind = xcalloc(1+csa->n_max, sizeof(int));
181.402 + memcpy(&csa->ind[1], &ind[1], n_max * sizeof(int));
181.403 + xfree(ind);
181.404 + csa->val = xcalloc(1+csa->n_max, sizeof(double));
181.405 + memcpy(&csa->val[1], &val[1], n_max * sizeof(double));
181.406 + xfree(val);
181.407 + csa->flag = xcalloc(1+csa->n_max, sizeof(char));
181.408 + memset(&csa->flag[1], 0, csa->n_max * sizeof(char));
181.409 + memcpy(&csa->flag[1], &flag[1], n_max * sizeof(char));
181.410 + xfree(flag);
181.411 + csa->lb = xcalloc(1+csa->n_max, sizeof(double));
181.412 + memcpy(&csa->lb[1], &lb[1], n_max * sizeof(double));
181.413 + xfree(lb);
181.414 + csa->ub = xcalloc(1+csa->n_max, sizeof(double));
181.415 + memcpy(&csa->ub[1], &ub[1], n_max * sizeof(double));
181.416 + xfree(ub);
181.417 + }
181.418 + csa->lb[j] = +DBL_MAX, csa->ub[j] = -DBL_MAX;
181.419 + }
181.420 + return j;
181.421 +}
181.422 +
181.423 +/***********************************************************************
181.424 +* parse_linear_form - parse linear form
181.425 +*
181.426 +* This routine parses the linear form using the following syntax:
181.427 +*
181.428 +* <variable> ::= <symbolic name>
181.429 +* <coefficient> ::= <numeric constant>
181.430 +* <term> ::= <variable> | <numeric constant> <variable>
181.431 +* <linear form> ::= <term> | + <term> | - <term> |
181.432 +* <linear form> + <term> | <linear form> - <term>
181.433 +*
181.434 +* The routine returns the number of terms in the linear form. */
181.435 +
181.436 +static int parse_linear_form(struct csa *csa)
181.437 +{ int j, k, len = 0, newlen;
181.438 + double s, coef;
181.439 +loop: /* parse an optional sign */
181.440 + if (csa->token == T_PLUS)
181.441 + s = +1.0, scan_token(csa);
181.442 + else if (csa->token == T_MINUS)
181.443 + s = -1.0, scan_token(csa);
181.444 + else
181.445 + s = +1.0;
181.446 + /* parse an optional coefficient */
181.447 + if (csa->token == T_NUMBER)
181.448 + coef = csa->value, scan_token(csa);
181.449 + else
181.450 + coef = 1.0;
181.451 + /* parse a variable name */
181.452 + if (csa->token != T_NAME)
181.453 + error(csa, "missing variable name\n");
181.454 + /* find the corresponding column */
181.455 + j = find_col(csa, csa->image);
181.456 + /* check if the variable is already used in the linear form */
181.457 + if (csa->flag[j])
181.458 + error(csa, "multiple use of variable `%s' not allowed\n",
181.459 + csa->image);
181.460 + /* add new term to the linear form */
181.461 + len++, csa->ind[len] = j, csa->val[len] = s * coef;
181.462 + /* and mark that the variable is used in the linear form */
181.463 + csa->flag[j] = 1;
181.464 + scan_token(csa);
181.465 + /* if the next token is a sign, there is another term */
181.466 + if (csa->token == T_PLUS || csa->token == T_MINUS) goto loop;
181.467 + /* clear marks of the variables used in the linear form */
181.468 + for (k = 1; k <= len; k++) csa->flag[csa->ind[k]] = 0;
181.469 + /* remove zero coefficients */
181.470 + newlen = 0;
181.471 + for (k = 1; k <= len; k++)
181.472 + { if (csa->val[k] != 0.0)
181.473 + { newlen++;
181.474 + csa->ind[newlen] = csa->ind[k];
181.475 + csa->val[newlen] = csa->val[k];
181.476 + }
181.477 + }
181.478 + return newlen;
181.479 +}
181.480 +
181.481 +/***********************************************************************
181.482 +* parse_objective - parse objective function
181.483 +*
181.484 +* This routine parses definition of the objective function using the
181.485 +* following syntax:
181.486 +*
181.487 +* <obj sense> ::= minimize | minimum | min | maximize | maximum | max
181.488 +* <obj name> ::= <empty> | <symbolic name> :
181.489 +* <obj function> ::= <obj sense> <obj name> <linear form> */
181.490 +
181.491 +static void parse_objective(struct csa *csa)
181.492 +{ /* parse objective sense */
181.493 + int k, len;
181.494 + /* parse the keyword 'minimize' or 'maximize' */
181.495 + if (csa->token == T_MINIMIZE)
181.496 + glp_set_obj_dir(csa->P, GLP_MIN);
181.497 + else if (csa->token == T_MAXIMIZE)
181.498 + glp_set_obj_dir(csa->P, GLP_MAX);
181.499 + else
181.500 + xassert(csa != csa);
181.501 + scan_token(csa);
181.502 + /* parse objective name */
181.503 + if (csa->token == T_NAME && csa->c == ':')
181.504 + { /* objective name is followed by a colon */
181.505 + glp_set_obj_name(csa->P, csa->image);
181.506 + scan_token(csa);
181.507 + xassert(csa->token == T_COLON);
181.508 + scan_token(csa);
181.509 + }
181.510 + else
181.511 + { /* objective name is not specified; use default */
181.512 + glp_set_obj_name(csa->P, "obj");
181.513 + }
181.514 + /* parse linear form */
181.515 + len = parse_linear_form(csa);
181.516 + for (k = 1; k <= len; k++)
181.517 + glp_set_obj_coef(csa->P, csa->ind[k], csa->val[k]);
181.518 + return;
181.519 +}
181.520 +
181.521 +/***********************************************************************
181.522 +* parse_constraints - parse constraints section
181.523 +*
181.524 +* This routine parses the constraints section using the following
181.525 +* syntax:
181.526 +*
181.527 +* <row name> ::= <empty> | <symbolic name> :
181.528 +* <row sense> ::= < | <= | =< | > | >= | => | =
181.529 +* <right-hand side> ::= <numeric constant> | + <numeric constant> |
181.530 +* - <numeric constant>
181.531 +* <constraint> ::= <row name> <linear form> <row sense>
181.532 +* <right-hand side>
181.533 +* <subject to> ::= subject to | such that | st | s.t. | st.
181.534 +* <constraints section> ::= <subject to> <constraint> |
181.535 +* <constraints section> <constraint> */
181.536 +
181.537 +static void parse_constraints(struct csa *csa)
181.538 +{ int i, len, type;
181.539 + double s;
181.540 + /* parse the keyword 'subject to' */
181.541 + xassert(csa->token == T_SUBJECT_TO);
181.542 + scan_token(csa);
181.543 +loop: /* create new row (constraint) */
181.544 + i = glp_add_rows(csa->P, 1);
181.545 + /* parse row name */
181.546 + if (csa->token == T_NAME && csa->c == ':')
181.547 + { /* row name is followed by a colon */
181.548 + if (glp_find_row(csa->P, csa->image) != 0)
181.549 + error(csa, "constraint `%s' multiply defined\n",
181.550 + csa->image);
181.551 + glp_set_row_name(csa->P, i, csa->image);
181.552 + scan_token(csa);
181.553 + xassert(csa->token == T_COLON);
181.554 + scan_token(csa);
181.555 + }
181.556 + else
181.557 + { /* row name is not specified; use default */
181.558 + char name[50];
181.559 + sprintf(name, "r.%d", csa->count);
181.560 + glp_set_row_name(csa->P, i, name);
181.561 + }
181.562 + /* parse linear form */
181.563 + len = parse_linear_form(csa);
181.564 + glp_set_mat_row(csa->P, i, len, csa->ind, csa->val);
181.565 + /* parse constraint sense */
181.566 + if (csa->token == T_LE)
181.567 + type = GLP_UP, scan_token(csa);
181.568 + else if (csa->token == T_GE)
181.569 + type = GLP_LO, scan_token(csa);
181.570 + else if (csa->token == T_EQ)
181.571 + type = GLP_FX, scan_token(csa);
181.572 + else
181.573 + error(csa, "missing constraint sense\n");
181.574 + /* parse right-hand side */
181.575 + if (csa->token == T_PLUS)
181.576 + s = +1.0, scan_token(csa);
181.577 + else if (csa->token == T_MINUS)
181.578 + s = -1.0, scan_token(csa);
181.579 + else
181.580 + s = +1.0;
181.581 + if (csa->token != T_NUMBER)
181.582 + error(csa, "missing right-hand side\n");
181.583 + glp_set_row_bnds(csa->P, i, type, s * csa->value, s * csa->value);
181.584 + /* the rest of the current line must be empty */
181.585 + if (!(csa->c == '\n' || csa->c == XEOF))
181.586 + error(csa, "invalid symbol(s) beyond right-hand side\n");
181.587 + scan_token(csa);
181.588 + /* if the next token is a sign, numeric constant, or a symbolic
181.589 + name, here is another constraint */
181.590 + if (csa->token == T_PLUS || csa->token == T_MINUS ||
181.591 + csa->token == T_NUMBER || csa->token == T_NAME) goto loop;
181.592 + return;
181.593 +}
181.594 +
181.595 +static void set_lower_bound(struct csa *csa, int j, double lb)
181.596 +{ /* set lower bound of j-th variable */
181.597 + if (csa->lb[j] != +DBL_MAX)
181.598 + { warning(csa, "lower bound of variable `%s' redefined\n",
181.599 + glp_get_col_name(csa->P, j));
181.600 + }
181.601 + csa->lb[j] = lb;
181.602 + return;
181.603 +}
181.604 +
181.605 +static void set_upper_bound(struct csa *csa, int j, double ub)
181.606 +{ /* set upper bound of j-th variable */
181.607 + if (csa->ub[j] != -DBL_MAX)
181.608 + { warning(csa, "upper bound of variable `%s' redefined\n",
181.609 + glp_get_col_name(csa->P, j));
181.610 + }
181.611 + csa->ub[j] = ub;
181.612 + return;
181.613 +}
181.614 +
181.615 +/***********************************************************************
181.616 +* parse_bounds - parse bounds section
181.617 +*
181.618 +* This routine parses the bounds section using the following syntax:
181.619 +*
181.620 +* <variable> ::= <symbolic name>
181.621 +* <infinity> ::= infinity | inf
181.622 +* <bound> ::= <numeric constant> | + <numeric constant> |
181.623 +* - <numeric constant> | + <infinity> | - <infinity>
181.624 +* <lt> ::= < | <= | =<
181.625 +* <gt> ::= > | >= | =>
181.626 +* <bound definition> ::= <bound> <lt> <variable> <lt> <bound> |
181.627 +* <bound> <lt> <variable> | <variable> <lt> <bound> |
181.628 +* <variable> <gt> <bound> | <variable> = <bound> | <variable> free
181.629 +* <bounds> ::= bounds | bound
181.630 +* <bounds section> ::= <bounds> |
181.631 +* <bounds section> <bound definition> */
181.632 +
181.633 +static void parse_bounds(struct csa *csa)
181.634 +{ int j, lb_flag;
181.635 + double lb, s;
181.636 + /* parse the keyword 'bounds' */
181.637 + xassert(csa->token == T_BOUNDS);
181.638 + scan_token(csa);
181.639 +loop: /* bound definition can start with a sign, numeric constant, or
181.640 + a symbolic name */
181.641 + if (!(csa->token == T_PLUS || csa->token == T_MINUS ||
181.642 + csa->token == T_NUMBER || csa->token == T_NAME)) goto done;
181.643 + /* parse bound definition */
181.644 + if (csa->token == T_PLUS || csa->token == T_MINUS)
181.645 + { /* parse signed lower bound */
181.646 + lb_flag = 1;
181.647 + s = (csa->token == T_PLUS ? +1.0 : -1.0);
181.648 + scan_token(csa);
181.649 + if (csa->token == T_NUMBER)
181.650 + lb = s * csa->value, scan_token(csa);
181.651 + else if (the_same(csa->image, "infinity") ||
181.652 + the_same(csa->image, "inf"))
181.653 + { if (s > 0.0)
181.654 + error(csa, "invalid use of `+inf' as lower bound\n");
181.655 + lb = -DBL_MAX, scan_token(csa);
181.656 + }
181.657 + else
181.658 + error(csa, "missing lower bound\n");
181.659 + }
181.660 + else if (csa->token == T_NUMBER)
181.661 + { /* parse unsigned lower bound */
181.662 + lb_flag = 1;
181.663 + lb = csa->value, scan_token(csa);
181.664 + }
181.665 + else
181.666 + { /* lower bound is not specified */
181.667 + lb_flag = 0;
181.668 + }
181.669 + /* parse the token that should follow the lower bound */
181.670 + if (lb_flag)
181.671 + { if (csa->token != T_LE)
181.672 + error(csa, "missing `<', `<=', or `=<' after lower bound\n")
181.673 + ;
181.674 + scan_token(csa);
181.675 + }
181.676 + /* parse variable name */
181.677 + if (csa->token != T_NAME)
181.678 + error(csa, "missing variable name\n");
181.679 + j = find_col(csa, csa->image);
181.680 + /* set lower bound */
181.681 + if (lb_flag) set_lower_bound(csa, j, lb);
181.682 + scan_token(csa);
181.683 + /* parse the context that follows the variable name */
181.684 + if (csa->token == T_LE)
181.685 + { /* parse upper bound */
181.686 + scan_token(csa);
181.687 + if (csa->token == T_PLUS || csa->token == T_MINUS)
181.688 + { /* parse signed upper bound */
181.689 + s = (csa->token == T_PLUS ? +1.0 : -1.0);
181.690 + scan_token(csa);
181.691 + if (csa->token == T_NUMBER)
181.692 + { set_upper_bound(csa, j, s * csa->value);
181.693 + scan_token(csa);
181.694 + }
181.695 + else if (the_same(csa->image, "infinity") ||
181.696 + the_same(csa->image, "inf"))
181.697 + { if (s < 0.0)
181.698 + error(csa, "invalid use of `-inf' as upper bound\n");
181.699 + set_upper_bound(csa, j, +DBL_MAX);
181.700 + scan_token(csa);
181.701 + }
181.702 + else
181.703 + error(csa, "missing upper bound\n");
181.704 + }
181.705 + else if (csa->token == T_NUMBER)
181.706 + { /* parse unsigned upper bound */
181.707 + set_upper_bound(csa, j, csa->value);
181.708 + scan_token(csa);
181.709 + }
181.710 + else
181.711 + error(csa, "missing upper bound\n");
181.712 + }
181.713 + else if (csa->token == T_GE)
181.714 + { /* parse lower bound */
181.715 + if (lb_flag)
181.716 + { /* the context '... <= x >= ...' is invalid */
181.717 + error(csa, "invalid bound definition\n");
181.718 + }
181.719 + scan_token(csa);
181.720 + if (csa->token == T_PLUS || csa->token == T_MINUS)
181.721 + { /* parse signed lower bound */
181.722 + s = (csa->token == T_PLUS ? +1.0 : -1.0);
181.723 + scan_token(csa);
181.724 + if (csa->token == T_NUMBER)
181.725 + { set_lower_bound(csa, j, s * csa->value);
181.726 + scan_token(csa);
181.727 + }
181.728 + else if (the_same(csa->image, "infinity") ||
181.729 + the_same(csa->image, "inf") == 0)
181.730 + { if (s > 0.0)
181.731 + error(csa, "invalid use of `+inf' as lower bound\n");
181.732 + set_lower_bound(csa, j, -DBL_MAX);
181.733 + scan_token(csa);
181.734 + }
181.735 + else
181.736 + error(csa, "missing lower bound\n");
181.737 + }
181.738 + else if (csa->token == T_NUMBER)
181.739 + { /* parse unsigned lower bound */
181.740 + set_lower_bound(csa, j, csa->value);
181.741 + scan_token(csa);
181.742 + }
181.743 + else
181.744 + error(csa, "missing lower bound\n");
181.745 + }
181.746 + else if (csa->token == T_EQ)
181.747 + { /* parse fixed value */
181.748 + if (lb_flag)
181.749 + { /* the context '... <= x = ...' is invalid */
181.750 + error(csa, "invalid bound definition\n");
181.751 + }
181.752 + scan_token(csa);
181.753 + if (csa->token == T_PLUS || csa->token == T_MINUS)
181.754 + { /* parse signed fixed value */
181.755 + s = (csa->token == T_PLUS ? +1.0 : -1.0);
181.756 + scan_token(csa);
181.757 + if (csa->token == T_NUMBER)
181.758 + { set_lower_bound(csa, j, s * csa->value);
181.759 + set_upper_bound(csa, j, s * csa->value);
181.760 + scan_token(csa);
181.761 + }
181.762 + else
181.763 + error(csa, "missing fixed value\n");
181.764 + }
181.765 + else if (csa->token == T_NUMBER)
181.766 + { /* parse unsigned fixed value */
181.767 + set_lower_bound(csa, j, csa->value);
181.768 + set_upper_bound(csa, j, csa->value);
181.769 + scan_token(csa);
181.770 + }
181.771 + else
181.772 + error(csa, "missing fixed value\n");
181.773 + }
181.774 + else if (the_same(csa->image, "free"))
181.775 + { /* parse the keyword 'free' */
181.776 + if (lb_flag)
181.777 + { /* the context '... <= x free ...' is invalid */
181.778 + error(csa, "invalid bound definition\n");
181.779 + }
181.780 + set_lower_bound(csa, j, -DBL_MAX);
181.781 + set_upper_bound(csa, j, +DBL_MAX);
181.782 + scan_token(csa);
181.783 + }
181.784 + else if (!lb_flag)
181.785 + { /* neither lower nor upper bounds are specified */
181.786 + error(csa, "invalid bound definition\n");
181.787 + }
181.788 + goto loop;
181.789 +done: return;
181.790 +}
181.791 +
181.792 +/***********************************************************************
181.793 +* parse_integer - parse general, integer, or binary section
181.794 +*
181.795 +* <variable> ::= <symbolic name>
181.796 +* <general> ::= general | generals | gen
181.797 +* <integer> ::= integer | integers | int
181.798 +* <binary> ::= binary | binaries | bin
181.799 +* <section head> ::= <general> <integer> <binary>
181.800 +* <additional section> ::= <section head> |
181.801 +* <additional section> <variable> */
181.802 +
181.803 +static void parse_integer(struct csa *csa)
181.804 +{ int j, binary;
181.805 + /* parse the keyword 'general', 'integer', or 'binary' */
181.806 + if (csa->token == T_GENERAL)
181.807 + binary = 0, scan_token(csa);
181.808 + else if (csa->token == T_INTEGER)
181.809 + binary = 0, scan_token(csa);
181.810 + else if (csa->token == T_BINARY)
181.811 + binary = 1, scan_token(csa);
181.812 + else
181.813 + xassert(csa != csa);
181.814 + /* parse list of variables (may be empty) */
181.815 + while (csa->token == T_NAME)
181.816 + { /* find the corresponding column */
181.817 + j = find_col(csa, csa->image);
181.818 + /* change kind of the variable */
181.819 + glp_set_col_kind(csa->P, j, GLP_IV);
181.820 + /* set 0-1 bounds for the binary variable */
181.821 + if (binary)
181.822 + { set_lower_bound(csa, j, 0.0);
181.823 + set_upper_bound(csa, j, 1.0);
181.824 + }
181.825 + scan_token(csa);
181.826 + }
181.827 + return;
181.828 +}
181.829 +
181.830 +int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname)
181.831 +{ /* read problem data in CPLEX LP format */
181.832 + glp_cpxcp _parm;
181.833 + struct csa _csa, *csa = &_csa;
181.834 + int ret;
181.835 + xprintf("Reading problem data from `%s'...\n", fname);
181.836 + if (parm == NULL)
181.837 + glp_init_cpxcp(&_parm), parm = &_parm;
181.838 + /* check control parameters */
181.839 + check_parm("glp_read_lp", parm);
181.840 + /* initialize common storage area */
181.841 + csa->P = P;
181.842 + csa->parm = parm;
181.843 + csa->fname = fname;
181.844 + csa->fp = NULL;
181.845 + if (setjmp(csa->jump))
181.846 + { ret = 1;
181.847 + goto done;
181.848 + }
181.849 + csa->count = 0;
181.850 + csa->c = '\n';
181.851 + csa->token = T_EOF;
181.852 + csa->image[0] = '\0';
181.853 + csa->imlen = 0;
181.854 + csa->value = 0.0;
181.855 + csa->n_max = 100;
181.856 + csa->ind = xcalloc(1+csa->n_max, sizeof(int));
181.857 + csa->val = xcalloc(1+csa->n_max, sizeof(double));
181.858 + csa->flag = xcalloc(1+csa->n_max, sizeof(char));
181.859 + memset(&csa->flag[1], 0, csa->n_max * sizeof(char));
181.860 + csa->lb = xcalloc(1+csa->n_max, sizeof(double));
181.861 + csa->ub = xcalloc(1+csa->n_max, sizeof(double));
181.862 + /* erase problem object */
181.863 + glp_erase_prob(P);
181.864 + glp_create_index(P);
181.865 + /* open input CPLEX LP file */
181.866 + csa->fp = xfopen(fname, "r");
181.867 + if (csa->fp == NULL)
181.868 + { xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
181.869 + ret = 1;
181.870 + goto done;
181.871 + }
181.872 + /* scan very first token */
181.873 + scan_token(csa);
181.874 + /* parse definition of the objective function */
181.875 + if (!(csa->token == T_MINIMIZE || csa->token == T_MAXIMIZE))
181.876 + error(csa, "`minimize' or `maximize' keyword missing\n");
181.877 + parse_objective(csa);
181.878 + /* parse constraints section */
181.879 + if (csa->token != T_SUBJECT_TO)
181.880 + error(csa, "constraints section missing\n");
181.881 + parse_constraints(csa);
181.882 + /* parse optional bounds section */
181.883 + if (csa->token == T_BOUNDS) parse_bounds(csa);
181.884 + /* parse optional general, integer, and binary sections */
181.885 + while (csa->token == T_GENERAL ||
181.886 + csa->token == T_INTEGER ||
181.887 + csa->token == T_BINARY) parse_integer(csa);
181.888 + /* check for the keyword 'end' */
181.889 + if (csa->token == T_END)
181.890 + scan_token(csa);
181.891 + else if (csa->token == T_EOF)
181.892 + warning(csa, "keyword `end' missing\n");
181.893 + else
181.894 + error(csa, "symbol `%s' in wrong position\n", csa->image);
181.895 + /* nothing must follow the keyword 'end' (except comments) */
181.896 + if (csa->token != T_EOF)
181.897 + error(csa, "extra symbol(s) detected beyond `end'\n");
181.898 + /* set bounds of variables */
181.899 + { int j, type;
181.900 + double lb, ub;
181.901 + for (j = 1; j <= P->n; j++)
181.902 + { lb = csa->lb[j];
181.903 + ub = csa->ub[j];
181.904 + if (lb == +DBL_MAX) lb = 0.0; /* default lb */
181.905 + if (ub == -DBL_MAX) ub = +DBL_MAX; /* default ub */
181.906 + if (lb == -DBL_MAX && ub == +DBL_MAX)
181.907 + type = GLP_FR;
181.908 + else if (ub == +DBL_MAX)
181.909 + type = GLP_LO;
181.910 + else if (lb == -DBL_MAX)
181.911 + type = GLP_UP;
181.912 + else if (lb != ub)
181.913 + type = GLP_DB;
181.914 + else
181.915 + type = GLP_FX;
181.916 + glp_set_col_bnds(csa->P, j, type, lb, ub);
181.917 + }
181.918 + }
181.919 + /* print some statistics */
181.920 + xprintf("%d row%s, %d column%s, %d non-zero%s\n",
181.921 + P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
181.922 + P->nnz, P->nnz == 1 ? "" : "s");
181.923 + if (glp_get_num_int(P) > 0)
181.924 + { int ni = glp_get_num_int(P);
181.925 + int nb = glp_get_num_bin(P);
181.926 + if (ni == 1)
181.927 + { if (nb == 0)
181.928 + xprintf("One variable is integer\n");
181.929 + else
181.930 + xprintf("One variable is binary\n");
181.931 + }
181.932 + else
181.933 + { xprintf("%d integer variables, ", ni);
181.934 + if (nb == 0)
181.935 + xprintf("none");
181.936 + else if (nb == 1)
181.937 + xprintf("one");
181.938 + else if (nb == ni)
181.939 + xprintf("all");
181.940 + else
181.941 + xprintf("%d", nb);
181.942 + xprintf(" of which %s binary\n", nb == 1 ? "is" : "are");
181.943 + }
181.944 + }
181.945 + xprintf("%d lines were read\n", csa->count);
181.946 + /* problem data has been successfully read */
181.947 + glp_delete_index(P);
181.948 + glp_sort_matrix(P);
181.949 + ret = 0;
181.950 +done: if (csa->fp != NULL) xfclose(csa->fp);
181.951 + xfree(csa->ind);
181.952 + xfree(csa->val);
181.953 + xfree(csa->flag);
181.954 + xfree(csa->lb);
181.955 + xfree(csa->ub);
181.956 + if (ret != 0) glp_erase_prob(P);
181.957 + return ret;
181.958 +}
181.959 +
181.960 +/***********************************************************************
181.961 +* NAME
181.962 +*
181.963 +* glp_write_lp - write problem data in CPLEX LP format
181.964 +*
181.965 +* SYNOPSIS
181.966 +*
181.967 +* int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char
181.968 +* *fname);
181.969 +*
181.970 +* DESCRIPTION
181.971 +*
181.972 +* The routine glp_write_lp writes problem data in CPLEX LP format to
181.973 +* a text file.
181.974 +*
181.975 +* The parameter parm is a pointer to the structure glp_cpxcp, which
181.976 +* specifies control parameters used by the routine. If parm is NULL,
181.977 +* the routine uses default settings.
181.978 +*
181.979 +* The character string fname specifies a name of the text file to be
181.980 +* written.
181.981 +*
181.982 +* RETURNS
181.983 +*
181.984 +* If the operation was successful, the routine glp_write_lp returns
181.985 +* zero. Otherwise, it prints an error message and returns non-zero. */
181.986 +
181.987 +#define csa csa1
181.988 +
181.989 +struct csa
181.990 +{ /* common storage area */
181.991 + glp_prob *P;
181.992 + /* pointer to problem object */
181.993 + const glp_cpxcp *parm;
181.994 + /* pointer to control parameters */
181.995 +};
181.996 +
181.997 +static int check_name(char *name)
181.998 +{ /* check if specified name is valid for CPLEX LP format */
181.999 + if (*name == '.') return 1;
181.1000 + if (isdigit((unsigned char)*name)) return 1;
181.1001 + for (; *name; name++)
181.1002 + { if (!isalnum((unsigned char)*name) &&
181.1003 + strchr(CHAR_SET, (unsigned char)*name) == NULL) return 1;
181.1004 + }
181.1005 + return 0; /* name is ok */
181.1006 +}
181.1007 +
181.1008 +static void adjust_name(char *name)
181.1009 +{ /* attempt to adjust specified name to make it valid for CPLEX LP
181.1010 + format */
181.1011 + for (; *name; name++)
181.1012 + { if (*name == ' ')
181.1013 + *name = '_';
181.1014 + else if (*name == '-')
181.1015 + *name = '~';
181.1016 + else if (*name == '[')
181.1017 + *name = '(';
181.1018 + else if (*name == ']')
181.1019 + *name = ')';
181.1020 + }
181.1021 + return;
181.1022 +}
181.1023 +
181.1024 +static char *row_name(struct csa *csa, int i, char rname[255+1])
181.1025 +{ /* construct symbolic name of i-th row (constraint) */
181.1026 + const char *name;
181.1027 + if (i == 0)
181.1028 + name = glp_get_obj_name(csa->P);
181.1029 + else
181.1030 + name = glp_get_row_name(csa->P, i);
181.1031 + if (name == NULL) goto fake;
181.1032 + strcpy(rname, name);
181.1033 + adjust_name(rname);
181.1034 + if (check_name(rname)) goto fake;
181.1035 + return rname;
181.1036 +fake: if (i == 0)
181.1037 + strcpy(rname, "obj");
181.1038 + else
181.1039 + sprintf(rname, "r_%d", i);
181.1040 + return rname;
181.1041 +}
181.1042 +
181.1043 +static char *col_name(struct csa *csa, int j, char cname[255+1])
181.1044 +{ /* construct symbolic name of j-th column (variable) */
181.1045 + const char *name;
181.1046 + name = glp_get_col_name(csa->P, j);
181.1047 + if (name == NULL) goto fake;
181.1048 + strcpy(cname, name);
181.1049 + adjust_name(cname);
181.1050 + if (check_name(cname)) goto fake;
181.1051 + return cname;
181.1052 +fake: sprintf(cname, "x_%d", j);
181.1053 + return cname;
181.1054 +}
181.1055 +
181.1056 +int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname)
181.1057 +{ /* write problem data in CPLEX LP format */
181.1058 + glp_cpxcp _parm;
181.1059 + struct csa _csa, *csa = &_csa;
181.1060 + XFILE *fp;
181.1061 + GLPROW *row;
181.1062 + GLPCOL *col;
181.1063 + GLPAIJ *aij;
181.1064 + int i, j, len, flag, count, ret;
181.1065 + char line[1000+1], term[500+1], name[255+1];
181.1066 + xprintf("Writing problem data to `%s'...\n", fname);
181.1067 + if (parm == NULL)
181.1068 + glp_init_cpxcp(&_parm), parm = &_parm;
181.1069 + /* check control parameters */
181.1070 + check_parm("glp_write_lp", parm);
181.1071 + /* initialize common storage area */
181.1072 + csa->P = P;
181.1073 + csa->parm = parm;
181.1074 + /* create output CPLEX LP file */
181.1075 + fp = xfopen(fname, "w"), count = 0;
181.1076 + if (fp == NULL)
181.1077 + { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
181.1078 + ret = 1;
181.1079 + goto done;
181.1080 + }
181.1081 + /* write problem name */
181.1082 + xfprintf(fp, "\\* Problem: %s *\\\n",
181.1083 + P->name == NULL ? "Unknown" : P->name), count++;
181.1084 + xfprintf(fp, "\n"), count++;
181.1085 + /* the problem should contain at least one row and one column */
181.1086 + if (!(P->m > 0 && P->n > 0))
181.1087 + { xprintf("Warning: problem has no rows/columns\n");
181.1088 + xfprintf(fp, "\\* WARNING: PROBLEM HAS NO ROWS/COLUMNS *\\\n"),
181.1089 + count++;
181.1090 + xfprintf(fp, "\n"), count++;
181.1091 + goto skip;
181.1092 + }
181.1093 + /* write the objective function definition */
181.1094 + if (P->dir == GLP_MIN)
181.1095 + xfprintf(fp, "Minimize\n"), count++;
181.1096 + else if (P->dir == GLP_MAX)
181.1097 + xfprintf(fp, "Maximize\n"), count++;
181.1098 + else
181.1099 + xassert(P != P);
181.1100 + row_name(csa, 0, name);
181.1101 + sprintf(line, " %s:", name);
181.1102 + len = 0;
181.1103 + for (j = 1; j <= P->n; j++)
181.1104 + { col = P->col[j];
181.1105 + if (col->coef != 0.0 || col->ptr == NULL)
181.1106 + { len++;
181.1107 + col_name(csa, j, name);
181.1108 + if (col->coef == 0.0)
181.1109 + sprintf(term, " + 0 %s", name); /* empty column */
181.1110 + else if (col->coef == +1.0)
181.1111 + sprintf(term, " + %s", name);
181.1112 + else if (col->coef == -1.0)
181.1113 + sprintf(term, " - %s", name);
181.1114 + else if (col->coef > 0.0)
181.1115 + sprintf(term, " + %.*g %s", DBL_DIG, +col->coef, name);
181.1116 + else
181.1117 + sprintf(term, " - %.*g %s", DBL_DIG, -col->coef, name);
181.1118 + if (strlen(line) + strlen(term) > 72)
181.1119 + xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
181.1120 + strcat(line, term);
181.1121 + }
181.1122 + }
181.1123 + if (len == 0)
181.1124 + { /* empty objective */
181.1125 + sprintf(term, " 0 %s", col_name(csa, 1, name));
181.1126 + strcat(line, term);
181.1127 + }
181.1128 + xfprintf(fp, "%s\n", line), count++;
181.1129 + if (P->c0 != 0.0)
181.1130 + xfprintf(fp, "\\* constant term = %.*g *\\\n", DBL_DIG, P->c0),
181.1131 + count++;
181.1132 + xfprintf(fp, "\n"), count++;
181.1133 + /* write the constraints section */
181.1134 + xfprintf(fp, "Subject To\n"), count++;
181.1135 + for (i = 1; i <= P->m; i++)
181.1136 + { row = P->row[i];
181.1137 + if (row->type == GLP_FR) continue; /* skip free row */
181.1138 + row_name(csa, i, name);
181.1139 + sprintf(line, " %s:", name);
181.1140 + /* linear form */
181.1141 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
181.1142 + { col_name(csa, aij->col->j, name);
181.1143 + if (aij->val == +1.0)
181.1144 + sprintf(term, " + %s", name);
181.1145 + else if (aij->val == -1.0)
181.1146 + sprintf(term, " - %s", name);
181.1147 + else if (aij->val > 0.0)
181.1148 + sprintf(term, " + %.*g %s", DBL_DIG, +aij->val, name);
181.1149 + else
181.1150 + sprintf(term, " - %.*g %s", DBL_DIG, -aij->val, name);
181.1151 + if (strlen(line) + strlen(term) > 72)
181.1152 + xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
181.1153 + strcat(line, term);
181.1154 + }
181.1155 + if (row->type == GLP_DB)
181.1156 + { /* double-bounded (ranged) constraint */
181.1157 + sprintf(term, " - ~r_%d", i);
181.1158 + if (strlen(line) + strlen(term) > 72)
181.1159 + xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
181.1160 + strcat(line, term);
181.1161 + }
181.1162 + else if (row->ptr == NULL)
181.1163 + { /* empty constraint */
181.1164 + sprintf(term, " 0 %s", col_name(csa, 1, name));
181.1165 + strcat(line, term);
181.1166 + }
181.1167 + /* right hand-side */
181.1168 + if (row->type == GLP_LO)
181.1169 + sprintf(term, " >= %.*g", DBL_DIG, row->lb);
181.1170 + else if (row->type == GLP_UP)
181.1171 + sprintf(term, " <= %.*g", DBL_DIG, row->ub);
181.1172 + else if (row->type == GLP_DB || row->type == GLP_FX)
181.1173 + sprintf(term, " = %.*g", DBL_DIG, row->lb);
181.1174 + else
181.1175 + xassert(row != row);
181.1176 + if (strlen(line) + strlen(term) > 72)
181.1177 + xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
181.1178 + strcat(line, term);
181.1179 + xfprintf(fp, "%s\n", line), count++;
181.1180 + }
181.1181 + xfprintf(fp, "\n"), count++;
181.1182 + /* write the bounds section */
181.1183 + flag = 0;
181.1184 + for (i = 1; i <= P->m; i++)
181.1185 + { row = P->row[i];
181.1186 + if (row->type != GLP_DB) continue;
181.1187 + if (!flag)
181.1188 + xfprintf(fp, "Bounds\n"), flag = 1, count++;
181.1189 + xfprintf(fp, " 0 <= ~r_%d <= %.*g\n",
181.1190 + i, DBL_DIG, row->ub - row->lb), count++;
181.1191 + }
181.1192 + for (j = 1; j <= P->n; j++)
181.1193 + { col = P->col[j];
181.1194 + if (col->type == GLP_LO && col->lb == 0.0) continue;
181.1195 + if (!flag)
181.1196 + xfprintf(fp, "Bounds\n"), flag = 1, count++;
181.1197 + col_name(csa, j, name);
181.1198 + if (col->type == GLP_FR)
181.1199 + xfprintf(fp, " %s free\n", name), count++;
181.1200 + else if (col->type == GLP_LO)
181.1201 + xfprintf(fp, " %s >= %.*g\n",
181.1202 + name, DBL_DIG, col->lb), count++;
181.1203 + else if (col->type == GLP_UP)
181.1204 + xfprintf(fp, " -Inf <= %s <= %.*g\n",
181.1205 + name, DBL_DIG, col->ub), count++;
181.1206 + else if (col->type == GLP_DB)
181.1207 + xfprintf(fp, " %.*g <= %s <= %.*g\n",
181.1208 + DBL_DIG, col->lb, name, DBL_DIG, col->ub), count++;
181.1209 + else if (col->type == GLP_FX)
181.1210 + xfprintf(fp, " %s = %.*g\n",
181.1211 + name, DBL_DIG, col->lb), count++;
181.1212 + else
181.1213 + xassert(col != col);
181.1214 + }
181.1215 + if (flag) xfprintf(fp, "\n"), count++;
181.1216 + /* write the integer section */
181.1217 + flag = 0;
181.1218 + for (j = 1; j <= P->n; j++)
181.1219 + { col = P->col[j];
181.1220 + if (col->kind == GLP_CV) continue;
181.1221 + xassert(col->kind == GLP_IV);
181.1222 + if (!flag)
181.1223 + xfprintf(fp, "Generals\n"), flag = 1, count++;
181.1224 + xfprintf(fp, " %s\n", col_name(csa, j, name)), count++;
181.1225 + }
181.1226 + if (flag) xfprintf(fp, "\n"), count++;
181.1227 +skip: /* write the end keyword */
181.1228 + xfprintf(fp, "End\n"), count++;
181.1229 + xfflush(fp);
181.1230 + if (xferror(fp))
181.1231 + { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
181.1232 + ret = 1;
181.1233 + goto done;
181.1234 + }
181.1235 + /* problem data has been successfully written */
181.1236 + xprintf("%d lines were written\n", count);
181.1237 + ret = 0;
181.1238 +done: if (fp != NULL) xfclose(fp);
181.1239 + return ret;
181.1240 +}
181.1241 +
181.1242 +/* eof */
182.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
182.2 +++ b/src/glpdmp.c Mon Dec 06 13:09:21 2010 +0100
182.3 @@ -0,0 +1,259 @@
182.4 +/* glpdmp.c (dynamic memory pool) */
182.5 +
182.6 +/***********************************************************************
182.7 +* This code is part of GLPK (GNU Linear Programming Kit).
182.8 +*
182.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
182.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
182.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
182.12 +* E-mail: <mao@gnu.org>.
182.13 +*
182.14 +* GLPK is free software: you can redistribute it and/or modify it
182.15 +* under the terms of the GNU General Public License as published by
182.16 +* the Free Software Foundation, either version 3 of the License, or
182.17 +* (at your option) any later version.
182.18 +*
182.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
182.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
182.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
182.22 +* License for more details.
182.23 +*
182.24 +* You should have received a copy of the GNU General Public License
182.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
182.26 +***********************************************************************/
182.27 +
182.28 +#include "glpdmp.h"
182.29 +
182.30 +#if 1 /* 29/VIII-2008 */
182.31 +/* some processors need data to be properly aligned; the macro
182.32 + align_datasize enlarges the specified size of a data item to provide
182.33 + a proper alignment of immediately following data */
182.34 +
182.35 +#define align_datasize(size) ((((size) + 7) / 8) * 8)
182.36 +/* 8 bytes is sufficient in both 32- and 64-bit environments */
182.37 +#endif
182.38 +
182.39 +#ifdef GLP_DEBUG
182.40 +struct info
182.41 +{ DMP *pool;
182.42 + int size;
182.43 +};
182.44 +#endif
182.45 +
182.46 +/***********************************************************************
182.47 +* NAME
182.48 +*
182.49 +* dmp_create_pool - create dynamic memory pool
182.50 +*
182.51 +* SYNOPSIS
182.52 +*
182.53 +* #include "glpdmp.h"
182.54 +* DMP *dmp_create_pool(void);
182.55 +*
182.56 +* DESCRIPTION
182.57 +*
182.58 +* The routine dmp_create_pool creates a dynamic memory pool.
182.59 +*
182.60 +* RETURNS
182.61 +*
182.62 +* The routine returns a pointer to the memory pool created. */
182.63 +
182.64 +DMP *dmp_create_pool(void)
182.65 +{ DMP *pool;
182.66 + int k;
182.67 +#ifdef GLP_DEBUG
182.68 + xprintf("dmp_create_pool: warning: debug mode enabled\n");
182.69 +#endif
182.70 + pool = xmalloc(sizeof(DMP));
182.71 +#if 0
182.72 + pool->size = 0;
182.73 +#endif
182.74 + for (k = 0; k <= 31; k++) pool->avail[k] = NULL;
182.75 + pool->block = NULL;
182.76 + pool->used = DMP_BLK_SIZE;
182.77 + pool->count.lo = pool->count.hi = 0;
182.78 + return pool;
182.79 +}
182.80 +
182.81 +/***********************************************************************
182.82 +* NAME
182.83 +*
182.84 +* dmp_get_atom - get free atom from dynamic memory pool
182.85 +*
182.86 +* SYNOPSIS
182.87 +*
182.88 +* #include "glpdmp.h"
182.89 +* void *dmp_get_atom(DMP *pool, int size);
182.90 +*
182.91 +* DESCRIPTION
182.92 +*
182.93 +* The routine dmp_get_atom obtains a free atom (memory block) from the
182.94 +* specified memory pool.
182.95 +*
182.96 +* The parameter size is the atom size, in bytes, 1 <= size <= 256.
182.97 +*
182.98 +* Note that the free atom contains arbitrary data, not binary zeros.
182.99 +*
182.100 +* RETURNS
182.101 +*
182.102 +* The routine returns a pointer to the free atom obtained. */
182.103 +
182.104 +void *dmp_get_atom(DMP *pool, int size)
182.105 +{ void *atom;
182.106 + int k;
182.107 +#ifdef GLP_DEBUG
182.108 + int orig_size = size;
182.109 +#endif
182.110 + if (!(1 <= size && size <= 256))
182.111 + xerror("dmp_get_atom: size = %d; invalid atom size\n", size);
182.112 +#if 0
182.113 + if (!(pool->size == 0 || pool->size == size))
182.114 + xerror("dmp_get_atom: size = %d; wrong atom size\n", size);
182.115 +#endif
182.116 + /* adjust the size to provide the proper data alignment */
182.117 + size = align_datasize(size);
182.118 +#ifdef GLP_DEBUG
182.119 + size += align_datasize(sizeof(struct info));
182.120 +#endif
182.121 + /* adjust the size to make it multiple of 8 bytes, if needed */
182.122 + size = ((size + 7) / 8) * 8;
182.123 + /* determine the corresponding list of free cells */
182.124 + k = size / 8 - 1;
182.125 + xassert(0 <= k && k <= 31);
182.126 + /* obtain a free atom */
182.127 + if (pool->avail[k] == NULL)
182.128 + { /* the list of free cells is empty */
182.129 + if (pool->used + size > DMP_BLK_SIZE)
182.130 + { /* allocate a new memory block */
182.131 + void *block = xmalloc(DMP_BLK_SIZE);
182.132 + *(void **)block = pool->block;
182.133 + pool->block = block;
182.134 + pool->used = align_datasize(sizeof(void *));
182.135 + }
182.136 + /* place the atom in the current memory block */
182.137 + atom = (char *)pool->block + pool->used;
182.138 + pool->used += size;
182.139 + }
182.140 + else
182.141 + { /* obtain the atom from the list of free cells */
182.142 + atom = pool->avail[k];
182.143 + pool->avail[k] = *(void **)atom;
182.144 + }
182.145 + memset(atom, '?', size);
182.146 + /* increase the number of atoms which are currently in use */
182.147 + pool->count.lo++;
182.148 + if (pool->count.lo == 0) pool->count.hi++;
182.149 +#ifdef GLP_DEBUG
182.150 + ((struct info *)atom)->pool = pool;
182.151 + ((struct info *)atom)->size = orig_size;
182.152 + atom = (char *)atom + align_datasize(sizeof(struct info));
182.153 +#endif
182.154 + return atom;
182.155 +}
182.156 +
182.157 +/***********************************************************************
182.158 +* NAME
182.159 +*
182.160 +* dmp_free_atom - return atom to dynamic memory pool
182.161 +*
182.162 +* SYNOPSIS
182.163 +*
182.164 +* #include "glpdmp.h"
182.165 +* void dmp_free_atom(DMP *pool, void *atom, int size);
182.166 +*
182.167 +* DESCRIPTION
182.168 +*
182.169 +* The routine dmp_free_atom returns the specified atom (memory block)
182.170 +* to the specified memory pool, making it free.
182.171 +*
182.172 +* The parameter size is the atom size, in bytes, 1 <= size <= 256.
182.173 +*
182.174 +* Note that the atom can be returned only to the pool, from which it
182.175 +* was obtained, and its size must be exactly the same as on obtaining
182.176 +* it from the pool. */
182.177 +
182.178 +void dmp_free_atom(DMP *pool, void *atom, int size)
182.179 +{ int k;
182.180 + if (!(1 <= size && size <= 256))
182.181 + xerror("dmp_free_atom: size = %d; invalid atom size\n", size);
182.182 +#if 0
182.183 + if (!(pool->size == 0 || pool->size == size))
182.184 + xerror("dmp_free_atom: size = %d; wrong atom size\n", size);
182.185 +#endif
182.186 + if (pool->count.lo == 0 && pool->count.hi == 0)
182.187 + xerror("dmp_free_atom: pool allocation error\n");
182.188 +#ifdef GLP_DEBUG
182.189 + atom = (char *)atom - align_datasize(sizeof(struct info));
182.190 + xassert(((struct info *)atom)->pool == pool);
182.191 + xassert(((struct info *)atom)->size == size);
182.192 +#endif
182.193 + /* adjust the size to provide the proper data alignment */
182.194 + size = align_datasize(size);
182.195 +#ifdef GLP_DEBUG
182.196 + size += align_datasize(sizeof(struct info));
182.197 +#endif
182.198 + /* adjust the size to make it multiple of 8 bytes, if needed */
182.199 + size = ((size + 7) / 8) * 8;
182.200 + /* determine the corresponding list of free cells */
182.201 + k = size / 8 - 1;
182.202 + xassert(0 <= k && k <= 31);
182.203 + /* return the atom to the list of free cells */
182.204 + *(void **)atom = pool->avail[k];
182.205 + pool->avail[k] = atom;
182.206 + /* decrease the number of atoms which are currently in use */
182.207 + pool->count.lo--;
182.208 + if (pool->count.lo == 0xFFFFFFFF) pool->count.hi--;
182.209 + return;
182.210 +}
182.211 +
182.212 +/***********************************************************************
182.213 +* NAME
182.214 +*
182.215 +* dmp_in_use - determine how many atoms are still in use
182.216 +*
182.217 +* SYNOPSIS
182.218 +*
182.219 +* #include "glpdmp.h"
182.220 +* glp_long dmp_in_use(DMP *pool);
182.221 +*
182.222 +* DESCRIPTION
182.223 +*
182.224 +* The routine dmp_in_use determines how many atoms allocated from the
182.225 +* specified memory pool with the routine dmp_get_atom are still in use,
182.226 +* i.e. not returned to the pool with the routine dmp_free_atom.
182.227 +*
182.228 +* RETURNS
182.229 +*
182.230 +* The routine returns the number of atoms which are still in use. */
182.231 +
182.232 +glp_long dmp_in_use(DMP *pool)
182.233 +{ return
182.234 + pool->count;
182.235 +}
182.236 +
182.237 +/***********************************************************************
182.238 +* NAME
182.239 +*
182.240 +* dmp_delete_pool - delete dynamic memory pool
182.241 +*
182.242 +* SYNOPSIS
182.243 +*
182.244 +* #include "glpdmp.h"
182.245 +* void dmp_delete_pool(DMP *pool);
182.246 +*
182.247 +* DESCRIPTION
182.248 +*
182.249 +* The routine dmp_delete_pool deletes the specified dynamic memory
182.250 +* pool and frees all the memory allocated to this object. */
182.251 +
182.252 +void dmp_delete_pool(DMP *pool)
182.253 +{ while (pool->block != NULL)
182.254 + { void *block = pool->block;
182.255 + pool->block = *(void **)block;
182.256 + xfree(block);
182.257 + }
182.258 + xfree(pool);
182.259 + return;
182.260 +}
182.261 +
182.262 +/* eof */
183.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
183.2 +++ b/src/glpdmp.h Mon Dec 06 13:09:21 2010 +0100
183.3 @@ -0,0 +1,80 @@
183.4 +/* glpdmp.h (dynamic memory pool) */
183.5 +
183.6 +/***********************************************************************
183.7 +* This code is part of GLPK (GNU Linear Programming Kit).
183.8 +*
183.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
183.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
183.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
183.12 +* E-mail: <mao@gnu.org>.
183.13 +*
183.14 +* GLPK is free software: you can redistribute it and/or modify it
183.15 +* under the terms of the GNU General Public License as published by
183.16 +* the Free Software Foundation, either version 3 of the License, or
183.17 +* (at your option) any later version.
183.18 +*
183.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
183.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
183.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
183.22 +* License for more details.
183.23 +*
183.24 +* You should have received a copy of the GNU General Public License
183.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
183.26 +***********************************************************************/
183.27 +
183.28 +#ifndef GLPDMP_H
183.29 +#define GLPDMP_H
183.30 +
183.31 +#include "glpenv.h"
183.32 +
183.33 +typedef struct DMP DMP;
183.34 +
183.35 +#define DMP_BLK_SIZE 8000
183.36 +/* size of memory blocks, in bytes, allocated for memory pools */
183.37 +
183.38 +struct DMP
183.39 +{ /* dynamic memory pool */
183.40 +#if 0
183.41 + int size;
183.42 + /* size of atoms, in bytes, 1 <= size <= 256; if size = 0, atoms
183.43 + may have different sizes */
183.44 +#endif
183.45 + void *avail[32];
183.46 + /* avail[k], 0 <= k <= 31, is a pointer to the first available
183.47 + (free) cell of (k+1)*8 bytes long; in the beginning of each
183.48 + free cell there is a pointer to another free cell of the same
183.49 + length */
183.50 + void *block;
183.51 + /* pointer to the most recently allocated memory block; in the
183.52 + beginning of each allocated memory block there is a pointer to
183.53 + the previously allocated memory block */
183.54 + int used;
183.55 + /* number of bytes used in the most recently allocated memory
183.56 + block */
183.57 + glp_long count;
183.58 + /* number of atoms which are currently in use */
183.59 +};
183.60 +
183.61 +#define dmp_create_pool _glp_dmp_create_pool
183.62 +DMP *dmp_create_pool(void);
183.63 +/* create dynamic memory pool */
183.64 +
183.65 +#define dmp_get_atom _glp_dmp_get_atom
183.66 +void *dmp_get_atom(DMP *pool, int size);
183.67 +/* get free atom from dynamic memory pool */
183.68 +
183.69 +#define dmp_free_atom _glp_dmp_free_atom
183.70 +void dmp_free_atom(DMP *pool, void *atom, int size);
183.71 +/* return atom to dynamic memory pool */
183.72 +
183.73 +#define dmp_in_use _glp_dmp_in_use
183.74 +glp_long dmp_in_use(DMP *pool);
183.75 +/* determine how many atoms are still in use */
183.76 +
183.77 +#define dmp_delete_pool _glp_dmp_delete_pool
183.78 +void dmp_delete_pool(DMP *pool);
183.79 +/* delete dynamic memory pool */
183.80 +
183.81 +#endif
183.82 +
183.83 +/* eof */
184.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
184.2 +++ b/src/glpdmx.c Mon Dec 06 13:09:21 2010 +0100
184.3 @@ -0,0 +1,1468 @@
184.4 +/* glpdmx.c (reading/writing data in DIMACS format) */
184.5 +
184.6 +/***********************************************************************
184.7 +* This code is part of GLPK (GNU Linear Programming Kit).
184.8 +*
184.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
184.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
184.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
184.12 +* E-mail: <mao@gnu.org>.
184.13 +*
184.14 +* GLPK is free software: you can redistribute it and/or modify it
184.15 +* under the terms of the GNU General Public License as published by
184.16 +* the Free Software Foundation, either version 3 of the License, or
184.17 +* (at your option) any later version.
184.18 +*
184.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
184.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
184.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
184.22 +* License for more details.
184.23 +*
184.24 +* You should have received a copy of the GNU General Public License
184.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
184.26 +***********************************************************************/
184.27 +
184.28 +#define _GLPSTD_STDIO
184.29 +#include "glpapi.h"
184.30 +
184.31 +struct csa
184.32 +{ /* common storage area */
184.33 + jmp_buf jump;
184.34 + /* label for go to in case of error */
184.35 + const char *fname;
184.36 + /* name of input text file */
184.37 + XFILE *fp;
184.38 + /* stream assigned to input text file */
184.39 + int count;
184.40 + /* line count */
184.41 + int c;
184.42 + /* current character */
184.43 + char field[255+1];
184.44 + /* data field */
184.45 + int empty;
184.46 + /* warning 'empty line ignored' was printed */
184.47 + int nonint;
184.48 + /* warning 'non-integer data detected' was printed */
184.49 +};
184.50 +
184.51 +static void error(struct csa *csa, const char *fmt, ...)
184.52 +{ /* print error message and terminate processing */
184.53 + va_list arg;
184.54 + xprintf("%s:%d: error: ", csa->fname, csa->count);
184.55 + va_start(arg, fmt);
184.56 + xvprintf(fmt, arg);
184.57 + va_end(arg);
184.58 + xprintf("\n");
184.59 + longjmp(csa->jump, 1);
184.60 + /* no return */
184.61 +}
184.62 +
184.63 +static void warning(struct csa *csa, const char *fmt, ...)
184.64 +{ /* print warning message and continue processing */
184.65 + va_list arg;
184.66 + xprintf("%s:%d: warning: ", csa->fname, csa->count);
184.67 + va_start(arg, fmt);
184.68 + xvprintf(fmt, arg);
184.69 + va_end(arg);
184.70 + xprintf("\n");
184.71 + return;
184.72 +}
184.73 +
184.74 +static void read_char(struct csa *csa)
184.75 +{ /* read character from input text file */
184.76 + int c;
184.77 + if (csa->c == '\n') csa->count++;
184.78 + c = xfgetc(csa->fp);
184.79 + if (c < 0)
184.80 + { if (xferror(csa->fp))
184.81 + error(csa, "read error - %s", xerrmsg());
184.82 + else if (csa->c == '\n')
184.83 + error(csa, "unexpected end of file");
184.84 + else
184.85 + { warning(csa, "missing final end of line");
184.86 + c = '\n';
184.87 + }
184.88 + }
184.89 + else if (c == '\n')
184.90 + ;
184.91 + else if (isspace(c))
184.92 + c = ' ';
184.93 + else if (iscntrl(c))
184.94 + error(csa, "invalid control character 0x%02X", c);
184.95 + csa->c = c;
184.96 + return;
184.97 +}
184.98 +
184.99 +static void read_designator(struct csa *csa)
184.100 +{ /* read one-character line designator */
184.101 + xassert(csa->c == '\n');
184.102 + read_char(csa);
184.103 + for (;;)
184.104 + { /* skip preceding white-space characters */
184.105 + while (csa->c == ' ')
184.106 + read_char(csa);
184.107 + if (csa->c == '\n')
184.108 + { /* ignore empty line */
184.109 + if (!csa->empty)
184.110 + { warning(csa, "empty line ignored");
184.111 + csa->empty = 1;
184.112 + }
184.113 + read_char(csa);
184.114 + }
184.115 + else if (csa->c == 'c')
184.116 + { /* skip comment line */
184.117 + while (csa->c != '\n')
184.118 + read_char(csa);
184.119 + read_char(csa);
184.120 + }
184.121 + else
184.122 + { /* hmm... looks like a line designator */
184.123 + csa->field[0] = (char)csa->c, csa->field[1] = '\0';
184.124 + /* check that it is followed by a white-space character */
184.125 + read_char(csa);
184.126 + if (!(csa->c == ' ' || csa->c == '\n'))
184.127 + error(csa, "line designator missing or invalid");
184.128 + break;
184.129 + }
184.130 + }
184.131 + return;
184.132 +}
184.133 +
184.134 +static void read_field(struct csa *csa)
184.135 +{ /* read data field */
184.136 + int len = 0;
184.137 + /* skip preceding white-space characters */
184.138 + while (csa->c == ' ')
184.139 + read_char(csa);
184.140 + /* scan data field */
184.141 + if (csa->c == '\n')
184.142 + error(csa, "unexpected end of line");
184.143 + while (!(csa->c == ' ' || csa->c == '\n'))
184.144 + { if (len == sizeof(csa->field)-1)
184.145 + error(csa, "data field `%.15s...' too long", csa->field);
184.146 + csa->field[len++] = (char)csa->c;
184.147 + read_char(csa);
184.148 + }
184.149 + csa->field[len] = '\0';
184.150 + return;
184.151 +}
184.152 +
184.153 +static void end_of_line(struct csa *csa)
184.154 +{ /* skip white-space characters until end of line */
184.155 + while (csa->c == ' ')
184.156 + read_char(csa);
184.157 + if (csa->c != '\n')
184.158 + error(csa, "too many data fields specified");
184.159 + return;
184.160 +}
184.161 +
184.162 +static void check_int(struct csa *csa, double num)
184.163 +{ /* print a warning if non-integer data are detected */
184.164 + if (!csa->nonint && num != floor(num))
184.165 + { warning(csa, "non-integer data detected");
184.166 + csa->nonint = 1;
184.167 + }
184.168 + return;
184.169 +}
184.170 +
184.171 +/***********************************************************************
184.172 +* NAME
184.173 +*
184.174 +* glp_read_mincost - read min-cost flow problem data in DIMACS format
184.175 +*
184.176 +* SYNOPSIS
184.177 +*
184.178 +* int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
184.179 +* int a_cost, const char *fname);
184.180 +*
184.181 +* DESCRIPTION
184.182 +*
184.183 +* The routine glp_read_mincost reads minimum cost flow problem data in
184.184 +* DIMACS format from a text file.
184.185 +*
184.186 +* RETURNS
184.187 +*
184.188 +* If the operation was successful, the routine returns zero. Otherwise
184.189 +* it prints an error message and returns non-zero. */
184.190 +
184.191 +int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
184.192 + int a_cost, const char *fname)
184.193 +{ struct csa _csa, *csa = &_csa;
184.194 + glp_vertex *v;
184.195 + glp_arc *a;
184.196 + int i, j, k, nv, na, ret = 0;
184.197 + double rhs, low, cap, cost;
184.198 + char *flag = NULL;
184.199 + if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
184.200 + xerror("glp_read_mincost: v_rhs = %d; invalid offset\n",
184.201 + v_rhs);
184.202 + if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
184.203 + xerror("glp_read_mincost: a_low = %d; invalid offset\n",
184.204 + a_low);
184.205 + if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
184.206 + xerror("glp_read_mincost: a_cap = %d; invalid offset\n",
184.207 + a_cap);
184.208 + if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
184.209 + xerror("glp_read_mincost: a_cost = %d; invalid offset\n",
184.210 + a_cost);
184.211 + glp_erase_graph(G, G->v_size, G->a_size);
184.212 + if (setjmp(csa->jump))
184.213 + { ret = 1;
184.214 + goto done;
184.215 + }
184.216 + csa->fname = fname;
184.217 + csa->fp = NULL;
184.218 + csa->count = 0;
184.219 + csa->c = '\n';
184.220 + csa->field[0] = '\0';
184.221 + csa->empty = csa->nonint = 0;
184.222 + xprintf("Reading min-cost flow problem data from `%s'...\n",
184.223 + fname);
184.224 + csa->fp = xfopen(fname, "r");
184.225 + if (csa->fp == NULL)
184.226 + { xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
184.227 + longjmp(csa->jump, 1);
184.228 + }
184.229 + /* read problem line */
184.230 + read_designator(csa);
184.231 + if (strcmp(csa->field, "p") != 0)
184.232 + error(csa, "problem line missing or invalid");
184.233 + read_field(csa);
184.234 + if (strcmp(csa->field, "min") != 0)
184.235 + error(csa, "wrong problem designator; `min' expected");
184.236 + read_field(csa);
184.237 + if (!(str2int(csa->field, &nv) == 0 && nv >= 0))
184.238 + error(csa, "number of nodes missing or invalid");
184.239 + read_field(csa);
184.240 + if (!(str2int(csa->field, &na) == 0 && na >= 0))
184.241 + error(csa, "number of arcs missing or invalid");
184.242 + xprintf("Flow network has %d node%s and %d arc%s\n",
184.243 + nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s");
184.244 + if (nv > 0) glp_add_vertices(G, nv);
184.245 + end_of_line(csa);
184.246 + /* read node descriptor lines */
184.247 + flag = xcalloc(1+nv, sizeof(char));
184.248 + memset(&flag[1], 0, nv * sizeof(char));
184.249 + if (v_rhs >= 0)
184.250 + { rhs = 0.0;
184.251 + for (i = 1; i <= nv; i++)
184.252 + { v = G->v[i];
184.253 + memcpy((char *)v->data + v_rhs, &rhs, sizeof(double));
184.254 + }
184.255 + }
184.256 + for (;;)
184.257 + { read_designator(csa);
184.258 + if (strcmp(csa->field, "n") != 0) break;
184.259 + read_field(csa);
184.260 + if (str2int(csa->field, &i) != 0)
184.261 + error(csa, "node number missing or invalid");
184.262 + if (!(1 <= i && i <= nv))
184.263 + error(csa, "node number %d out of range", i);
184.264 + if (flag[i])
184.265 + error(csa, "duplicate descriptor of node %d", i);
184.266 + read_field(csa);
184.267 + if (str2num(csa->field, &rhs) != 0)
184.268 + error(csa, "node supply/demand missing or invalid");
184.269 + check_int(csa, rhs);
184.270 + if (v_rhs >= 0)
184.271 + { v = G->v[i];
184.272 + memcpy((char *)v->data + v_rhs, &rhs, sizeof(double));
184.273 + }
184.274 + flag[i] = 1;
184.275 + end_of_line(csa);
184.276 + }
184.277 + xfree(flag), flag = NULL;
184.278 + /* read arc descriptor lines */
184.279 + for (k = 1; k <= na; k++)
184.280 + { if (k > 1) read_designator(csa);
184.281 + if (strcmp(csa->field, "a") != 0)
184.282 + error(csa, "wrong line designator; `a' expected");
184.283 + read_field(csa);
184.284 + if (str2int(csa->field, &i) != 0)
184.285 + error(csa, "starting node number missing or invalid");
184.286 + if (!(1 <= i && i <= nv))
184.287 + error(csa, "starting node number %d out of range", i);
184.288 + read_field(csa);
184.289 + if (str2int(csa->field, &j) != 0)
184.290 + error(csa, "ending node number missing or invalid");
184.291 + if (!(1 <= j && j <= nv))
184.292 + error(csa, "ending node number %d out of range", j);
184.293 + read_field(csa);
184.294 + if (!(str2num(csa->field, &low) == 0 && low >= 0.0))
184.295 + error(csa, "lower bound of arc flow missing or invalid");
184.296 + check_int(csa, low);
184.297 + read_field(csa);
184.298 + if (!(str2num(csa->field, &cap) == 0 && cap >= low))
184.299 + error(csa, "upper bound of arc flow missing or invalid");
184.300 + check_int(csa, cap);
184.301 + read_field(csa);
184.302 + if (str2num(csa->field, &cost) != 0)
184.303 + error(csa, "per-unit cost of arc flow missing or invalid");
184.304 + check_int(csa, cost);
184.305 + a = glp_add_arc(G, i, j);
184.306 + if (a_low >= 0)
184.307 + memcpy((char *)a->data + a_low, &low, sizeof(double));
184.308 + if (a_cap >= 0)
184.309 + memcpy((char *)a->data + a_cap, &cap, sizeof(double));
184.310 + if (a_cost >= 0)
184.311 + memcpy((char *)a->data + a_cost, &cost, sizeof(double));
184.312 + end_of_line(csa);
184.313 + }
184.314 + xprintf("%d lines were read\n", csa->count);
184.315 +done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
184.316 + if (csa->fp != NULL) xfclose(csa->fp);
184.317 + if (flag != NULL) xfree(flag);
184.318 + return ret;
184.319 +}
184.320 +
184.321 +/***********************************************************************
184.322 +* NAME
184.323 +*
184.324 +* glp_write_mincost - write min-cost flow problem data in DIMACS format
184.325 +*
184.326 +* SYNOPSIS
184.327 +*
184.328 +* int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
184.329 +* int a_cost, const char *fname);
184.330 +*
184.331 +* DESCRIPTION
184.332 +*
184.333 +* The routine glp_write_mincost writes minimum cost flow problem data
184.334 +* in DIMACS format to a text file.
184.335 +*
184.336 +* RETURNS
184.337 +*
184.338 +* If the operation was successful, the routine returns zero. Otherwise
184.339 +* it prints an error message and returns non-zero. */
184.340 +
184.341 +int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
184.342 + int a_cost, const char *fname)
184.343 +{ XFILE *fp;
184.344 + glp_vertex *v;
184.345 + glp_arc *a;
184.346 + int i, count = 0, ret;
184.347 + double rhs, low, cap, cost;
184.348 + if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
184.349 + xerror("glp_write_mincost: v_rhs = %d; invalid offset\n",
184.350 + v_rhs);
184.351 + if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
184.352 + xerror("glp_write_mincost: a_low = %d; invalid offset\n",
184.353 + a_low);
184.354 + if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
184.355 + xerror("glp_write_mincost: a_cap = %d; invalid offset\n",
184.356 + a_cap);
184.357 + if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
184.358 + xerror("glp_write_mincost: a_cost = %d; invalid offset\n",
184.359 + a_cost);
184.360 + xprintf("Writing min-cost flow problem data to `%s'...\n",
184.361 + fname);
184.362 + fp = xfopen(fname, "w");
184.363 + if (fp == NULL)
184.364 + { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
184.365 + ret = 1;
184.366 + goto done;
184.367 + }
184.368 + xfprintf(fp, "c %s\n",
184.369 + G->name == NULL ? "unknown" : G->name), count++;
184.370 + xfprintf(fp, "p min %d %d\n", G->nv, G->na), count++;
184.371 + if (v_rhs >= 0)
184.372 + { for (i = 1; i <= G->nv; i++)
184.373 + { v = G->v[i];
184.374 + memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double));
184.375 + if (rhs != 0.0)
184.376 + xfprintf(fp, "n %d %.*g\n", i, DBL_DIG, rhs), count++;
184.377 + }
184.378 + }
184.379 + for (i = 1; i <= G->nv; i++)
184.380 + { v = G->v[i];
184.381 + for (a = v->out; a != NULL; a = a->t_next)
184.382 + { if (a_low >= 0)
184.383 + memcpy(&low, (char *)a->data + a_low, sizeof(double));
184.384 + else
184.385 + low = 0.0;
184.386 + if (a_cap >= 0)
184.387 + memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
184.388 + else
184.389 + cap = 1.0;
184.390 + if (a_cost >= 0)
184.391 + memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
184.392 + else
184.393 + cost = 0.0;
184.394 + xfprintf(fp, "a %d %d %.*g %.*g %.*g\n",
184.395 + a->tail->i, a->head->i, DBL_DIG, low, DBL_DIG, cap,
184.396 + DBL_DIG, cost), count++;
184.397 + }
184.398 + }
184.399 + xfprintf(fp, "c eof\n"), count++;
184.400 + xfflush(fp);
184.401 + if (xferror(fp))
184.402 + { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
184.403 + ret = 1;
184.404 + goto done;
184.405 + }
184.406 + xprintf("%d lines were written\n", count);
184.407 + ret = 0;
184.408 +done: if (fp != NULL) xfclose(fp);
184.409 + return ret;
184.410 +}
184.411 +
184.412 +/***********************************************************************
184.413 +* NAME
184.414 +*
184.415 +* glp_read_maxflow - read maximum flow problem data in DIMACS format
184.416 +*
184.417 +* SYNOPSIS
184.418 +*
184.419 +* int glp_read_maxflow(glp_graph *G, int *s, int *t, int a_cap,
184.420 +* const char *fname);
184.421 +*
184.422 +* DESCRIPTION
184.423 +*
184.424 +* The routine glp_read_maxflow reads maximum flow problem data in
184.425 +* DIMACS format from a text file.
184.426 +*
184.427 +* RETURNS
184.428 +*
184.429 +* If the operation was successful, the routine returns zero. Otherwise
184.430 +* it prints an error message and returns non-zero. */
184.431 +
184.432 +int glp_read_maxflow(glp_graph *G, int *_s, int *_t, int a_cap,
184.433 + const char *fname)
184.434 +{ struct csa _csa, *csa = &_csa;
184.435 + glp_arc *a;
184.436 + int i, j, k, s, t, nv, na, ret = 0;
184.437 + double cap;
184.438 + if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
184.439 + xerror("glp_read_maxflow: a_cap = %d; invalid offset\n",
184.440 + a_cap);
184.441 + glp_erase_graph(G, G->v_size, G->a_size);
184.442 + if (setjmp(csa->jump))
184.443 + { ret = 1;
184.444 + goto done;
184.445 + }
184.446 + csa->fname = fname;
184.447 + csa->fp = NULL;
184.448 + csa->count = 0;
184.449 + csa->c = '\n';
184.450 + csa->field[0] = '\0';
184.451 + csa->empty = csa->nonint = 0;
184.452 + xprintf("Reading maximum flow problem data from `%s'...\n",
184.453 + fname);
184.454 + csa->fp = xfopen(fname, "r");
184.455 + if (csa->fp == NULL)
184.456 + { xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
184.457 + longjmp(csa->jump, 1);
184.458 + }
184.459 + /* read problem line */
184.460 + read_designator(csa);
184.461 + if (strcmp(csa->field, "p") != 0)
184.462 + error(csa, "problem line missing or invalid");
184.463 + read_field(csa);
184.464 + if (strcmp(csa->field, "max") != 0)
184.465 + error(csa, "wrong problem designator; `max' expected");
184.466 + read_field(csa);
184.467 + if (!(str2int(csa->field, &nv) == 0 && nv >= 2))
184.468 + error(csa, "number of nodes missing or invalid");
184.469 + read_field(csa);
184.470 + if (!(str2int(csa->field, &na) == 0 && na >= 0))
184.471 + error(csa, "number of arcs missing or invalid");
184.472 + xprintf("Flow network has %d node%s and %d arc%s\n",
184.473 + nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s");
184.474 + if (nv > 0) glp_add_vertices(G, nv);
184.475 + end_of_line(csa);
184.476 + /* read node descriptor lines */
184.477 + s = t = 0;
184.478 + for (;;)
184.479 + { read_designator(csa);
184.480 + if (strcmp(csa->field, "n") != 0) break;
184.481 + read_field(csa);
184.482 + if (str2int(csa->field, &i) != 0)
184.483 + error(csa, "node number missing or invalid");
184.484 + if (!(1 <= i && i <= nv))
184.485 + error(csa, "node number %d out of range", i);
184.486 + read_field(csa);
184.487 + if (strcmp(csa->field, "s") == 0)
184.488 + { if (s > 0)
184.489 + error(csa, "only one source node allowed");
184.490 + s = i;
184.491 + }
184.492 + else if (strcmp(csa->field, "t") == 0)
184.493 + { if (t > 0)
184.494 + error(csa, "only one sink node allowed");
184.495 + t = i;
184.496 + }
184.497 + else
184.498 + error(csa, "wrong node designator; `s' or `t' expected");
184.499 + if (s > 0 && s == t)
184.500 + error(csa, "source and sink nodes must be distinct");
184.501 + end_of_line(csa);
184.502 + }
184.503 + if (s == 0)
184.504 + error(csa, "source node descriptor missing\n");
184.505 + if (t == 0)
184.506 + error(csa, "sink node descriptor missing\n");
184.507 + if (_s != NULL) *_s = s;
184.508 + if (_t != NULL) *_t = t;
184.509 + /* read arc descriptor lines */
184.510 + for (k = 1; k <= na; k++)
184.511 + { if (k > 1) read_designator(csa);
184.512 + if (strcmp(csa->field, "a") != 0)
184.513 + error(csa, "wrong line designator; `a' expected");
184.514 + read_field(csa);
184.515 + if (str2int(csa->field, &i) != 0)
184.516 + error(csa, "starting node number missing or invalid");
184.517 + if (!(1 <= i && i <= nv))
184.518 + error(csa, "starting node number %d out of range", i);
184.519 + read_field(csa);
184.520 + if (str2int(csa->field, &j) != 0)
184.521 + error(csa, "ending node number missing or invalid");
184.522 + if (!(1 <= j && j <= nv))
184.523 + error(csa, "ending node number %d out of range", j);
184.524 + read_field(csa);
184.525 + if (!(str2num(csa->field, &cap) == 0 && cap >= 0.0))
184.526 + error(csa, "arc capacity missing or invalid");
184.527 + check_int(csa, cap);
184.528 + a = glp_add_arc(G, i, j);
184.529 + if (a_cap >= 0)
184.530 + memcpy((char *)a->data + a_cap, &cap, sizeof(double));
184.531 + end_of_line(csa);
184.532 + }
184.533 + xprintf("%d lines were read\n", csa->count);
184.534 +done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
184.535 + if (csa->fp != NULL) xfclose(csa->fp);
184.536 + return ret;
184.537 +}
184.538 +
184.539 +/***********************************************************************
184.540 +* NAME
184.541 +*
184.542 +* glp_write_maxflow - write maximum flow problem data in DIMACS format
184.543 +*
184.544 +* SYNOPSIS
184.545 +*
184.546 +* int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
184.547 +* const char *fname);
184.548 +*
184.549 +* DESCRIPTION
184.550 +*
184.551 +* The routine glp_write_maxflow writes maximum flow problem data in
184.552 +* DIMACS format to a text file.
184.553 +*
184.554 +* RETURNS
184.555 +*
184.556 +* If the operation was successful, the routine returns zero. Otherwise
184.557 +* it prints an error message and returns non-zero. */
184.558 +
184.559 +int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
184.560 + const char *fname)
184.561 +{ XFILE *fp;
184.562 + glp_vertex *v;
184.563 + glp_arc *a;
184.564 + int i, count = 0, ret;
184.565 + double cap;
184.566 + if (!(1 <= s && s <= G->nv))
184.567 + xerror("glp_write_maxflow: s = %d; source node number out of r"
184.568 + "ange\n", s);
184.569 + if (!(1 <= t && t <= G->nv))
184.570 + xerror("glp_write_maxflow: t = %d: sink node number out of ran"
184.571 + "ge\n", t);
184.572 + if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
184.573 + xerror("glp_write_mincost: a_cap = %d; invalid offset\n",
184.574 + a_cap);
184.575 + xprintf("Writing maximum flow problem data to `%s'...\n",
184.576 + fname);
184.577 + fp = xfopen(fname, "w");
184.578 + if (fp == NULL)
184.579 + { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
184.580 + ret = 1;
184.581 + goto done;
184.582 + }
184.583 + xfprintf(fp, "c %s\n",
184.584 + G->name == NULL ? "unknown" : G->name), count++;
184.585 + xfprintf(fp, "p max %d %d\n", G->nv, G->na), count++;
184.586 + xfprintf(fp, "n %d s\n", s), count++;
184.587 + xfprintf(fp, "n %d t\n", t), count++;
184.588 + for (i = 1; i <= G->nv; i++)
184.589 + { v = G->v[i];
184.590 + for (a = v->out; a != NULL; a = a->t_next)
184.591 + { if (a_cap >= 0)
184.592 + memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
184.593 + else
184.594 + cap = 1.0;
184.595 + xfprintf(fp, "a %d %d %.*g\n",
184.596 + a->tail->i, a->head->i, DBL_DIG, cap), count++;
184.597 + }
184.598 + }
184.599 + xfprintf(fp, "c eof\n"), count++;
184.600 + xfflush(fp);
184.601 + if (xferror(fp))
184.602 + { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
184.603 + ret = 1;
184.604 + goto done;
184.605 + }
184.606 + xprintf("%d lines were written\n", count);
184.607 + ret = 0;
184.608 +done: if (fp != NULL) xfclose(fp);
184.609 + return ret;
184.610 +}
184.611 +
184.612 +/***********************************************************************
184.613 +* NAME
184.614 +*
184.615 +* glp_read_asnprob - read assignment problem data in DIMACS format
184.616 +*
184.617 +* SYNOPSIS
184.618 +*
184.619 +* int glp_read_asnprob(glp_graph *G, int v_set, int a_cost,
184.620 +* const char *fname);
184.621 +*
184.622 +* DESCRIPTION
184.623 +*
184.624 +* The routine glp_read_asnprob reads assignment problem data in DIMACS
184.625 +* format from a text file.
184.626 +*
184.627 +* RETURNS
184.628 +*
184.629 +* If the operation was successful, the routine returns zero. Otherwise
184.630 +* it prints an error message and returns non-zero. */
184.631 +
184.632 +int glp_read_asnprob(glp_graph *G, int v_set, int a_cost, const char
184.633 + *fname)
184.634 +{ struct csa _csa, *csa = &_csa;
184.635 + glp_vertex *v;
184.636 + glp_arc *a;
184.637 + int nv, na, n1, i, j, k, ret = 0;
184.638 + double cost;
184.639 + char *flag = NULL;
184.640 + if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
184.641 + xerror("glp_read_asnprob: v_set = %d; invalid offset\n",
184.642 + v_set);
184.643 + if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
184.644 + xerror("glp_read_asnprob: a_cost = %d; invalid offset\n",
184.645 + a_cost);
184.646 + glp_erase_graph(G, G->v_size, G->a_size);
184.647 + if (setjmp(csa->jump))
184.648 + { ret = 1;
184.649 + goto done;
184.650 + }
184.651 + csa->fname = fname;
184.652 + csa->fp = NULL;
184.653 + csa->count = 0;
184.654 + csa->c = '\n';
184.655 + csa->field[0] = '\0';
184.656 + csa->empty = csa->nonint = 0;
184.657 + xprintf("Reading assignment problem data from `%s'...\n", fname);
184.658 + csa->fp = xfopen(fname, "r");
184.659 + if (csa->fp == NULL)
184.660 + { xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
184.661 + longjmp(csa->jump, 1);
184.662 + }
184.663 + /* read problem line */
184.664 + read_designator(csa);
184.665 + if (strcmp(csa->field, "p") != 0)
184.666 + error(csa, "problem line missing or invalid");
184.667 + read_field(csa);
184.668 + if (strcmp(csa->field, "asn") != 0)
184.669 + error(csa, "wrong problem designator; `asn' expected");
184.670 + read_field(csa);
184.671 + if (!(str2int(csa->field, &nv) == 0 && nv >= 0))
184.672 + error(csa, "number of nodes missing or invalid");
184.673 + read_field(csa);
184.674 + if (!(str2int(csa->field, &na) == 0 && na >= 0))
184.675 + error(csa, "number of arcs missing or invalid");
184.676 + if (nv > 0) glp_add_vertices(G, nv);
184.677 + end_of_line(csa);
184.678 + /* read node descriptor lines */
184.679 + flag = xcalloc(1+nv, sizeof(char));
184.680 + memset(&flag[1], 0, nv * sizeof(char));
184.681 + n1 = 0;
184.682 + for (;;)
184.683 + { read_designator(csa);
184.684 + if (strcmp(csa->field, "n") != 0) break;
184.685 + read_field(csa);
184.686 + if (str2int(csa->field, &i) != 0)
184.687 + error(csa, "node number missing or invalid");
184.688 + if (!(1 <= i && i <= nv))
184.689 + error(csa, "node number %d out of range", i);
184.690 + if (flag[i])
184.691 + error(csa, "duplicate descriptor of node %d", i);
184.692 + flag[i] = 1, n1++;
184.693 + end_of_line(csa);
184.694 + }
184.695 + xprintf(
184.696 + "Assignment problem has %d + %d = %d node%s and %d arc%s\n",
184.697 + n1, nv - n1, nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s");
184.698 + if (v_set >= 0)
184.699 + { for (i = 1; i <= nv; i++)
184.700 + { v = G->v[i];
184.701 + k = (flag[i] ? 0 : 1);
184.702 + memcpy((char *)v->data + v_set, &k, sizeof(int));
184.703 + }
184.704 + }
184.705 + /* read arc descriptor lines */
184.706 + for (k = 1; k <= na; k++)
184.707 + { if (k > 1) read_designator(csa);
184.708 + if (strcmp(csa->field, "a") != 0)
184.709 + error(csa, "wrong line designator; `a' expected");
184.710 + read_field(csa);
184.711 + if (str2int(csa->field, &i) != 0)
184.712 + error(csa, "starting node number missing or invalid");
184.713 + if (!(1 <= i && i <= nv))
184.714 + error(csa, "starting node number %d out of range", i);
184.715 + if (!flag[i])
184.716 + error(csa, "node %d cannot be a starting node", i);
184.717 + read_field(csa);
184.718 + if (str2int(csa->field, &j) != 0)
184.719 + error(csa, "ending node number missing or invalid");
184.720 + if (!(1 <= j && j <= nv))
184.721 + error(csa, "ending node number %d out of range", j);
184.722 + if (flag[j])
184.723 + error(csa, "node %d cannot be an ending node", j);
184.724 + read_field(csa);
184.725 + if (str2num(csa->field, &cost) != 0)
184.726 + error(csa, "arc cost missing or invalid");
184.727 + check_int(csa, cost);
184.728 + a = glp_add_arc(G, i, j);
184.729 + if (a_cost >= 0)
184.730 + memcpy((char *)a->data + a_cost, &cost, sizeof(double));
184.731 + end_of_line(csa);
184.732 + }
184.733 + xprintf("%d lines were read\n", csa->count);
184.734 +done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
184.735 + if (csa->fp != NULL) xfclose(csa->fp);
184.736 + if (flag != NULL) xfree(flag);
184.737 + return ret;
184.738 +}
184.739 +
184.740 +/***********************************************************************
184.741 +* NAME
184.742 +*
184.743 +* glp_write_asnprob - write assignment problem data in DIMACS format
184.744 +*
184.745 +* SYNOPSIS
184.746 +*
184.747 +* int glp_write_asnprob(glp_graph *G, int v_set, int a_cost,
184.748 +* const char *fname);
184.749 +*
184.750 +* DESCRIPTION
184.751 +*
184.752 +* The routine glp_write_asnprob writes assignment problem data in
184.753 +* DIMACS format to a text file.
184.754 +*
184.755 +* RETURNS
184.756 +*
184.757 +* If the operation was successful, the routine returns zero. Otherwise
184.758 +* it prints an error message and returns non-zero. */
184.759 +
184.760 +int glp_write_asnprob(glp_graph *G, int v_set, int a_cost, const char
184.761 + *fname)
184.762 +{ XFILE *fp;
184.763 + glp_vertex *v;
184.764 + glp_arc *a;
184.765 + int i, k, count = 0, ret;
184.766 + double cost;
184.767 + if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
184.768 + xerror("glp_write_asnprob: v_set = %d; invalid offset\n",
184.769 + v_set);
184.770 + if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
184.771 + xerror("glp_write_asnprob: a_cost = %d; invalid offset\n",
184.772 + a_cost);
184.773 + xprintf("Writing assignment problem data to `%s'...\n", fname);
184.774 + fp = xfopen(fname, "w");
184.775 + if (fp == NULL)
184.776 + { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
184.777 + ret = 1;
184.778 + goto done;
184.779 + }
184.780 + xfprintf(fp, "c %s\n",
184.781 + G->name == NULL ? "unknown" : G->name), count++;
184.782 + xfprintf(fp, "p asn %d %d\n", G->nv, G->na), count++;
184.783 + for (i = 1; i <= G->nv; i++)
184.784 + { v = G->v[i];
184.785 + if (v_set >= 0)
184.786 + memcpy(&k, (char *)v->data + v_set, sizeof(int));
184.787 + else
184.788 + k = (v->out != NULL ? 0 : 1);
184.789 + if (k == 0)
184.790 + xfprintf(fp, "n %d\n", i), count++;
184.791 + }
184.792 + for (i = 1; i <= G->nv; i++)
184.793 + { v = G->v[i];
184.794 + for (a = v->out; a != NULL; a = a->t_next)
184.795 + { if (a_cost >= 0)
184.796 + memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
184.797 + else
184.798 + cost = 1.0;
184.799 + xfprintf(fp, "a %d %d %.*g\n",
184.800 + a->tail->i, a->head->i, DBL_DIG, cost), count++;
184.801 + }
184.802 + }
184.803 + xfprintf(fp, "c eof\n"), count++;
184.804 + xfflush(fp);
184.805 + if (xferror(fp))
184.806 + { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
184.807 + ret = 1;
184.808 + goto done;
184.809 + }
184.810 + xprintf("%d lines were written\n", count);
184.811 + ret = 0;
184.812 +done: if (fp != NULL) xfclose(fp);
184.813 + return ret;
184.814 +}
184.815 +
184.816 +/***********************************************************************
184.817 +* NAME
184.818 +*
184.819 +* glp_read_ccdata - read graph in DIMACS clique/coloring format
184.820 +*
184.821 +* SYNOPSIS
184.822 +*
184.823 +* int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname);
184.824 +*
184.825 +* DESCRIPTION
184.826 +*
184.827 +* The routine glp_read_ccdata reads an (undirected) graph in DIMACS
184.828 +* clique/coloring format from a text file.
184.829 +*
184.830 +* RETURNS
184.831 +*
184.832 +* If the operation was successful, the routine returns zero. Otherwise
184.833 +* it prints an error message and returns non-zero. */
184.834 +
184.835 +int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname)
184.836 +{ struct csa _csa, *csa = &_csa;
184.837 + glp_vertex *v;
184.838 + int i, j, k, nv, ne, ret = 0;
184.839 + double w;
184.840 + char *flag = NULL;
184.841 + if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double))
184.842 + xerror("glp_read_ccdata: v_wgt = %d; invalid offset\n",
184.843 + v_wgt);
184.844 + glp_erase_graph(G, G->v_size, G->a_size);
184.845 + if (setjmp(csa->jump))
184.846 + { ret = 1;
184.847 + goto done;
184.848 + }
184.849 + csa->fname = fname;
184.850 + csa->fp = NULL;
184.851 + csa->count = 0;
184.852 + csa->c = '\n';
184.853 + csa->field[0] = '\0';
184.854 + csa->empty = csa->nonint = 0;
184.855 + xprintf("Reading graph from `%s'...\n", fname);
184.856 + csa->fp = xfopen(fname, "r");
184.857 + if (csa->fp == NULL)
184.858 + { xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
184.859 + longjmp(csa->jump, 1);
184.860 + }
184.861 + /* read problem line */
184.862 + read_designator(csa);
184.863 + if (strcmp(csa->field, "p") != 0)
184.864 + error(csa, "problem line missing or invalid");
184.865 + read_field(csa);
184.866 + if (strcmp(csa->field, "edge") != 0)
184.867 + error(csa, "wrong problem designator; `edge' expected");
184.868 + read_field(csa);
184.869 + if (!(str2int(csa->field, &nv) == 0 && nv >= 0))
184.870 + error(csa, "number of vertices missing or invalid");
184.871 + read_field(csa);
184.872 + if (!(str2int(csa->field, &ne) == 0 && ne >= 0))
184.873 + error(csa, "number of edges missing or invalid");
184.874 + xprintf("Graph has %d vert%s and %d edge%s\n",
184.875 + nv, nv == 1 ? "ex" : "ices", ne, ne == 1 ? "" : "s");
184.876 + if (nv > 0) glp_add_vertices(G, nv);
184.877 + end_of_line(csa);
184.878 + /* read node descriptor lines */
184.879 + flag = xcalloc(1+nv, sizeof(char));
184.880 + memset(&flag[1], 0, nv * sizeof(char));
184.881 + if (v_wgt >= 0)
184.882 + { w = 1.0;
184.883 + for (i = 1; i <= nv; i++)
184.884 + { v = G->v[i];
184.885 + memcpy((char *)v->data + v_wgt, &w, sizeof(double));
184.886 + }
184.887 + }
184.888 + for (;;)
184.889 + { read_designator(csa);
184.890 + if (strcmp(csa->field, "n") != 0) break;
184.891 + read_field(csa);
184.892 + if (str2int(csa->field, &i) != 0)
184.893 + error(csa, "vertex number missing or invalid");
184.894 + if (!(1 <= i && i <= nv))
184.895 + error(csa, "vertex number %d out of range", i);
184.896 + if (flag[i])
184.897 + error(csa, "duplicate descriptor of vertex %d", i);
184.898 + read_field(csa);
184.899 + if (str2num(csa->field, &w) != 0)
184.900 + error(csa, "vertex weight missing or invalid");
184.901 + check_int(csa, w);
184.902 + if (v_wgt >= 0)
184.903 + { v = G->v[i];
184.904 + memcpy((char *)v->data + v_wgt, &w, sizeof(double));
184.905 + }
184.906 + flag[i] = 1;
184.907 + end_of_line(csa);
184.908 + }
184.909 + xfree(flag), flag = NULL;
184.910 + /* read edge descriptor lines */
184.911 + for (k = 1; k <= ne; k++)
184.912 + { if (k > 1) read_designator(csa);
184.913 + if (strcmp(csa->field, "e") != 0)
184.914 + error(csa, "wrong line designator; `e' expected");
184.915 + read_field(csa);
184.916 + if (str2int(csa->field, &i) != 0)
184.917 + error(csa, "first vertex number missing or invalid");
184.918 + if (!(1 <= i && i <= nv))
184.919 + error(csa, "first vertex number %d out of range", i);
184.920 + read_field(csa);
184.921 + if (str2int(csa->field, &j) != 0)
184.922 + error(csa, "second vertex number missing or invalid");
184.923 + if (!(1 <= j && j <= nv))
184.924 + error(csa, "second vertex number %d out of range", j);
184.925 + glp_add_arc(G, i, j);
184.926 + end_of_line(csa);
184.927 + }
184.928 + xprintf("%d lines were read\n", csa->count);
184.929 +done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
184.930 + if (csa->fp != NULL) xfclose(csa->fp);
184.931 + if (flag != NULL) xfree(flag);
184.932 + return ret;
184.933 +}
184.934 +
184.935 +/***********************************************************************
184.936 +* NAME
184.937 +*
184.938 +* glp_write_ccdata - write graph in DIMACS clique/coloring format
184.939 +*
184.940 +* SYNOPSIS
184.941 +*
184.942 +* int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname);
184.943 +*
184.944 +* DESCRIPTION
184.945 +*
184.946 +* The routine glp_write_ccdata writes the specified graph in DIMACS
184.947 +* clique/coloring format to a text file.
184.948 +*
184.949 +* RETURNS
184.950 +*
184.951 +* If the operation was successful, the routine returns zero. Otherwise
184.952 +* it prints an error message and returns non-zero. */
184.953 +
184.954 +int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname)
184.955 +{ XFILE *fp;
184.956 + glp_vertex *v;
184.957 + glp_arc *e;
184.958 + int i, count = 0, ret;
184.959 + double w;
184.960 + if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double))
184.961 + xerror("glp_write_ccdata: v_wgt = %d; invalid offset\n",
184.962 + v_wgt);
184.963 + xprintf("Writing graph to `%s'\n", fname);
184.964 + fp = xfopen(fname, "w");
184.965 + if (fp == NULL)
184.966 + { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
184.967 + ret = 1;
184.968 + goto done;
184.969 + }
184.970 + xfprintf(fp, "c %s\n",
184.971 + G->name == NULL ? "unknown" : G->name), count++;
184.972 + xfprintf(fp, "p edge %d %d\n", G->nv, G->na), count++;
184.973 + if (v_wgt >= 0)
184.974 + { for (i = 1; i <= G->nv; i++)
184.975 + { v = G->v[i];
184.976 + memcpy(&w, (char *)v->data + v_wgt, sizeof(double));
184.977 + if (w != 1.0)
184.978 + xfprintf(fp, "n %d %.*g\n", i, DBL_DIG, w), count++;
184.979 + }
184.980 + }
184.981 + for (i = 1; i <= G->nv; i++)
184.982 + { v = G->v[i];
184.983 + for (e = v->out; e != NULL; e = e->t_next)
184.984 + xfprintf(fp, "e %d %d\n", e->tail->i, e->head->i), count++;
184.985 + }
184.986 + xfprintf(fp, "c eof\n"), count++;
184.987 + xfflush(fp);
184.988 + if (xferror(fp))
184.989 + { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
184.990 + ret = 1;
184.991 + goto done;
184.992 + }
184.993 + xprintf("%d lines were written\n", count);
184.994 + ret = 0;
184.995 +done: if (fp != NULL) xfclose(fp);
184.996 + return ret;
184.997 +}
184.998 +
184.999 +/***********************************************************************
184.1000 +* NAME
184.1001 +*
184.1002 +* glp_read_prob - read problem data in GLPK format
184.1003 +*
184.1004 +* SYNOPSIS
184.1005 +*
184.1006 +* int glp_read_prob(glp_prob *P, int flags, const char *fname);
184.1007 +*
184.1008 +* The routine glp_read_prob reads problem data in GLPK LP/MIP format
184.1009 +* from a text file.
184.1010 +*
184.1011 +* RETURNS
184.1012 +*
184.1013 +* If the operation was successful, the routine returns zero. Otherwise
184.1014 +* it prints an error message and returns non-zero. */
184.1015 +
184.1016 +int glp_read_prob(glp_prob *P, int flags, const char *fname)
184.1017 +{ struct csa _csa, *csa = &_csa;
184.1018 + int mip, m, n, nnz, ne, i, j, k, type, kind, ret, *ln = NULL,
184.1019 + *ia = NULL, *ja = NULL;
184.1020 + double lb, ub, temp, *ar = NULL;
184.1021 + char *rf = NULL, *cf = NULL;
184.1022 + if (P == NULL || P->magic != GLP_PROB_MAGIC)
184.1023 + xerror("glp_read_prob: P = %p; invalid problem object\n",
184.1024 + P);
184.1025 + if (flags != 0)
184.1026 + xerror("glp_read_prob: flags = %d; invalid parameter\n",
184.1027 + flags);
184.1028 + if (fname == NULL)
184.1029 + xerror("glp_read_prob: fname = %d; invalid parameter\n",
184.1030 + fname);
184.1031 + glp_erase_prob(P);
184.1032 + if (setjmp(csa->jump))
184.1033 + { ret = 1;
184.1034 + goto done;
184.1035 + }
184.1036 + csa->fname = fname;
184.1037 + csa->fp = NULL;
184.1038 + csa->count = 0;
184.1039 + csa->c = '\n';
184.1040 + csa->field[0] = '\0';
184.1041 + csa->empty = csa->nonint = 0;
184.1042 + xprintf("Reading problem data from `%s'...\n", fname);
184.1043 + csa->fp = xfopen(fname, "r");
184.1044 + if (csa->fp == NULL)
184.1045 + { xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
184.1046 + longjmp(csa->jump, 1);
184.1047 + }
184.1048 + /* read problem line */
184.1049 + read_designator(csa);
184.1050 + if (strcmp(csa->field, "p") != 0)
184.1051 + error(csa, "problem line missing or invalid");
184.1052 + read_field(csa);
184.1053 + if (strcmp(csa->field, "lp") == 0)
184.1054 + mip = 0;
184.1055 + else if (strcmp(csa->field, "mip") == 0)
184.1056 + mip = 1;
184.1057 + else
184.1058 + error(csa, "wrong problem designator; `lp' or `mip' expected\n"
184.1059 + );
184.1060 + read_field(csa);
184.1061 + if (strcmp(csa->field, "min") == 0)
184.1062 + glp_set_obj_dir(P, GLP_MIN);
184.1063 + else if (strcmp(csa->field, "max") == 0)
184.1064 + glp_set_obj_dir(P, GLP_MAX);
184.1065 + else
184.1066 + error(csa, "objective sense missing or invalid");
184.1067 + read_field(csa);
184.1068 + if (!(str2int(csa->field, &m) == 0 && m >= 0))
184.1069 + error(csa, "number of rows missing or invalid");
184.1070 + read_field(csa);
184.1071 + if (!(str2int(csa->field, &n) == 0 && n >= 0))
184.1072 + error(csa, "number of columns missing or invalid");
184.1073 + read_field(csa);
184.1074 + if (!(str2int(csa->field, &nnz) == 0 && nnz >= 0))
184.1075 + error(csa, "number of constraint coefficients missing or inval"
184.1076 + "id");
184.1077 + if (m > 0)
184.1078 + { glp_add_rows(P, m);
184.1079 + for (i = 1; i <= m; i++)
184.1080 + glp_set_row_bnds(P, i, GLP_FX, 0.0, 0.0);
184.1081 + }
184.1082 + if (n > 0)
184.1083 + { glp_add_cols(P, n);
184.1084 + for (j = 1; j <= n; j++)
184.1085 + { if (!mip)
184.1086 + glp_set_col_bnds(P, j, GLP_LO, 0.0, 0.0);
184.1087 + else
184.1088 + glp_set_col_kind(P, j, GLP_BV);
184.1089 + }
184.1090 + }
184.1091 + end_of_line(csa);
184.1092 + /* allocate working arrays */
184.1093 + rf = xcalloc(1+m, sizeof(char));
184.1094 + memset(rf, 0, 1+m);
184.1095 + cf = xcalloc(1+n, sizeof(char));
184.1096 + memset(cf, 0, 1+n);
184.1097 + ln = xcalloc(1+nnz, sizeof(int));
184.1098 + ia = xcalloc(1+nnz, sizeof(int));
184.1099 + ja = xcalloc(1+nnz, sizeof(int));
184.1100 + ar = xcalloc(1+nnz, sizeof(double));
184.1101 + /* read descriptor lines */
184.1102 + ne = 0;
184.1103 + for (;;)
184.1104 + { read_designator(csa);
184.1105 + if (strcmp(csa->field, "i") == 0)
184.1106 + { /* row descriptor */
184.1107 + read_field(csa);
184.1108 + if (str2int(csa->field, &i) != 0)
184.1109 + error(csa, "row number missing or invalid");
184.1110 + if (!(1 <= i && i <= m))
184.1111 + error(csa, "row number out of range");
184.1112 + read_field(csa);
184.1113 + if (strcmp(csa->field, "f") == 0)
184.1114 + type = GLP_FR;
184.1115 + else if (strcmp(csa->field, "l") == 0)
184.1116 + type = GLP_LO;
184.1117 + else if (strcmp(csa->field, "u") == 0)
184.1118 + type = GLP_UP;
184.1119 + else if (strcmp(csa->field, "d") == 0)
184.1120 + type = GLP_DB;
184.1121 + else if (strcmp(csa->field, "s") == 0)
184.1122 + type = GLP_FX;
184.1123 + else
184.1124 + error(csa, "row type missing or invalid");
184.1125 + if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
184.1126 + { read_field(csa);
184.1127 + if (str2num(csa->field, &lb) != 0)
184.1128 + error(csa, "row lower bound/fixed value missing or in"
184.1129 + "valid");
184.1130 + }
184.1131 + else
184.1132 + lb = 0.0;
184.1133 + if (type == GLP_UP || type == GLP_DB)
184.1134 + { read_field(csa);
184.1135 + if (str2num(csa->field, &ub) != 0)
184.1136 + error(csa, "row upper bound missing or invalid");
184.1137 + }
184.1138 + else
184.1139 + ub = 0.0;
184.1140 + if (rf[i] & 0x01)
184.1141 + error(csa, "duplicate row descriptor");
184.1142 + glp_set_row_bnds(P, i, type, lb, ub), rf[i] |= 0x01;
184.1143 + }
184.1144 + else if (strcmp(csa->field, "j") == 0)
184.1145 + { /* column descriptor */
184.1146 + read_field(csa);
184.1147 + if (str2int(csa->field, &j) != 0)
184.1148 + error(csa, "column number missing or invalid");
184.1149 + if (!(1 <= j && j <= n))
184.1150 + error(csa, "column number out of range");
184.1151 + if (!mip)
184.1152 + kind = GLP_CV;
184.1153 + else
184.1154 + { read_field(csa);
184.1155 + if (strcmp(csa->field, "c") == 0)
184.1156 + kind = GLP_CV;
184.1157 + else if (strcmp(csa->field, "i") == 0)
184.1158 + kind = GLP_IV;
184.1159 + else if (strcmp(csa->field, "b") == 0)
184.1160 + { kind = GLP_IV;
184.1161 + type = GLP_DB, lb = 0.0, ub = 1.0;
184.1162 + goto skip;
184.1163 + }
184.1164 + else
184.1165 + error(csa, "column kind missing or invalid");
184.1166 + }
184.1167 + read_field(csa);
184.1168 + if (strcmp(csa->field, "f") == 0)
184.1169 + type = GLP_FR;
184.1170 + else if (strcmp(csa->field, "l") == 0)
184.1171 + type = GLP_LO;
184.1172 + else if (strcmp(csa->field, "u") == 0)
184.1173 + type = GLP_UP;
184.1174 + else if (strcmp(csa->field, "d") == 0)
184.1175 + type = GLP_DB;
184.1176 + else if (strcmp(csa->field, "s") == 0)
184.1177 + type = GLP_FX;
184.1178 + else
184.1179 + error(csa, "column type missing or invalid");
184.1180 + if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
184.1181 + { read_field(csa);
184.1182 + if (str2num(csa->field, &lb) != 0)
184.1183 + error(csa, "column lower bound/fixed value missing or"
184.1184 + " invalid");
184.1185 + }
184.1186 + else
184.1187 + lb = 0.0;
184.1188 + if (type == GLP_UP || type == GLP_DB)
184.1189 + { read_field(csa);
184.1190 + if (str2num(csa->field, &ub) != 0)
184.1191 + error(csa, "column upper bound missing or invalid");
184.1192 + }
184.1193 + else
184.1194 + ub = 0.0;
184.1195 +skip: if (cf[j] & 0x01)
184.1196 + error(csa, "duplicate column descriptor");
184.1197 + glp_set_col_kind(P, j, kind);
184.1198 + glp_set_col_bnds(P, j, type, lb, ub), cf[j] |= 0x01;
184.1199 + }
184.1200 + else if (strcmp(csa->field, "a") == 0)
184.1201 + { /* coefficient descriptor */
184.1202 + read_field(csa);
184.1203 + if (str2int(csa->field, &i) != 0)
184.1204 + error(csa, "row number missing or invalid");
184.1205 + if (!(0 <= i && i <= m))
184.1206 + error(csa, "row number out of range");
184.1207 + read_field(csa);
184.1208 + if (str2int(csa->field, &j) != 0)
184.1209 + error(csa, "column number missing or invalid");
184.1210 + if (!((i == 0 ? 0 : 1) <= j && j <= n))
184.1211 + error(csa, "column number out of range");
184.1212 + read_field(csa);
184.1213 + if (i == 0)
184.1214 + { if (str2num(csa->field, &temp) != 0)
184.1215 + error(csa, "objective %s missing or invalid",
184.1216 + j == 0 ? "constant term" : "coefficient");
184.1217 + if (cf[j] & 0x10)
184.1218 + error(csa, "duplicate objective %s",
184.1219 + j == 0 ? "constant term" : "coefficient");
184.1220 + glp_set_obj_coef(P, j, temp), cf[j] |= 0x10;
184.1221 + }
184.1222 + else
184.1223 + { if (str2num(csa->field, &temp) != 0)
184.1224 + error(csa, "constraint coefficient missing or invalid"
184.1225 + );
184.1226 + if (ne == nnz)
184.1227 + error(csa, "too many constraint coefficient descripto"
184.1228 + "rs");
184.1229 + ln[++ne] = csa->count;
184.1230 + ia[ne] = i, ja[ne] = j, ar[ne] = temp;
184.1231 + }
184.1232 + }
184.1233 + else if (strcmp(csa->field, "n") == 0)
184.1234 + { /* symbolic name descriptor */
184.1235 + read_field(csa);
184.1236 + if (strcmp(csa->field, "p") == 0)
184.1237 + { /* problem name */
184.1238 + read_field(csa);
184.1239 + if (P->name != NULL)
184.1240 + error(csa, "duplicate problem name");
184.1241 + glp_set_prob_name(P, csa->field);
184.1242 + }
184.1243 + else if (strcmp(csa->field, "z") == 0)
184.1244 + { /* objective name */
184.1245 + read_field(csa);
184.1246 + if (P->obj != NULL)
184.1247 + error(csa, "duplicate objective name");
184.1248 + glp_set_obj_name(P, csa->field);
184.1249 + }
184.1250 + else if (strcmp(csa->field, "i") == 0)
184.1251 + { /* row name */
184.1252 + read_field(csa);
184.1253 + if (str2int(csa->field, &i) != 0)
184.1254 + error(csa, "row number missing or invalid");
184.1255 + if (!(1 <= i && i <= m))
184.1256 + error(csa, "row number out of range");
184.1257 + read_field(csa);
184.1258 + if (P->row[i]->name != NULL)
184.1259 + error(csa, "duplicate row name");
184.1260 + glp_set_row_name(P, i, csa->field);
184.1261 + }
184.1262 + else if (strcmp(csa->field, "j") == 0)
184.1263 + { /* column name */
184.1264 + read_field(csa);
184.1265 + if (str2int(csa->field, &j) != 0)
184.1266 + error(csa, "column number missing or invalid");
184.1267 + if (!(1 <= j && j <= n))
184.1268 + error(csa, "column number out of range");
184.1269 + read_field(csa);
184.1270 + if (P->col[j]->name != NULL)
184.1271 + error(csa, "duplicate column name");
184.1272 + glp_set_col_name(P, j, csa->field);
184.1273 + }
184.1274 + else
184.1275 + error(csa, "object designator missing or invalid");
184.1276 + }
184.1277 + else if (strcmp(csa->field, "e") == 0)
184.1278 + break;
184.1279 + else
184.1280 + error(csa, "line designator missing or invalid");
184.1281 + end_of_line(csa);
184.1282 + }
184.1283 + if (ne < nnz)
184.1284 + error(csa, "too few constraint coefficient descriptors");
184.1285 + xassert(ne == nnz);
184.1286 + k = glp_check_dup(m, n, ne, ia, ja);
184.1287 + xassert(0 <= k && k <= nnz);
184.1288 + if (k > 0)
184.1289 + { csa->count = ln[k];
184.1290 + error(csa, "duplicate constraint coefficient");
184.1291 + }
184.1292 + glp_load_matrix(P, ne, ia, ja, ar);
184.1293 + /* print some statistics */
184.1294 + if (P->name != NULL)
184.1295 + xprintf("Problem: %s\n", P->name);
184.1296 + if (P->obj != NULL)
184.1297 + xprintf("Objective: %s\n", P->obj);
184.1298 + xprintf("%d row%s, %d column%s, %d non-zero%s\n",
184.1299 + m, m == 1 ? "" : "s", n, n == 1 ? "" : "s", nnz, nnz == 1 ?
184.1300 + "" : "s");
184.1301 + if (glp_get_num_int(P) > 0)
184.1302 + { int ni = glp_get_num_int(P);
184.1303 + int nb = glp_get_num_bin(P);
184.1304 + if (ni == 1)
184.1305 + { if (nb == 0)
184.1306 + xprintf("One variable is integer\n");
184.1307 + else
184.1308 + xprintf("One variable is binary\n");
184.1309 + }
184.1310 + else
184.1311 + { xprintf("%d integer variables, ", ni);
184.1312 + if (nb == 0)
184.1313 + xprintf("none");
184.1314 + else if (nb == 1)
184.1315 + xprintf("one");
184.1316 + else if (nb == ni)
184.1317 + xprintf("all");
184.1318 + else
184.1319 + xprintf("%d", nb);
184.1320 + xprintf(" of which %s binary\n", nb == 1 ? "is" : "are");
184.1321 + }
184.1322 + }
184.1323 + xprintf("%d lines were read\n", csa->count);
184.1324 + /* problem data has been successfully read */
184.1325 + glp_sort_matrix(P);
184.1326 + ret = 0;
184.1327 +done: if (csa->fp != NULL) xfclose(csa->fp);
184.1328 + if (rf != NULL) xfree(rf);
184.1329 + if (cf != NULL) xfree(cf);
184.1330 + if (ln != NULL) xfree(ln);
184.1331 + if (ia != NULL) xfree(ia);
184.1332 + if (ja != NULL) xfree(ja);
184.1333 + if (ar != NULL) xfree(ar);
184.1334 + if (ret) glp_erase_prob(P);
184.1335 + return ret;
184.1336 +}
184.1337 +
184.1338 +/***********************************************************************
184.1339 +* NAME
184.1340 +*
184.1341 +* glp_write_prob - write problem data in GLPK format
184.1342 +*
184.1343 +* SYNOPSIS
184.1344 +*
184.1345 +* int glp_write_prob(glp_prob *P, int flags, const char *fname);
184.1346 +*
184.1347 +* The routine glp_write_prob writes problem data in GLPK LP/MIP format
184.1348 +* to a text file.
184.1349 +*
184.1350 +* RETURNS
184.1351 +*
184.1352 +* If the operation was successful, the routine returns zero. Otherwise
184.1353 +* it prints an error message and returns non-zero. */
184.1354 +
184.1355 +int glp_write_prob(glp_prob *P, int flags, const char *fname)
184.1356 +{ XFILE *fp;
184.1357 + GLPROW *row;
184.1358 + GLPCOL *col;
184.1359 + GLPAIJ *aij;
184.1360 + int mip, i, j, count, ret;
184.1361 + if (P == NULL || P->magic != GLP_PROB_MAGIC)
184.1362 + xerror("glp_write_prob: P = %p; invalid problem object\n",
184.1363 + P);
184.1364 + if (flags != 0)
184.1365 + xerror("glp_write_prob: flags = %d; invalid parameter\n",
184.1366 + flags);
184.1367 + if (fname == NULL)
184.1368 + xerror("glp_write_prob: fname = %d; invalid parameter\n",
184.1369 + fname);
184.1370 + xprintf("Writing problem data to `%s'...\n", fname);
184.1371 + fp = xfopen(fname, "w"), count = 0;
184.1372 + if (fp == NULL)
184.1373 + { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
184.1374 + ret = 1;
184.1375 + goto done;
184.1376 + }
184.1377 + /* write problem line */
184.1378 + mip = (glp_get_num_int(P) > 0);
184.1379 + xfprintf(fp, "p %s %s %d %d %d\n", !mip ? "lp" : "mip",
184.1380 + P->dir == GLP_MIN ? "min" : P->dir == GLP_MAX ? "max" : "???",
184.1381 + P->m, P->n, P->nnz), count++;
184.1382 + if (P->name != NULL)
184.1383 + xfprintf(fp, "n p %s\n", P->name), count++;
184.1384 + if (P->obj != NULL)
184.1385 + xfprintf(fp, "n z %s\n", P->obj), count++;
184.1386 + /* write row descriptors */
184.1387 + for (i = 1; i <= P->m; i++)
184.1388 + { row = P->row[i];
184.1389 + if (row->type == GLP_FX && row->lb == 0.0)
184.1390 + goto skip1;
184.1391 + xfprintf(fp, "i %d ", i), count++;
184.1392 + if (row->type == GLP_FR)
184.1393 + xfprintf(fp, "f\n");
184.1394 + else if (row->type == GLP_LO)
184.1395 + xfprintf(fp, "l %.*g\n", DBL_DIG, row->lb);
184.1396 + else if (row->type == GLP_UP)
184.1397 + xfprintf(fp, "u %.*g\n", DBL_DIG, row->ub);
184.1398 + else if (row->type == GLP_DB)
184.1399 + xfprintf(fp, "d %.*g %.*g\n", DBL_DIG, row->lb, DBL_DIG,
184.1400 + row->ub);
184.1401 + else if (row->type == GLP_FX)
184.1402 + xfprintf(fp, "s %.*g\n", DBL_DIG, row->lb);
184.1403 + else
184.1404 + xassert(row != row);
184.1405 +skip1: if (row->name != NULL)
184.1406 + xfprintf(fp, "n i %d %s\n", i, row->name), count++;
184.1407 + }
184.1408 + /* write column descriptors */
184.1409 + for (j = 1; j <= P->n; j++)
184.1410 + { col = P->col[j];
184.1411 + if (!mip && col->type == GLP_LO && col->lb == 0.0)
184.1412 + goto skip2;
184.1413 + if (mip && col->kind == GLP_IV && col->type == GLP_DB &&
184.1414 + col->lb == 0.0 && col->ub == 1.0)
184.1415 + goto skip2;
184.1416 + xfprintf(fp, "j %d ", j), count++;
184.1417 + if (mip)
184.1418 + { if (col->kind == GLP_CV)
184.1419 + xfprintf(fp, "c ");
184.1420 + else if (col->kind == GLP_IV)
184.1421 + xfprintf(fp, "i ");
184.1422 + else
184.1423 + xassert(col != col);
184.1424 + }
184.1425 + if (col->type == GLP_FR)
184.1426 + xfprintf(fp, "f\n");
184.1427 + else if (col->type == GLP_LO)
184.1428 + xfprintf(fp, "l %.*g\n", DBL_DIG, col->lb);
184.1429 + else if (col->type == GLP_UP)
184.1430 + xfprintf(fp, "u %.*g\n", DBL_DIG, col->ub);
184.1431 + else if (col->type == GLP_DB)
184.1432 + xfprintf(fp, "d %.*g %.*g\n", DBL_DIG, col->lb, DBL_DIG,
184.1433 + col->ub);
184.1434 + else if (col->type == GLP_FX)
184.1435 + xfprintf(fp, "s %.*g\n", DBL_DIG, col->lb);
184.1436 + else
184.1437 + xassert(col != col);
184.1438 +skip2: if (col->name != NULL)
184.1439 + xfprintf(fp, "n j %d %s\n", j, col->name), count++;
184.1440 + }
184.1441 + /* write objective coefficient descriptors */
184.1442 + if (P->c0 != 0.0)
184.1443 + xfprintf(fp, "a 0 0 %.*g\n", DBL_DIG, P->c0), count++;
184.1444 + for (j = 1; j <= P->n; j++)
184.1445 + { col = P->col[j];
184.1446 + if (col->coef != 0.0)
184.1447 + xfprintf(fp, "a 0 %d %.*g\n", j, DBL_DIG, col->coef),
184.1448 + count++;
184.1449 + }
184.1450 + /* write constraint coefficient descriptors */
184.1451 + for (i = 1; i <= P->m; i++)
184.1452 + { row = P->row[i];
184.1453 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
184.1454 + xfprintf(fp, "a %d %d %.*g\n", i, aij->col->j, DBL_DIG,
184.1455 + aij->val), count++;
184.1456 + }
184.1457 + /* write end line */
184.1458 + xfprintf(fp, "e o f\n"), count++;
184.1459 + xfflush(fp);
184.1460 + if (xferror(fp))
184.1461 + { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
184.1462 + ret = 1;
184.1463 + goto done;
184.1464 + }
184.1465 + xprintf("%d lines were written\n", count);
184.1466 + ret = 0;
184.1467 +done: if (fp != NULL) xfclose(fp);
184.1468 + return ret;
184.1469 +}
184.1470 +
184.1471 +/* eof */
185.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
185.2 +++ b/src/glpenv.h Mon Dec 06 13:09:21 2010 +0100
185.3 @@ -0,0 +1,228 @@
185.4 +/* glpenv.h (GLPK environment) */
185.5 +
185.6 +/***********************************************************************
185.7 +* This code is part of GLPK (GNU Linear Programming Kit).
185.8 +*
185.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
185.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
185.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
185.12 +* E-mail: <mao@gnu.org>.
185.13 +*
185.14 +* GLPK is free software: you can redistribute it and/or modify it
185.15 +* under the terms of the GNU General Public License as published by
185.16 +* the Free Software Foundation, either version 3 of the License, or
185.17 +* (at your option) any later version.
185.18 +*
185.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
185.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
185.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
185.22 +* License for more details.
185.23 +*
185.24 +* You should have received a copy of the GNU General Public License
185.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
185.26 +***********************************************************************/
185.27 +
185.28 +#ifndef GLPENV_H
185.29 +#define GLPENV_H
185.30 +
185.31 +#include "glpstd.h"
185.32 +#include "glplib.h"
185.33 +
185.34 +typedef struct ENV ENV;
185.35 +typedef struct MEM MEM;
185.36 +typedef struct XFILE XFILE;
185.37 +
185.38 +#define ENV_MAGIC 0x454E5631
185.39 +/* environment block magic value */
185.40 +
185.41 +#define TERM_BUF_SIZE 4096
185.42 +/* terminal output buffer size, in bytes */
185.43 +
185.44 +#define IOERR_MSG_SIZE 1024
185.45 +/* i/o error message buffer size, in bytes */
185.46 +
185.47 +#define MEM_MAGIC 0x4D454D31
185.48 +/* memory block descriptor magic value */
185.49 +
185.50 +struct ENV
185.51 +{ /* environment block */
185.52 + int magic;
185.53 + /* magic value used for debugging */
185.54 + char version[7+1];
185.55 + /* version string returned by the routine glp_version */
185.56 + /*--------------------------------------------------------------*/
185.57 + /* terminal output */
185.58 + char *term_buf; /* char term_buf[TERM_BUF_SIZE]; */
185.59 + /* terminal output buffer */
185.60 + int term_out;
185.61 + /* flag to enable/disable terminal output */
185.62 + int (*term_hook)(void *info, const char *s);
185.63 + /* user-defined routine to intercept terminal output */
185.64 + void *term_info;
185.65 + /* transit pointer (cookie) passed to the routine term_hook */
185.66 + FILE *tee_file;
185.67 + /* output stream used to copy terminal output */
185.68 + /*--------------------------------------------------------------*/
185.69 + /* error handling */
185.70 + const char *err_file;
185.71 + /* value of the __FILE__ macro passed to glp_error */
185.72 + int err_line;
185.73 + /* value of the __LINE__ macro passed to glp_error */
185.74 + void (*err_hook)(void *info);
185.75 + /* user-defined routine to intercept abnormal termination */
185.76 + void *err_info;
185.77 + /* transit pointer (cookie) passed to the routine err_hook */
185.78 + /*--------------------------------------------------------------*/
185.79 + /* memory allocation */
185.80 + glp_long mem_limit;
185.81 + /* maximal amount of memory (in bytes) available for dynamic
185.82 + allocation */
185.83 + MEM *mem_ptr;
185.84 + /* pointer to the linked list of allocated memory blocks */
185.85 + int mem_count;
185.86 + /* total number of currently allocated memory blocks */
185.87 + int mem_cpeak;
185.88 + /* peak value of mem_count */
185.89 + glp_long mem_total;
185.90 + /* total amount of currently allocated memory (in bytes; is the
185.91 + sum of the size field over all memory block descriptors) */
185.92 + glp_long mem_tpeak;
185.93 + /* peak value of mem_total */
185.94 + /*--------------------------------------------------------------*/
185.95 + /* stream input/output */
185.96 + XFILE *file_ptr;
185.97 + /* pointer to the linked list of active stream descriptors */
185.98 + char *ioerr_msg; /* char ioerr_msg[IOERR_MSG_SIZE]; */
185.99 + /* input/output error message buffer */
185.100 + /*--------------------------------------------------------------*/
185.101 + /* shared libraries support */
185.102 + void *h_odbc;
185.103 + /* handle to ODBC shared library */
185.104 + void *h_mysql;
185.105 + /* handle to MySQL shared library */
185.106 +};
185.107 +
185.108 +struct MEM
185.109 +{ /* memory block descriptor */
185.110 + int flag;
185.111 + /* descriptor flag */
185.112 + int size;
185.113 + /* size of block (in bytes, including descriptor) */
185.114 + MEM *prev;
185.115 + /* pointer to previous memory block descriptor */
185.116 + MEM *next;
185.117 + /* pointer to next memory block descriptor */
185.118 +};
185.119 +
185.120 +struct XFILE
185.121 +{ /* input/output stream descriptor */
185.122 + int type;
185.123 + /* stream handle type: */
185.124 +#define FH_FILE 0x11 /* FILE */
185.125 +#define FH_ZLIB 0x22 /* gzFile */
185.126 + void *fh;
185.127 + /* pointer to stream handle */
185.128 + XFILE *prev;
185.129 + /* pointer to previous stream descriptor */
185.130 + XFILE *next;
185.131 + /* pointer to next stream descriptor */
185.132 +};
185.133 +
185.134 +#define XEOF (-1)
185.135 +
185.136 +#define get_env_ptr _glp_get_env_ptr
185.137 +ENV *get_env_ptr(void);
185.138 +/* retrieve pointer to environment block */
185.139 +
185.140 +#define tls_set_ptr _glp_tls_set_ptr
185.141 +void tls_set_ptr(void *ptr);
185.142 +/* store global pointer in TLS */
185.143 +
185.144 +#define tls_get_ptr _glp_tls_get_ptr
185.145 +void *tls_get_ptr(void);
185.146 +/* retrieve global pointer from TLS */
185.147 +
185.148 +#define xprintf glp_printf
185.149 +void glp_printf(const char *fmt, ...);
185.150 +/* write formatted output to the terminal */
185.151 +
185.152 +#define xvprintf glp_vprintf
185.153 +void glp_vprintf(const char *fmt, va_list arg);
185.154 +/* write formatted output to the terminal */
185.155 +
185.156 +#ifndef GLP_ERROR_DEFINED
185.157 +#define GLP_ERROR_DEFINED
185.158 +typedef void (*_glp_error)(const char *fmt, ...);
185.159 +#endif
185.160 +
185.161 +#define xerror glp_error_(__FILE__, __LINE__)
185.162 +_glp_error glp_error_(const char *file, int line);
185.163 +/* display error message and terminate execution */
185.164 +
185.165 +#define xassert(expr) \
185.166 + ((void)((expr) || (glp_assert_(#expr, __FILE__, __LINE__), 1)))
185.167 +void glp_assert_(const char *expr, const char *file, int line);
185.168 +/* check for logical condition */
185.169 +
185.170 +#define xmalloc glp_malloc
185.171 +void *glp_malloc(int size);
185.172 +/* allocate memory block */
185.173 +
185.174 +#define xcalloc glp_calloc
185.175 +void *glp_calloc(int n, int size);
185.176 +/* allocate memory block */
185.177 +
185.178 +#define xfree glp_free
185.179 +void glp_free(void *ptr);
185.180 +/* free memory block */
185.181 +
185.182 +#define xtime glp_time
185.183 +glp_long glp_time(void);
185.184 +/* determine current universal time */
185.185 +
185.186 +#define xdifftime glp_difftime
185.187 +double glp_difftime(glp_long t1, glp_long t0);
185.188 +/* compute difference between two time values, in seconds */
185.189 +
185.190 +#define lib_err_msg _glp_lib_err_msg
185.191 +void lib_err_msg(const char *msg);
185.192 +
185.193 +#define xerrmsg _glp_lib_xerrmsg
185.194 +const char *xerrmsg(void);
185.195 +
185.196 +#define xfopen _glp_lib_xfopen
185.197 +XFILE *xfopen(const char *fname, const char *mode);
185.198 +
185.199 +#define xferror _glp_lib_xferror
185.200 +int xferror(XFILE *file);
185.201 +
185.202 +#define xfeof _glp_lib_xfeof
185.203 +int xfeof(XFILE *file);
185.204 +
185.205 +#define xfgetc _glp_lib_xfgetc
185.206 +int xfgetc(XFILE *file);
185.207 +
185.208 +#define xfputc _glp_lib_xfputc
185.209 +int xfputc(int c, XFILE *file);
185.210 +
185.211 +#define xfflush _glp_lib_xfflush
185.212 +int xfflush(XFILE *fp);
185.213 +
185.214 +#define xfclose _glp_lib_xfclose
185.215 +int xfclose(XFILE *file);
185.216 +
185.217 +#define xfprintf _glp_lib_xfprintf
185.218 +int xfprintf(XFILE *file, const char *fmt, ...);
185.219 +
185.220 +#define xdlopen _glp_xdlopen
185.221 +void *xdlopen(const char *module);
185.222 +
185.223 +#define xdlsym _glp_xdlsym
185.224 +void *xdlsym(void *h, const char *symbol);
185.225 +
185.226 +#define xdlclose _glp_xdlclose
185.227 +void xdlclose(void *h);
185.228 +
185.229 +#endif
185.230 +
185.231 +/* eof */
186.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
186.2 +++ b/src/glpenv01.c Mon Dec 06 13:09:21 2010 +0100
186.3 @@ -0,0 +1,233 @@
186.4 +/* glpenv01.c (environment initialization/termination) */
186.5 +
186.6 +/***********************************************************************
186.7 +* This code is part of GLPK (GNU Linear Programming Kit).
186.8 +*
186.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
186.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
186.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
186.12 +* E-mail: <mao@gnu.org>.
186.13 +*
186.14 +* GLPK is free software: you can redistribute it and/or modify it
186.15 +* under the terms of the GNU General Public License as published by
186.16 +* the Free Software Foundation, either version 3 of the License, or
186.17 +* (at your option) any later version.
186.18 +*
186.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
186.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
186.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
186.22 +* License for more details.
186.23 +*
186.24 +* You should have received a copy of the GNU General Public License
186.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
186.26 +***********************************************************************/
186.27 +
186.28 +#include "glpapi.h"
186.29 +
186.30 +/***********************************************************************
186.31 +* NAME
186.32 +*
186.33 +* glp_init_env - initialize GLPK environment
186.34 +*
186.35 +* SYNOPSIS
186.36 +*
186.37 +* int glp_init_env(void);
186.38 +*
186.39 +* DESCRIPTION
186.40 +*
186.41 +* The routine glp_init_env initializes the GLPK environment. Normally
186.42 +* the application program does not need to call this routine, because
186.43 +* it is called automatically on the first call to any API routine.
186.44 +*
186.45 +* RETURNS
186.46 +*
186.47 +* The routine glp_init_env returns one of the following codes:
186.48 +*
186.49 +* 0 - initialization successful;
186.50 +* 1 - environment has been already initialized;
186.51 +* 2 - initialization failed (insufficient memory);
186.52 +* 3 - initialization failed (unsupported programming model). */
186.53 +
186.54 +int glp_init_env(void)
186.55 +{ ENV *env;
186.56 + int ok;
186.57 + /* check if the programming model is supported */
186.58 + ok = (CHAR_BIT == 8 && sizeof(char) == 1 &&
186.59 + sizeof(short) == 2 && sizeof(int) == 4 &&
186.60 + (sizeof(void *) == 4 || sizeof(void *) == 8));
186.61 + if (!ok) return 3;
186.62 + /* check if the environment is already initialized */
186.63 + if (tls_get_ptr() != NULL) return 1;
186.64 + /* allocate and initialize the environment block */
186.65 + env = malloc(sizeof(ENV));
186.66 + if (env == NULL) return 2;
186.67 + env->magic = ENV_MAGIC;
186.68 + sprintf(env->version, "%d.%d",
186.69 + GLP_MAJOR_VERSION, GLP_MINOR_VERSION);
186.70 + env->term_buf = malloc(TERM_BUF_SIZE);
186.71 + if (env->term_buf == NULL)
186.72 + { free(env);
186.73 + return 2;
186.74 + }
186.75 + env->term_out = GLP_ON;
186.76 + env->term_hook = NULL;
186.77 + env->term_info = NULL;
186.78 + env->tee_file = NULL;
186.79 + env->err_file = "";
186.80 + env->err_line = 0;
186.81 + env->err_hook = NULL;
186.82 + env->err_info = NULL;
186.83 + env->mem_limit.hi = 0x7FFFFFFF, env->mem_limit.lo = 0xFFFFFFFF;
186.84 + env->mem_ptr = NULL;
186.85 + env->mem_count = env->mem_cpeak = 0;
186.86 + env->mem_total = env->mem_tpeak = xlset(0);
186.87 + env->file_ptr = NULL;
186.88 + env->ioerr_msg = malloc(IOERR_MSG_SIZE);
186.89 + if (env->ioerr_msg == NULL)
186.90 + { free(env->term_buf);
186.91 + free(env);
186.92 + return 2;
186.93 + }
186.94 + strcpy(env->ioerr_msg, "No error");
186.95 + env->h_odbc = env->h_mysql = NULL;
186.96 + /* save pointer to the environment block */
186.97 + tls_set_ptr(env);
186.98 + /* initialization successful */
186.99 + return 0;
186.100 +}
186.101 +
186.102 +/***********************************************************************
186.103 +* NAME
186.104 +*
186.105 +* get_env_ptr - retrieve pointer to environment block
186.106 +*
186.107 +* SYNOPSIS
186.108 +*
186.109 +* #include "glpenv.h"
186.110 +* ENV *get_env_ptr(void);
186.111 +*
186.112 +* DESCRIPTION
186.113 +*
186.114 +* The routine get_env_ptr retrieves and returns a pointer to the GLPK
186.115 +* environment block.
186.116 +*
186.117 +* If the GLPK environment has not been initialized yet, the routine
186.118 +* performs initialization. If initialization fails, the routine prints
186.119 +* an error message to stderr and terminates the program.
186.120 +*
186.121 +* RETURNS
186.122 +*
186.123 +* The routine returns a pointer to the environment block. */
186.124 +
186.125 +ENV *get_env_ptr(void)
186.126 +{ ENV *env = tls_get_ptr();
186.127 + /* check if the environment has been initialized */
186.128 + if (env == NULL)
186.129 + { /* not initialized yet; perform initialization */
186.130 + if (glp_init_env() != 0)
186.131 + { /* initialization failed; display an error message */
186.132 + fprintf(stderr, "GLPK initialization failed\n");
186.133 + fflush(stderr);
186.134 + /* and abnormally terminate the program */
186.135 + abort();
186.136 + }
186.137 + /* initialization successful; retrieve the pointer */
186.138 + env = tls_get_ptr();
186.139 + }
186.140 + /* check if the environment block is valid */
186.141 + if (env->magic != ENV_MAGIC)
186.142 + { fprintf(stderr, "Invalid GLPK environment\n");
186.143 + fflush(stderr);
186.144 + abort();
186.145 + }
186.146 + return env;
186.147 +}
186.148 +
186.149 +/***********************************************************************
186.150 +* NAME
186.151 +*
186.152 +* glp_version - determine library version
186.153 +*
186.154 +* SYNOPSIS
186.155 +*
186.156 +* const char *glp_version(void);
186.157 +*
186.158 +* RETURNS
186.159 +*
186.160 +* The routine glp_version returns a pointer to a null-terminated
186.161 +* character string, which specifies the version of the GLPK library in
186.162 +* the form "X.Y", where X is the major version number, and Y is the
186.163 +* minor version number, for example, "4.16". */
186.164 +
186.165 +const char *glp_version(void)
186.166 +{ ENV *env = get_env_ptr();
186.167 + return env->version;
186.168 +}
186.169 +
186.170 +/***********************************************************************
186.171 +* NAME
186.172 +*
186.173 +* glp_free_env - free GLPK environment
186.174 +*
186.175 +* SYNOPSIS
186.176 +*
186.177 +* int glp_free_env(void);
186.178 +*
186.179 +* DESCRIPTION
186.180 +*
186.181 +* The routine glp_free_env frees all resources used by GLPK routines
186.182 +* (memory blocks, etc.) which are currently still in use.
186.183 +*
186.184 +* Normally the application program does not need to call this routine,
186.185 +* because GLPK routines always free all unused resources. However, if
186.186 +* the application program even has deleted all problem objects, there
186.187 +* will be several memory blocks still allocated for the library needs.
186.188 +* For some reasons the application program may want GLPK to free this
186.189 +* memory, in which case it should call glp_free_env.
186.190 +*
186.191 +* Note that a call to glp_free_env invalidates all problem objects as
186.192 +* if no GLPK routine were called.
186.193 +*
186.194 +* RETURNS
186.195 +*
186.196 +* 0 - termination successful;
186.197 +* 1 - environment is inactive (was not initialized). */
186.198 +
186.199 +int glp_free_env(void)
186.200 +{ ENV *env = tls_get_ptr();
186.201 + MEM *desc;
186.202 + /* check if the environment is active */
186.203 + if (env == NULL) return 1;
186.204 + /* check if the environment block is valid */
186.205 + if (env->magic != ENV_MAGIC)
186.206 + { fprintf(stderr, "Invalid GLPK environment\n");
186.207 + fflush(stderr);
186.208 + abort();
186.209 + }
186.210 + /* close handles to shared libraries */
186.211 + if (env->h_odbc != NULL)
186.212 + xdlclose(env->h_odbc);
186.213 + if (env->h_mysql != NULL)
186.214 + xdlclose(env->h_mysql);
186.215 + /* close streams which are still open */
186.216 + while (env->file_ptr != NULL)
186.217 + xfclose(env->file_ptr);
186.218 + /* free memory blocks which are still allocated */
186.219 + while (env->mem_ptr != NULL)
186.220 + { desc = env->mem_ptr;
186.221 + env->mem_ptr = desc->next;
186.222 + free(desc);
186.223 + }
186.224 + /* invalidate the environment block */
186.225 + env->magic = -1;
186.226 + /* free memory allocated to the environment block */
186.227 + free(env->term_buf);
186.228 + free(env->ioerr_msg);
186.229 + free(env);
186.230 + /* reset a pointer to the environment block */
186.231 + tls_set_ptr(NULL);
186.232 + /* termination successful */
186.233 + return 0;
186.234 +}
186.235 +
186.236 +/* eof */
187.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
187.2 +++ b/src/glpenv02.c Mon Dec 06 13:09:21 2010 +0100
187.3 @@ -0,0 +1,73 @@
187.4 +/* glpenv02.c (thread local storage) */
187.5 +
187.6 +/***********************************************************************
187.7 +* This code is part of GLPK (GNU Linear Programming Kit).
187.8 +*
187.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
187.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
187.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
187.12 +* E-mail: <mao@gnu.org>.
187.13 +*
187.14 +* GLPK is free software: you can redistribute it and/or modify it
187.15 +* under the terms of the GNU General Public License as published by
187.16 +* the Free Software Foundation, either version 3 of the License, or
187.17 +* (at your option) any later version.
187.18 +*
187.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
187.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
187.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
187.22 +* License for more details.
187.23 +*
187.24 +* You should have received a copy of the GNU General Public License
187.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
187.26 +***********************************************************************/
187.27 +
187.28 +#include "glpenv.h"
187.29 +
187.30 +static void *tls = NULL;
187.31 +/* in a re-entrant version of the package this variable must be placed
187.32 + in the Thread Local Storage (TLS) */
187.33 +
187.34 +/***********************************************************************
187.35 +* NAME
187.36 +*
187.37 +* tls_set_ptr - store global pointer in TLS
187.38 +*
187.39 +* SYNOPSIS
187.40 +*
187.41 +* #include "glpenv.h"
187.42 +* void tls_set_ptr(void *ptr);
187.43 +*
187.44 +* DESCRIPTION
187.45 +*
187.46 +* The routine tls_set_ptr stores a pointer specified by the parameter
187.47 +* ptr in the Thread Local Storage (TLS). */
187.48 +
187.49 +void tls_set_ptr(void *ptr)
187.50 +{ tls = ptr;
187.51 + return;
187.52 +}
187.53 +
187.54 +/***********************************************************************
187.55 +* NAME
187.56 +*
187.57 +* tls_get_ptr - retrieve global pointer from TLS
187.58 +*
187.59 +* SYNOPSIS
187.60 +*
187.61 +* #include "glpenv.h"
187.62 +* void *tls_get_ptr(void);
187.63 +*
187.64 +* RETURNS
187.65 +*
187.66 +* The routine tls_get_ptr returns a pointer previously stored by the
187.67 +* routine tls_set_ptr. If the latter has not been called yet, NULL is
187.68 +* returned. */
187.69 +
187.70 +void *tls_get_ptr(void)
187.71 +{ void *ptr;
187.72 + ptr = tls;
187.73 + return ptr;
187.74 +}
187.75 +
187.76 +/* eof */
188.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
188.2 +++ b/src/glpenv03.c Mon Dec 06 13:09:21 2010 +0100
188.3 @@ -0,0 +1,228 @@
188.4 +/* glpenv03.c (terminal output) */
188.5 +
188.6 +/***********************************************************************
188.7 +* This code is part of GLPK (GNU Linear Programming Kit).
188.8 +*
188.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
188.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
188.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
188.12 +* E-mail: <mao@gnu.org>.
188.13 +*
188.14 +* GLPK is free software: you can redistribute it and/or modify it
188.15 +* under the terms of the GNU General Public License as published by
188.16 +* the Free Software Foundation, either version 3 of the License, or
188.17 +* (at your option) any later version.
188.18 +*
188.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
188.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
188.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
188.22 +* License for more details.
188.23 +*
188.24 +* You should have received a copy of the GNU General Public License
188.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
188.26 +***********************************************************************/
188.27 +
188.28 +#include "glpapi.h"
188.29 +
188.30 +/***********************************************************************
188.31 +* NAME
188.32 +*
188.33 +* glp_printf - write formatted output to terminal
188.34 +*
188.35 +* SYNOPSIS
188.36 +*
188.37 +* void glp_printf(const char *fmt, ...);
188.38 +*
188.39 +* DESCRIPTION
188.40 +*
188.41 +* The routine glp_printf uses the format control string fmt to format
188.42 +* its parameters and writes the formatted output to the terminal. */
188.43 +
188.44 +void glp_printf(const char *fmt, ...)
188.45 +{ va_list arg;
188.46 + va_start(arg, fmt);
188.47 + xvprintf(fmt, arg);
188.48 + va_end(arg);
188.49 + return;
188.50 +}
188.51 +
188.52 +/***********************************************************************
188.53 +* NAME
188.54 +*
188.55 +* glp_vprintf - write formatted output to terminal
188.56 +*
188.57 +* SYNOPSIS
188.58 +*
188.59 +* void glp_vprintf(const char *fmt, va_list arg);
188.60 +*
188.61 +* DESCRIPTION
188.62 +*
188.63 +* The routine glp_vprintf uses the format control string fmt to format
188.64 +* its parameters specified by the list arg and writes the formatted
188.65 +* output to the terminal. */
188.66 +
188.67 +void glp_vprintf(const char *fmt, va_list arg)
188.68 +{ ENV *env = get_env_ptr();
188.69 + /* if terminal output is disabled, do nothing */
188.70 + if (!env->term_out) goto skip;
188.71 + /* format the output */
188.72 + vsprintf(env->term_buf, fmt, arg);
188.73 + /* pass the output to the user-defined routine */
188.74 + if (env->term_hook != NULL)
188.75 + { if (env->term_hook(env->term_info, env->term_buf) != 0)
188.76 + goto skip;
188.77 + }
188.78 + /* send the output to the terminal */
188.79 + fputs(env->term_buf, stdout);
188.80 + fflush(stdout);
188.81 + /* copy the output to the text file */
188.82 + if (env->tee_file != NULL)
188.83 + { fputs(env->term_buf, env->tee_file);
188.84 + fflush(env->tee_file);
188.85 + }
188.86 +skip: return;
188.87 +}
188.88 +
188.89 +/***********************************************************************
188.90 +* NAME
188.91 +*
188.92 +* glp_term_out - enable/disable terminal output
188.93 +*
188.94 +* SYNOPSIS
188.95 +*
188.96 +* int glp_term_out(int flag);
188.97 +*
188.98 +* DESCRIPTION
188.99 +*
188.100 +* Depending on the parameter flag the routine glp_term_out enables or
188.101 +* disables terminal output performed by glpk routines:
188.102 +*
188.103 +* GLP_ON - enable terminal output;
188.104 +* GLP_OFF - disable terminal output.
188.105 +*
188.106 +* RETURNS
188.107 +*
188.108 +* The routine glp_term_out returns the previous value of the terminal
188.109 +* output flag. */
188.110 +
188.111 +int glp_term_out(int flag)
188.112 +{ ENV *env = get_env_ptr();
188.113 + int old = env->term_out;
188.114 + if (!(flag == GLP_ON || flag == GLP_OFF))
188.115 + xerror("glp_term_out: flag = %d; invalid value\n", flag);
188.116 + env->term_out = flag;
188.117 + return old;
188.118 +}
188.119 +
188.120 +/***********************************************************************
188.121 +* NAME
188.122 +*
188.123 +* glp_term_hook - install hook to intercept terminal output
188.124 +*
188.125 +* SYNOPSIS
188.126 +*
188.127 +* void glp_term_hook(int (*func)(void *info, const char *s),
188.128 +* void *info);
188.129 +*
188.130 +* DESCRIPTION
188.131 +*
188.132 +* The routine glp_term_hook installs a user-defined hook routine to
188.133 +* intercept all terminal output performed by glpk routines.
188.134 +*
188.135 +* This feature can be used to redirect the terminal output to other
188.136 +* destination, for example to a file or a text window.
188.137 +*
188.138 +* The parameter func specifies the user-defined hook routine. It is
188.139 +* called from an internal printing routine, which passes to it two
188.140 +* parameters: info and s. The parameter info is a transit pointer,
188.141 +* specified in the corresponding call to the routine glp_term_hook;
188.142 +* it may be used to pass some information to the hook routine. The
188.143 +* parameter s is a pointer to the null terminated character string,
188.144 +* which is intended to be written to the terminal. If the hook routine
188.145 +* returns zero, the printing routine writes the string s to the
188.146 +* terminal in a usual way; otherwise, if the hook routine returns
188.147 +* non-zero, no terminal output is performed.
188.148 +*
188.149 +* To uninstall the hook routine the parameters func and info should be
188.150 +* specified as NULL. */
188.151 +
188.152 +void glp_term_hook(int (*func)(void *info, const char *s), void *info)
188.153 +{ ENV *env = get_env_ptr();
188.154 + if (func == NULL)
188.155 + { env->term_hook = NULL;
188.156 + env->term_info = NULL;
188.157 + }
188.158 + else
188.159 + { env->term_hook = func;
188.160 + env->term_info = info;
188.161 + }
188.162 + return;
188.163 +}
188.164 +
188.165 +/***********************************************************************
188.166 +* NAME
188.167 +*
188.168 +* glp_open_tee - start copying terminal output to text file
188.169 +*
188.170 +* SYNOPSIS
188.171 +*
188.172 +* int glp_open_tee(const char *fname);
188.173 +*
188.174 +* DESCRIPTION
188.175 +*
188.176 +* The routine glp_open_tee starts copying all the terminal output to
188.177 +* an output text file, whose name is specified by the character string
188.178 +* fname.
188.179 +*
188.180 +* RETURNS
188.181 +*
188.182 +* 0 - operation successful
188.183 +* 1 - copying terminal output is already active
188.184 +* 2 - unable to create output file */
188.185 +
188.186 +int glp_open_tee(const char *fname)
188.187 +{ ENV *env = get_env_ptr();
188.188 + if (env->tee_file != NULL)
188.189 + { /* copying terminal output is already active */
188.190 + return 1;
188.191 + }
188.192 + env->tee_file = fopen(fname, "w");
188.193 + if (env->tee_file == NULL)
188.194 + { /* unable to create output file */
188.195 + return 2;
188.196 + }
188.197 + return 0;
188.198 +}
188.199 +
188.200 +/***********************************************************************
188.201 +* NAME
188.202 +*
188.203 +* glp_close_tee - stop copying terminal output to text file
188.204 +*
188.205 +* SYNOPSIS
188.206 +*
188.207 +* int glp_close_tee(void);
188.208 +*
188.209 +* DESCRIPTION
188.210 +*
188.211 +* The routine glp_close_tee stops copying the terminal output to the
188.212 +* output text file previously open by the routine glp_open_tee closing
188.213 +* that file.
188.214 +*
188.215 +* RETURNS
188.216 +*
188.217 +* 0 - operation successful
188.218 +* 1 - copying terminal output was not started */
188.219 +
188.220 +int glp_close_tee(void)
188.221 +{ ENV *env = get_env_ptr();
188.222 + if (env->tee_file == NULL)
188.223 + { /* copying terminal output was not started */
188.224 + return 1;
188.225 + }
188.226 + fclose(env->tee_file);
188.227 + env->tee_file = NULL;
188.228 + return 0;
188.229 +}
188.230 +
188.231 +/* eof */
189.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
189.2 +++ b/src/glpenv04.c Mon Dec 06 13:09:21 2010 +0100
189.3 @@ -0,0 +1,124 @@
189.4 +/* glpenv04.c (error handling) */
189.5 +
189.6 +/***********************************************************************
189.7 +* This code is part of GLPK (GNU Linear Programming Kit).
189.8 +*
189.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
189.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
189.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
189.12 +* E-mail: <mao@gnu.org>.
189.13 +*
189.14 +* GLPK is free software: you can redistribute it and/or modify it
189.15 +* under the terms of the GNU General Public License as published by
189.16 +* the Free Software Foundation, either version 3 of the License, or
189.17 +* (at your option) any later version.
189.18 +*
189.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
189.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
189.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
189.22 +* License for more details.
189.23 +*
189.24 +* You should have received a copy of the GNU General Public License
189.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
189.26 +***********************************************************************/
189.27 +
189.28 +#include "glpapi.h"
189.29 +
189.30 +/***********************************************************************
189.31 +* NAME
189.32 +*
189.33 +* glp_error - display error message and terminate execution
189.34 +*
189.35 +* SYNOPSIS
189.36 +*
189.37 +* void glp_error(const char *fmt, ...);
189.38 +*
189.39 +* DESCRIPTION
189.40 +*
189.41 +* The routine glp_error (implemented as a macro) formats its
189.42 +* parameters using the format control string fmt, writes the formatted
189.43 +* message to the terminal, and abnormally terminates the program. */
189.44 +
189.45 +static void error(const char *fmt, ...)
189.46 +{ ENV *env = get_env_ptr();
189.47 + va_list arg;
189.48 + env->term_out = GLP_ON;
189.49 + va_start(arg, fmt);
189.50 + xvprintf(fmt, arg);
189.51 + va_end(arg);
189.52 + xprintf("Error detected in file %s at line %d\n", env->err_file,
189.53 + env->err_line);
189.54 + if (env->err_hook != NULL)
189.55 + env->err_hook(env->err_info);
189.56 + abort();
189.57 + exit(EXIT_FAILURE);
189.58 + /* no return */
189.59 +}
189.60 +
189.61 +_glp_error glp_error_(const char *file, int line)
189.62 +{ ENV *env = get_env_ptr();
189.63 + env->err_file = file;
189.64 + env->err_line = line;
189.65 + return error;
189.66 +}
189.67 +
189.68 +/***********************************************************************
189.69 +* NAME
189.70 +*
189.71 +* glp_assert - check for logical condition
189.72 +*
189.73 +* SYNOPSIS
189.74 +*
189.75 +* #include "glplib.h"
189.76 +* void glp_assert(int expr);
189.77 +*
189.78 +* DESCRIPTION
189.79 +*
189.80 +* The routine glp_assert (implemented as a macro) checks for a logical
189.81 +* condition specified by the parameter expr. If the condition is false
189.82 +* (i.e. the value of expr is zero), the routine writes a message to
189.83 +* the terminal and abnormally terminates the program. */
189.84 +
189.85 +void glp_assert_(const char *expr, const char *file, int line)
189.86 +{ glp_error_(file, line)("Assertion failed: %s\n", expr);
189.87 + /* no return */
189.88 +}
189.89 +
189.90 +/***********************************************************************
189.91 +* NAME
189.92 +*
189.93 +* glp_error_hook - install hook to intercept abnormal termination
189.94 +*
189.95 +* SYNOPSIS
189.96 +*
189.97 +* void glp_error_hook(void (*func)(void *info), void *info);
189.98 +*
189.99 +* DESCRIPTION
189.100 +*
189.101 +* The routine glp_error_hook installs a user-defined hook routine to
189.102 +* intercept abnormal termination.
189.103 +*
189.104 +* The parameter func specifies the user-defined hook routine. It is
189.105 +* called from the routine glp_error before the latter calls the abort
189.106 +* function to abnormally terminate the application program because of
189.107 +* fatal error. The parameter info is a transit pointer, specified in
189.108 +* the corresponding call to the routine glp_error_hook; it may be used
189.109 +* to pass some information to the hook routine.
189.110 +*
189.111 +* To uninstall the hook routine the parameters func and info should be
189.112 +* specified as NULL. */
189.113 +
189.114 +void glp_error_hook(void (*func)(void *info), void *info)
189.115 +{ ENV *env = get_env_ptr();
189.116 + if (func == NULL)
189.117 + { env->err_hook = NULL;
189.118 + env->err_info = NULL;
189.119 + }
189.120 + else
189.121 + { env->err_hook = func;
189.122 + env->err_info = info;
189.123 + }
189.124 + return;
189.125 +}
189.126 +
189.127 +/* eof */
190.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
190.2 +++ b/src/glpenv05.c Mon Dec 06 13:09:21 2010 +0100
190.3 @@ -0,0 +1,225 @@
190.4 +/* glpenv05.c (memory allocation) */
190.5 +
190.6 +/***********************************************************************
190.7 +* This code is part of GLPK (GNU Linear Programming Kit).
190.8 +*
190.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
190.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
190.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
190.12 +* E-mail: <mao@gnu.org>.
190.13 +*
190.14 +* GLPK is free software: you can redistribute it and/or modify it
190.15 +* under the terms of the GNU General Public License as published by
190.16 +* the Free Software Foundation, either version 3 of the License, or
190.17 +* (at your option) any later version.
190.18 +*
190.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
190.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
190.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
190.22 +* License for more details.
190.23 +*
190.24 +* You should have received a copy of the GNU General Public License
190.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
190.26 +***********************************************************************/
190.27 +
190.28 +#include "glpapi.h"
190.29 +
190.30 +/* some processors need data to be properly aligned; the macro
190.31 + align_datasize enlarges the specified size of a data item to provide
190.32 + a proper alignment of immediately following data */
190.33 +
190.34 +#define align_datasize(size) ((((size) + 15) / 16) * 16)
190.35 +/* 16 bytes is sufficient in both 32- and 64-bit environments
190.36 + (8 bytes is not sufficient in 64-bit environment due to jmp_buf) */
190.37 +
190.38 +/***********************************************************************
190.39 +* NAME
190.40 +*
190.41 +* glp_malloc - allocate memory block
190.42 +*
190.43 +* SYNOPSIS
190.44 +*
190.45 +* void *glp_malloc(int size);
190.46 +*
190.47 +* DESCRIPTION
190.48 +*
190.49 +* The routine glp_malloc allocates a memory block of size bytes long.
190.50 +*
190.51 +* Note that being allocated the memory block contains arbitrary data
190.52 +* (not binary zeros).
190.53 +*
190.54 +* RETURNS
190.55 +*
190.56 +* The routine glp_malloc returns a pointer to the allocated block.
190.57 +* To free this block the routine glp_free (not free!) must be used. */
190.58 +
190.59 +void *glp_malloc(int size)
190.60 +{ ENV *env = get_env_ptr();
190.61 + MEM *desc;
190.62 + int size_of_desc = align_datasize(sizeof(MEM));
190.63 + if (size < 1 || size > INT_MAX - size_of_desc)
190.64 + xerror("glp_malloc: size = %d; invalid parameter\n", size);
190.65 + size += size_of_desc;
190.66 + if (xlcmp(xlset(size),
190.67 + xlsub(env->mem_limit, env->mem_total)) > 0)
190.68 + xerror("glp_malloc: memory limit exceeded\n");
190.69 + if (env->mem_count == INT_MAX)
190.70 + xerror("glp_malloc: too many memory blocks allocated\n");
190.71 + desc = malloc(size);
190.72 + if (desc == NULL)
190.73 + xerror("glp_malloc: no memory available\n");
190.74 + memset(desc, '?', size);
190.75 + desc->flag = MEM_MAGIC;
190.76 + desc->size = size;
190.77 + desc->prev = NULL;
190.78 + desc->next = env->mem_ptr;
190.79 + if (desc->next != NULL) desc->next->prev = desc;
190.80 + env->mem_ptr = desc;
190.81 + env->mem_count++;
190.82 + if (env->mem_cpeak < env->mem_count)
190.83 + env->mem_cpeak = env->mem_count;
190.84 + env->mem_total = xladd(env->mem_total, xlset(size));
190.85 + if (xlcmp(env->mem_tpeak, env->mem_total) < 0)
190.86 + env->mem_tpeak = env->mem_total;
190.87 + return (void *)((char *)desc + size_of_desc);
190.88 +}
190.89 +
190.90 +/***********************************************************************
190.91 +* NAME
190.92 +*
190.93 +* glp_calloc - allocate memory block
190.94 +*
190.95 +* SYNOPSIS
190.96 +*
190.97 +* void *glp_calloc(int n, int size);
190.98 +*
190.99 +* DESCRIPTION
190.100 +*
190.101 +* The routine glp_calloc allocates a memory block of (n*size) bytes
190.102 +* long.
190.103 +*
190.104 +* Note that being allocated the memory block contains arbitrary data
190.105 +* (not binary zeros).
190.106 +*
190.107 +* RETURNS
190.108 +*
190.109 +* The routine glp_calloc returns a pointer to the allocated block.
190.110 +* To free this block the routine glp_free (not free!) must be used. */
190.111 +
190.112 +void *glp_calloc(int n, int size)
190.113 +{ if (n < 1)
190.114 + xerror("glp_calloc: n = %d; invalid parameter\n", n);
190.115 + if (size < 1)
190.116 + xerror("glp_calloc: size = %d; invalid parameter\n", size);
190.117 + if (n > INT_MAX / size)
190.118 + xerror("glp_calloc: n = %d; size = %d; array too big\n", n,
190.119 + size);
190.120 + return xmalloc(n * size);
190.121 +}
190.122 +
190.123 +/***********************************************************************
190.124 +* NAME
190.125 +*
190.126 +* glp_free - free memory block
190.127 +*
190.128 +* SYNOPSIS
190.129 +*
190.130 +* void glp_free(void *ptr);
190.131 +*
190.132 +* DESCRIPTION
190.133 +*
190.134 +* The routine glp_free frees a memory block pointed to by ptr, which
190.135 +* was previuosly allocated by the routine glp_malloc or glp_calloc. */
190.136 +
190.137 +void glp_free(void *ptr)
190.138 +{ ENV *env = get_env_ptr();
190.139 + MEM *desc;
190.140 + int size_of_desc = align_datasize(sizeof(MEM));
190.141 + if (ptr == NULL)
190.142 + xerror("glp_free: ptr = %p; null pointer\n", ptr);
190.143 + desc = (void *)((char *)ptr - size_of_desc);
190.144 + if (desc->flag != MEM_MAGIC)
190.145 + xerror("glp_free: ptr = %p; invalid pointer\n", ptr);
190.146 + if (env->mem_count == 0 ||
190.147 + xlcmp(env->mem_total, xlset(desc->size)) < 0)
190.148 + xerror("glp_free: memory allocation error\n");
190.149 + if (desc->prev == NULL)
190.150 + env->mem_ptr = desc->next;
190.151 + else
190.152 + desc->prev->next = desc->next;
190.153 + if (desc->next == NULL)
190.154 + ;
190.155 + else
190.156 + desc->next->prev = desc->prev;
190.157 + env->mem_count--;
190.158 + env->mem_total = xlsub(env->mem_total, xlset(desc->size));
190.159 + memset(desc, '?', size_of_desc);
190.160 + free(desc);
190.161 + return;
190.162 +}
190.163 +
190.164 +/***********************************************************************
190.165 +* NAME
190.166 +*
190.167 +* glp_mem_limit - set memory usage limit
190.168 +*
190.169 +* SYNOPSIS
190.170 +*
190.171 +* void glp_mem_limit(int limit);
190.172 +*
190.173 +* DESCRIPTION
190.174 +*
190.175 +* The routine glp_mem_limit limits the amount of memory available for
190.176 +* dynamic allocation (in GLPK routines) to limit megabytes. */
190.177 +
190.178 +void glp_mem_limit(int limit)
190.179 +{ ENV *env = get_env_ptr();
190.180 + if (limit < 0)
190.181 + xerror("glp_mem_limit: limit = %d; invalid parameter\n",
190.182 + limit);
190.183 + env->mem_limit = xlmul(xlset(limit), xlset(1 << 20));
190.184 + return;
190.185 +}
190.186 +
190.187 +/***********************************************************************
190.188 +* NAME
190.189 +*
190.190 +* glp_mem_usage - get memory usage information
190.191 +*
190.192 +* SYNOPSIS
190.193 +*
190.194 +* void glp_mem_usage(int *count, int *cpeak, glp_long *total,
190.195 +* glp_long *tpeak);
190.196 +*
190.197 +* DESCRIPTION
190.198 +*
190.199 +* The routine glp_mem_usage reports some information about utilization
190.200 +* of the memory by GLPK routines. Information is stored to locations
190.201 +* specified by corresponding parameters (see below). Any parameter can
190.202 +* be specified as NULL, in which case corresponding information is not
190.203 +* stored.
190.204 +*
190.205 +* *count is the number of the memory blocks currently allocated by the
190.206 +* routines xmalloc and xcalloc (one call to xmalloc or xcalloc results
190.207 +* in allocating one memory block).
190.208 +*
190.209 +* *cpeak is the peak value of *count reached since the initialization
190.210 +* of the GLPK library environment.
190.211 +*
190.212 +* *total is the total amount, in bytes, of the memory blocks currently
190.213 +* allocated by the routines xmalloc and xcalloc.
190.214 +*
190.215 +* *tpeak is the peak value of *total reached since the initialization
190.216 +* of the GLPK library envirionment. */
190.217 +
190.218 +void glp_mem_usage(int *count, int *cpeak, glp_long *total,
190.219 + glp_long *tpeak)
190.220 +{ ENV *env = get_env_ptr();
190.221 + if (count != NULL) *count = env->mem_count;
190.222 + if (cpeak != NULL) *cpeak = env->mem_cpeak;
190.223 + if (total != NULL) *total = env->mem_total;
190.224 + if (tpeak != NULL) *tpeak = env->mem_tpeak;
190.225 + return;
190.226 +}
190.227 +
190.228 +/* eof */
191.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
191.2 +++ b/src/glpenv06.c Mon Dec 06 13:09:21 2010 +0100
191.3 @@ -0,0 +1,172 @@
191.4 +/* glpenv06.c (standard time) */
191.5 +
191.6 +/***********************************************************************
191.7 +* This code is part of GLPK (GNU Linear Programming Kit).
191.8 +*
191.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
191.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
191.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
191.12 +* E-mail: <mao@gnu.org>.
191.13 +*
191.14 +* GLPK is free software: you can redistribute it and/or modify it
191.15 +* under the terms of the GNU General Public License as published by
191.16 +* the Free Software Foundation, either version 3 of the License, or
191.17 +* (at your option) any later version.
191.18 +*
191.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
191.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
191.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
191.22 +* License for more details.
191.23 +*
191.24 +* You should have received a copy of the GNU General Public License
191.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
191.26 +***********************************************************************/
191.27 +
191.28 +#ifdef HAVE_CONFIG_H
191.29 +#include <config.h>
191.30 +#endif
191.31 +
191.32 +#include "glpapi.h"
191.33 +
191.34 +/***********************************************************************
191.35 +* NAME
191.36 +*
191.37 +* glp_time - determine current universal time
191.38 +*
191.39 +* SYNOPSIS
191.40 +*
191.41 +* glp_long glp_time(void);
191.42 +*
191.43 +* RETURNS
191.44 +*
191.45 +* The routine glp_time returns the current universal time (UTC), in
191.46 +* milliseconds, elapsed since 00:00:00 GMT January 1, 1970. */
191.47 +
191.48 +static const int epoch = 2440588; /* = jday(1, 1, 1970) */
191.49 +
191.50 +/* POSIX version ******************************************************/
191.51 +
191.52 +#if defined(HAVE_SYS_TIME_H) && defined(HAVE_GETTIMEOFDAY)
191.53 +
191.54 +#include <sys/time.h>
191.55 +#include <time.h>
191.56 +
191.57 +glp_long glp_time(void)
191.58 +{ struct timeval tv;
191.59 + struct tm *tm;
191.60 + glp_long t;
191.61 + int j;
191.62 + gettimeofday(&tv, NULL);
191.63 + tm = gmtime(&tv.tv_sec);
191.64 + j = jday(tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
191.65 + xassert(j >= 0);
191.66 + t = xlset(j - epoch);
191.67 + t = xlmul(t, xlset(24));
191.68 + t = xladd(t, xlset(tm->tm_hour));
191.69 + t = xlmul(t, xlset(60));
191.70 + t = xladd(t, xlset(tm->tm_min));
191.71 + t = xlmul(t, xlset(60));
191.72 + t = xladd(t, xlset(tm->tm_sec));
191.73 + t = xlmul(t, xlset(1000));
191.74 + t = xladd(t, xlset(tv.tv_usec / 1000));
191.75 + return t;
191.76 +}
191.77 +
191.78 +/* Windows version ****************************************************/
191.79 +
191.80 +#elif defined(__WOE__)
191.81 +
191.82 +#include <windows.h>
191.83 +
191.84 +glp_long glp_time(void)
191.85 +{ SYSTEMTIME st;
191.86 + glp_long t;
191.87 + int j;
191.88 + GetSystemTime(&st);
191.89 + j = jday(st.wDay, st.wMonth, st.wYear);
191.90 + xassert(j >= 0);
191.91 + t = xlset(j - epoch);
191.92 + t = xlmul(t, xlset(24));
191.93 + t = xladd(t, xlset(st.wHour));
191.94 + t = xlmul(t, xlset(60));
191.95 + t = xladd(t, xlset(st.wMinute));
191.96 + t = xlmul(t, xlset(60));
191.97 + t = xladd(t, xlset(st.wSecond));
191.98 + t = xlmul(t, xlset(1000));
191.99 + t = xladd(t, xlset(st.wMilliseconds));
191.100 + return t;
191.101 +}
191.102 +
191.103 +/* portable ISO C version *********************************************/
191.104 +
191.105 +#else
191.106 +
191.107 +#include <time.h>
191.108 +
191.109 +glp_long glp_time(void)
191.110 +{ time_t timer;
191.111 + struct tm *tm;
191.112 + glp_long t;
191.113 + int j;
191.114 + timer = time(NULL);
191.115 + tm = gmtime(&timer);
191.116 + j = jday(tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
191.117 + xassert(j >= 0);
191.118 + t = xlset(j - epoch);
191.119 + t = xlmul(t, xlset(24));
191.120 + t = xladd(t, xlset(tm->tm_hour));
191.121 + t = xlmul(t, xlset(60));
191.122 + t = xladd(t, xlset(tm->tm_min));
191.123 + t = xlmul(t, xlset(60));
191.124 + t = xladd(t, xlset(tm->tm_sec));
191.125 + t = xlmul(t, xlset(1000));
191.126 + return t;
191.127 +}
191.128 +
191.129 +#endif
191.130 +
191.131 +/***********************************************************************
191.132 +* NAME
191.133 +*
191.134 +* glp_difftime - compute difference between two time values
191.135 +*
191.136 +* SYNOPSIS
191.137 +*
191.138 +* double glp_difftime(glp_long t1, glp_long t0);
191.139 +*
191.140 +* RETURNS
191.141 +*
191.142 +* The routine glp_difftime returns the difference between two time
191.143 +* values t1 and t0, expressed in seconds. */
191.144 +
191.145 +double glp_difftime(glp_long t1, glp_long t0)
191.146 +{ return
191.147 + xltod(xlsub(t1, t0)) / 1000.0;
191.148 +}
191.149 +
191.150 +/**********************************************************************/
191.151 +
191.152 +#if 0
191.153 +int main(void)
191.154 +{ glp_long t;
191.155 + glp_ldiv d;
191.156 + int ttt, ss, mm, hh, day, month, year;
191.157 + char s[50];
191.158 + t = glp_time();
191.159 + xprintf("t = %s\n", xltoa(t, s));
191.160 + d = xldiv(t, xlset(1000));
191.161 + ttt = d.rem.lo, t = d.quot;
191.162 + d = xldiv(t, xlset(60));
191.163 + ss = d.rem.lo, t = d.quot;
191.164 + d = xldiv(t, xlset(60));
191.165 + mm = d.rem.lo, t = d.quot;
191.166 + d = xldiv(t, xlset(24));
191.167 + hh = d.rem.lo, t = d.quot;
191.168 + xassert(jdate(t.lo + epoch, &day, &month, &year) == 0);
191.169 + xprintf("%04d-%02d-%02d %02d:%02d:%02d.%03d\n", year, month, day,
191.170 + hh, mm, ss, ttt);
191.171 + return 0;
191.172 +}
191.173 +#endif
191.174 +
191.175 +/* eof */
192.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
192.2 +++ b/src/glpenv07.c Mon Dec 06 13:09:21 2010 +0100
192.3 @@ -0,0 +1,671 @@
192.4 +/* glpenv07.c (stream input/output) */
192.5 +
192.6 +/***********************************************************************
192.7 +* This code is part of GLPK (GNU Linear Programming Kit).
192.8 +*
192.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
192.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
192.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
192.12 +* E-mail: <mao@gnu.org>.
192.13 +*
192.14 +* GLPK is free software: you can redistribute it and/or modify it
192.15 +* under the terms of the GNU General Public License as published by
192.16 +* the Free Software Foundation, either version 3 of the License, or
192.17 +* (at your option) any later version.
192.18 +*
192.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
192.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
192.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
192.22 +* License for more details.
192.23 +*
192.24 +* You should have received a copy of the GNU General Public License
192.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
192.26 +***********************************************************************/
192.27 +
192.28 +#ifdef HAVE_CONFIG_H
192.29 +#include <config.h>
192.30 +#endif
192.31 +
192.32 +#include "glpenv.h"
192.33 +
192.34 +/***********************************************************************
192.35 +* NAME
192.36 +*
192.37 +* lib_err_msg - save error message string
192.38 +*
192.39 +* SYNOPSIS
192.40 +*
192.41 +* #include "glpenv.h"
192.42 +* void lib_err_msg(const char *msg);
192.43 +*
192.44 +* DESCRIPTION
192.45 +*
192.46 +* The routine lib_err_msg saves an error message string specified by
192.47 +* the parameter msg. The message is obtained by some library routines
192.48 +* with a call to strerror(errno). */
192.49 +
192.50 +void lib_err_msg(const char *msg)
192.51 +{ ENV *env = get_env_ptr();
192.52 + int len = strlen(msg);
192.53 + if (len >= IOERR_MSG_SIZE)
192.54 + len = IOERR_MSG_SIZE - 1;
192.55 + memcpy(env->ioerr_msg, msg, len);
192.56 + if (len > 0 && env->ioerr_msg[len-1] == '\n') len--;
192.57 + env->ioerr_msg[len] = '\0';
192.58 + return;
192.59 +}
192.60 +
192.61 +/***********************************************************************
192.62 +* NAME
192.63 +*
192.64 +* xerrmsg - retrieve error message string
192.65 +*
192.66 +* SYNOPSIS
192.67 +*
192.68 +* #include "glpenv.h"
192.69 +* const char *xerrmsg(void);
192.70 +*
192.71 +* RETURNS
192.72 +*
192.73 +* The routine xerrmsg returns a pointer to an error message string
192.74 +* previously set by some library routine to indicate an error. */
192.75 +
192.76 +const char *xerrmsg(void)
192.77 +{ ENV *env = get_env_ptr();
192.78 + return env->ioerr_msg;
192.79 +}
192.80 +
192.81 +/***********************************************************************
192.82 +* NAME
192.83 +*
192.84 +* xfopen - open a stream
192.85 +*
192.86 +* SYNOPSIS
192.87 +*
192.88 +* #include "glpenv.h"
192.89 +* XFILE *xfopen(const char *fname, const char *mode);
192.90 +*
192.91 +* DESCRIPTION
192.92 +*
192.93 +* The routine xfopen opens the file whose name is a string pointed to
192.94 +* by fname and associates a stream with it.
192.95 +*
192.96 +* The parameter mode points to a string, which indicates the open mode
192.97 +* and should be one of the following:
192.98 +*
192.99 +* "r" open text file for reading;
192.100 +* "w" truncate to zero length or create text file for writing;
192.101 +* "rb" open binary file for reading;
192.102 +* "wb" truncate to zero length or create binary file for writing.
192.103 +*
192.104 +* RETURNS
192.105 +*
192.106 +* The routine xfopen returns a pointer to the object controlling the
192.107 +* stream. If the open operation fails, xfopen returns NULL. */
192.108 +
192.109 +static void *c_fopen(const char *fname, const char *mode);
192.110 +static void *z_fopen(const char *fname, const char *mode);
192.111 +
192.112 +static int is_gz_file(const char *fname)
192.113 +{ char *ext = strrchr(fname, '.');
192.114 + return ext != NULL && strcmp(ext, ".gz") == 0;
192.115 +}
192.116 +
192.117 +XFILE *xfopen(const char *fname, const char *mode)
192.118 +{ ENV *env = get_env_ptr();
192.119 + XFILE *fp;
192.120 + int type;
192.121 + void *fh;
192.122 + if (!is_gz_file(fname))
192.123 + { type = FH_FILE;
192.124 + fh = c_fopen(fname, mode);
192.125 + }
192.126 + else
192.127 + { type = FH_ZLIB;
192.128 + fh = z_fopen(fname, mode);
192.129 + }
192.130 + if (fh == NULL)
192.131 + { fp = NULL;
192.132 + goto done;
192.133 + }
192.134 + fp = xmalloc(sizeof(XFILE));
192.135 + fp->type = type;
192.136 + fp->fh = fh;
192.137 + fp->prev = NULL;
192.138 + fp->next = env->file_ptr;
192.139 + if (fp->next != NULL) fp->next->prev = fp;
192.140 + env->file_ptr = fp;
192.141 +done: return fp;
192.142 +}
192.143 +
192.144 +/***********************************************************************
192.145 +* NAME
192.146 +*
192.147 +* xfgetc - read character from the stream
192.148 +*
192.149 +* SYNOPSIS
192.150 +*
192.151 +* #include "glpenv.h"
192.152 +* int xfgetc(XFILE *fp);
192.153 +*
192.154 +* DESCRIPTION
192.155 +*
192.156 +* If the end-of-file indicator for the input stream pointed to by fp
192.157 +* is not set and a next character is present, the routine xfgetc
192.158 +* obtains that character as an unsigned char converted to an int and
192.159 +* advances the associated file position indicator for the stream (if
192.160 +* defined).
192.161 +*
192.162 +* RETURNS
192.163 +*
192.164 +* If the end-of-file indicator for the stream is set, or if the
192.165 +* stream is at end-of-file, the end-of-file indicator for the stream
192.166 +* is set and the routine xfgetc returns XEOF. Otherwise, the routine
192.167 +* xfgetc returns the next character from the input stream pointed to
192.168 +* by fp. If a read error occurs, the error indicator for the stream is
192.169 +* set and the xfgetc routine returns XEOF.
192.170 +*
192.171 +* Note: An end-of-file and a read error can be distinguished by use of
192.172 +* the routines xfeof and xferror. */
192.173 +
192.174 +static int c_fgetc(void *fh);
192.175 +static int z_fgetc(void *fh);
192.176 +
192.177 +int xfgetc(XFILE *fp)
192.178 +{ int c;
192.179 + switch (fp->type)
192.180 + { case FH_FILE:
192.181 + c = c_fgetc(fp->fh);
192.182 + break;
192.183 + case FH_ZLIB:
192.184 + c = z_fgetc(fp->fh);
192.185 + break;
192.186 + default:
192.187 + xassert(fp != fp);
192.188 + }
192.189 + return c;
192.190 +}
192.191 +
192.192 +/***********************************************************************
192.193 +* NAME
192.194 +*
192.195 +* xfputc - write character to the stream
192.196 +*
192.197 +* SYNOPSIS
192.198 +*
192.199 +* #include "glpenv.h"
192.200 +* int xfputc(int c, XFILE *fp);
192.201 +*
192.202 +* DESCRIPTION
192.203 +*
192.204 +* The routine xfputc writes the character specified by c (converted
192.205 +* to an unsigned char) to the output stream pointed to by fp, at the
192.206 +* position indicated by the associated file position indicator (if
192.207 +* defined), and advances the indicator appropriately.
192.208 +*
192.209 +* RETURNS
192.210 +*
192.211 +* The routine xfputc returns the character written. If a write error
192.212 +* occurs, the error indicator for the stream is set and xfputc returns
192.213 +* XEOF. */
192.214 +
192.215 +static int c_fputc(int c, void *fh);
192.216 +static int z_fputc(int c, void *fh);
192.217 +
192.218 +int xfputc(int c, XFILE *fp)
192.219 +{ switch (fp->type)
192.220 + { case FH_FILE:
192.221 + c = c_fputc(c, fp->fh);
192.222 + break;
192.223 + case FH_ZLIB:
192.224 + c = z_fputc(c, fp->fh);
192.225 + break;
192.226 + default:
192.227 + xassert(fp != fp);
192.228 + }
192.229 + return c;
192.230 +}
192.231 +
192.232 +/***********************************************************************
192.233 +* NAME
192.234 +*
192.235 +* xferror - test error indicator for the stream
192.236 +*
192.237 +* SYNOPSIS
192.238 +*
192.239 +* #include "glpenv.h"
192.240 +* int xferror(XFILE *fp);
192.241 +*
192.242 +* DESCRIPTION
192.243 +*
192.244 +* The routine xferror tests the error indicator for the stream
192.245 +* pointed to by fp.
192.246 +*
192.247 +* RETURNS
192.248 +*
192.249 +* The routine xferror returns non-zero if and only if the error
192.250 +* indicator is set for the stream. */
192.251 +
192.252 +static int c_ferror(void *fh);
192.253 +static int z_ferror(void *fh);
192.254 +
192.255 +int xferror(XFILE *fp)
192.256 +{ int ret;
192.257 + switch (fp->type)
192.258 + { case FH_FILE:
192.259 + ret = c_ferror(fp->fh);
192.260 + break;
192.261 + case FH_ZLIB:
192.262 + ret = z_ferror(fp->fh);
192.263 + break;
192.264 + default:
192.265 + xassert(fp != fp);
192.266 + }
192.267 + return ret;
192.268 +}
192.269 +
192.270 +/***********************************************************************
192.271 +* NAME
192.272 +*
192.273 +* xfeof - test end-of-file indicator for the stream
192.274 +*
192.275 +* SYNOPSIS
192.276 +*
192.277 +* #include "glpenv.h"
192.278 +* int xfeof(XFILE *fp);
192.279 +*
192.280 +* DESCRIPTION
192.281 +*
192.282 +* The routine xfeof tests the end-of-file indicator for the stream
192.283 +* pointed to by fp.
192.284 +*
192.285 +* RETURNS
192.286 +*
192.287 +* The routine xfeof returns non-zero if and only if the end-of-file
192.288 +* indicator is set for the stream. */
192.289 +
192.290 +static int c_feof(void *fh);
192.291 +static int z_feof(void *fh);
192.292 +
192.293 +int xfeof(XFILE *fp)
192.294 +{ int ret;
192.295 + switch (fp->type)
192.296 + { case FH_FILE:
192.297 + ret = c_feof(fp->fh);
192.298 + break;
192.299 + case FH_ZLIB:
192.300 + ret = z_feof(fp->fh);
192.301 + break;
192.302 + default:
192.303 + xassert(fp != fp);
192.304 + }
192.305 + return ret;
192.306 +}
192.307 +
192.308 +int xfprintf(XFILE *file, const char *fmt, ...)
192.309 +{ ENV *env = get_env_ptr();
192.310 + int cnt, j;
192.311 + va_list arg;
192.312 + va_start(arg, fmt);
192.313 + cnt = vsprintf(env->term_buf, fmt, arg);
192.314 + va_end(arg);
192.315 + for (j = 0; j < cnt; j++)
192.316 + { if (xfputc(env->term_buf[j], file) < 0)
192.317 + { cnt = -1;
192.318 + break;
192.319 + }
192.320 + }
192.321 + return cnt;
192.322 +}
192.323 +
192.324 +/***********************************************************************
192.325 +* NAME
192.326 +*
192.327 +* xfflush - flush the stream
192.328 +*
192.329 +* SYNOPSIS
192.330 +*
192.331 +* #include "glpenv.h"
192.332 +* int xfflush(XFILE *fp);
192.333 +*
192.334 +* DESCRIPTION
192.335 +*
192.336 +* The routine xfflush causes any unwritten data for the output stream
192.337 +* pointed to by fp to be written to the associated file.
192.338 +*
192.339 +* RETURNS
192.340 +*
192.341 +* The routine xfflush returns zero if the stream was successfully
192.342 +* flushed. Otherwise, xfflush sets the error indicator for the stream
192.343 +* and returns XEOF. */
192.344 +
192.345 +static int c_fflush(void *fh);
192.346 +static int z_fflush(void *fh);
192.347 +
192.348 +int xfflush(XFILE *fp)
192.349 +{ int ret;
192.350 + switch (fp->type)
192.351 + { case FH_FILE:
192.352 + ret = c_fflush(fp->fh);
192.353 + break;
192.354 + case FH_ZLIB:
192.355 + ret = z_fflush(fp->fh);
192.356 + break;
192.357 + default:
192.358 + xassert(fp != fp);
192.359 + }
192.360 + return ret;
192.361 +}
192.362 +
192.363 +/***********************************************************************
192.364 +* NAME
192.365 +*
192.366 +* xfclose - close the stream
192.367 +*
192.368 +* SYNOPSIS
192.369 +*
192.370 +* #include "glpenv.h"
192.371 +* int xfclose(XFILE *fp);
192.372 +*
192.373 +* DESCRIPTION
192.374 +*
192.375 +* A successful call to the routine xfclose causes the stream pointed
192.376 +* to by fp to be flushed and the associated file to be closed. Whether
192.377 +* or not the call succeeds, the stream is disassociated from the file.
192.378 +*
192.379 +* RETURNS
192.380 +*
192.381 +* The routine xfclose returns zero if the stream was successfully
192.382 +* closed, or XEOF if any errors were detected. */
192.383 +
192.384 +static int c_fclose(void *fh);
192.385 +static int z_fclose(void *fh);
192.386 +
192.387 +int xfclose(XFILE *fp)
192.388 +{ ENV *env = get_env_ptr();
192.389 + int ret;
192.390 + switch (fp->type)
192.391 + { case FH_FILE:
192.392 + ret = c_fclose(fp->fh);
192.393 + break;
192.394 + case FH_ZLIB:
192.395 + ret = z_fclose(fp->fh);
192.396 + break;
192.397 + default:
192.398 + xassert(fp != fp);
192.399 + }
192.400 + fp->type = 0xF00BAD;
192.401 + if (fp->prev == NULL)
192.402 + env->file_ptr = fp->next;
192.403 + else
192.404 + fp->prev->next = fp->next;
192.405 + if (fp->next == NULL)
192.406 + ;
192.407 + else
192.408 + fp->next->prev = fp->prev;
192.409 + xfree(fp);
192.410 + return ret;
192.411 +}
192.412 +
192.413 +/***********************************************************************
192.414 +* The following routines implement stream input/output based on the
192.415 +* standard C streams. */
192.416 +
192.417 +static void *c_fopen(const char *fname, const char *mode)
192.418 +{ FILE *fh;
192.419 + if (strcmp(fname, "/dev/stdin") == 0)
192.420 + fh = stdin;
192.421 + else if (strcmp(fname, "/dev/stdout") == 0)
192.422 + fh = stdout;
192.423 + else if (strcmp(fname, "/dev/stderr") == 0)
192.424 + fh = stderr;
192.425 + else
192.426 + fh = fopen(fname, mode);
192.427 + if (fh == NULL)
192.428 + lib_err_msg(strerror(errno));
192.429 + return fh;
192.430 +}
192.431 +
192.432 +static int c_fgetc(void *_fh)
192.433 +{ FILE *fh = _fh;
192.434 + int c;
192.435 + if (ferror(fh) || feof(fh))
192.436 + { c = XEOF;
192.437 + goto done;
192.438 + }
192.439 + c = fgetc(fh);
192.440 + if (ferror(fh))
192.441 + { lib_err_msg(strerror(errno));
192.442 + c = XEOF;
192.443 + }
192.444 + else if (feof(fh))
192.445 + c = XEOF;
192.446 + else
192.447 + xassert(0x00 <= c && c <= 0xFF);
192.448 +done: return c;
192.449 +}
192.450 +
192.451 +static int c_fputc(int c, void *_fh)
192.452 +{ FILE *fh = _fh;
192.453 + if (ferror(fh))
192.454 + { c = XEOF;
192.455 + goto done;
192.456 + }
192.457 + c = (unsigned char)c;
192.458 + fputc(c, fh);
192.459 + if (ferror(fh))
192.460 + { lib_err_msg(strerror(errno));
192.461 + c = XEOF;
192.462 + }
192.463 +done: return c;
192.464 +}
192.465 +
192.466 +static int c_ferror(void *_fh)
192.467 +{ FILE *fh = _fh;
192.468 + return ferror(fh);
192.469 +}
192.470 +
192.471 +static int c_feof(void *_fh)
192.472 +{ FILE *fh = _fh;
192.473 + return feof(fh);
192.474 +}
192.475 +
192.476 +static int c_fflush(void *_fh)
192.477 +{ FILE *fh = _fh;
192.478 + int ret;
192.479 + ret = fflush(fh);
192.480 + if (ret != 0)
192.481 + { lib_err_msg(strerror(errno));
192.482 + ret = XEOF;
192.483 + }
192.484 + return ret;
192.485 +}
192.486 +
192.487 +static int c_fclose(void *_fh)
192.488 +{ FILE *fh = _fh;
192.489 + int ret;
192.490 + if (fh == stdin)
192.491 + ret = 0;
192.492 + else if (fh == stdout || fh == stderr)
192.493 + fflush(fh), ret = 0;
192.494 + else
192.495 + ret = fclose(fh);
192.496 + if (ret != 0)
192.497 + { lib_err_msg(strerror(errno));
192.498 + ret = XEOF;
192.499 + }
192.500 + return ret;
192.501 +}
192.502 +
192.503 +/***********************************************************************
192.504 +* The following routines implement stream input/output based on the
192.505 +* zlib library, which provides processing .gz files "on the fly". */
192.506 +
192.507 +#ifndef HAVE_ZLIB
192.508 +
192.509 +static void *z_fopen(const char *fname, const char *mode)
192.510 +{ xassert(fname == fname);
192.511 + xassert(mode == mode);
192.512 + lib_err_msg("Compressed files not supported");
192.513 + return NULL;
192.514 +}
192.515 +
192.516 +static int z_fgetc(void *fh)
192.517 +{ xassert(fh != fh);
192.518 + return 0;
192.519 +}
192.520 +
192.521 +static int z_fputc(int c, void *fh)
192.522 +{ xassert(c != c);
192.523 + xassert(fh != fh);
192.524 + return 0;
192.525 +}
192.526 +
192.527 +static int z_ferror(void *fh)
192.528 +{ xassert(fh != fh);
192.529 + return 0;
192.530 +}
192.531 +
192.532 +static int z_feof(void *fh)
192.533 +{ xassert(fh != fh);
192.534 + return 0;
192.535 +}
192.536 +
192.537 +static int z_fflush(void *fh)
192.538 +{ xassert(fh != fh);
192.539 + return 0;
192.540 +}
192.541 +
192.542 +static int z_fclose(void *fh)
192.543 +{ xassert(fh != fh);
192.544 + return 0;
192.545 +}
192.546 +
192.547 +#else
192.548 +
192.549 +#include <zlib.h>
192.550 +
192.551 +struct z_file
192.552 +{ /* .gz file handle */
192.553 + gzFile file;
192.554 + /* pointer to .gz stream */
192.555 + int err;
192.556 + /* i/o error indicator */
192.557 + int eof;
192.558 + /* end-of-file indicator */
192.559 +};
192.560 +
192.561 +static void *z_fopen(const char *fname, const char *mode)
192.562 +{ struct z_file *fh;
192.563 + gzFile file;
192.564 + if (strcmp(mode, "r") == 0 || strcmp(mode, "rb") == 0)
192.565 + mode = "rb";
192.566 + else if (strcmp(mode, "w") == 0 || strcmp(mode, "wb") == 0)
192.567 + mode = "wb";
192.568 + else
192.569 + { lib_err_msg("Invalid open mode");
192.570 + fh = NULL;
192.571 + goto done;
192.572 + }
192.573 + file = gzopen(fname, mode);
192.574 + if (file == NULL)
192.575 + { lib_err_msg(strerror(errno));
192.576 + fh = NULL;
192.577 + goto done;
192.578 + }
192.579 + fh = xmalloc(sizeof(struct z_file));
192.580 + fh->file = file;
192.581 + fh->err = fh->eof = 0;
192.582 +done: return fh;
192.583 +}
192.584 +
192.585 +static int z_fgetc(void *_fh)
192.586 +{ struct z_file *fh = _fh;
192.587 + int c;
192.588 + if (fh->err || fh->eof)
192.589 + { c = XEOF;
192.590 + goto done;
192.591 + }
192.592 + c = gzgetc(fh->file);
192.593 + if (c < 0)
192.594 + { int errnum;
192.595 + const char *msg;
192.596 + msg = gzerror(fh->file, &errnum);
192.597 + if (errnum == Z_STREAM_END)
192.598 + fh->eof = 1;
192.599 + else if (errnum == Z_ERRNO)
192.600 + { fh->err = 1;
192.601 + lib_err_msg(strerror(errno));
192.602 + }
192.603 + else
192.604 + { fh->err = 1;
192.605 + lib_err_msg(msg);
192.606 + }
192.607 + c = XEOF;
192.608 + }
192.609 + else
192.610 + xassert(0x00 <= c && c <= 0xFF);
192.611 +done: return c;
192.612 +}
192.613 +
192.614 +static int z_fputc(int c, void *_fh)
192.615 +{ struct z_file *fh = _fh;
192.616 + if (fh->err)
192.617 + { c = XEOF;
192.618 + goto done;
192.619 + }
192.620 + c = (unsigned char)c;
192.621 + if (gzputc(fh->file, c) < 0)
192.622 + { int errnum;
192.623 + const char *msg;
192.624 + fh->err = 1;
192.625 + msg = gzerror(fh->file, &errnum);
192.626 + if (errnum == Z_ERRNO)
192.627 + lib_err_msg(strerror(errno));
192.628 + else
192.629 + lib_err_msg(msg);
192.630 + c = XEOF;
192.631 + }
192.632 +done: return c;
192.633 +}
192.634 +
192.635 +static int z_ferror(void *_fh)
192.636 +{ struct z_file *fh = _fh;
192.637 + return fh->err;
192.638 +}
192.639 +
192.640 +static int z_feof(void *_fh)
192.641 +{ struct z_file *fh = _fh;
192.642 + return fh->eof;
192.643 +}
192.644 +
192.645 +static int z_fflush(void *_fh)
192.646 +{ struct z_file *fh = _fh;
192.647 + int ret;
192.648 + ret = gzflush(fh->file, Z_FINISH);
192.649 + if (ret == Z_OK)
192.650 + ret = 0;
192.651 + else
192.652 + { int errnum;
192.653 + const char *msg;
192.654 + fh->err = 1;
192.655 + msg = gzerror(fh->file, &errnum);
192.656 + if (errnum == Z_ERRNO)
192.657 + lib_err_msg(strerror(errno));
192.658 + else
192.659 + lib_err_msg(msg);
192.660 + ret = XEOF;
192.661 + }
192.662 + return ret;
192.663 +}
192.664 +
192.665 +static int z_fclose(void *_fh)
192.666 +{ struct z_file *fh = _fh;
192.667 + gzclose(fh->file);
192.668 + xfree(fh);
192.669 + return 0;
192.670 +}
192.671 +
192.672 +#endif
192.673 +
192.674 +/* eof */
193.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
193.2 +++ b/src/glpenv08.c Mon Dec 06 13:09:21 2010 +0100
193.3 @@ -0,0 +1,156 @@
193.4 +/* glpenv08.c (shared library support) */
193.5 +
193.6 +/***********************************************************************
193.7 +* This code is part of GLPK (GNU Linear Programming Kit).
193.8 +*
193.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
193.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
193.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
193.12 +* E-mail: <mao@gnu.org>.
193.13 +*
193.14 +* GLPK is free software: you can redistribute it and/or modify it
193.15 +* under the terms of the GNU General Public License as published by
193.16 +* the Free Software Foundation, either version 3 of the License, or
193.17 +* (at your option) any later version.
193.18 +*
193.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
193.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
193.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
193.22 +* License for more details.
193.23 +*
193.24 +* You should have received a copy of the GNU General Public License
193.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
193.26 +***********************************************************************/
193.27 +
193.28 +#ifdef HAVE_CONFIG_H
193.29 +#include <config.h>
193.30 +#endif
193.31 +
193.32 +#include "glpenv.h"
193.33 +
193.34 +/* GNU version ********************************************************/
193.35 +
193.36 +#if defined(HAVE_LTDL)
193.37 +
193.38 +#include <ltdl.h>
193.39 +
193.40 +void *xdlopen(const char *module)
193.41 +{ void *h = NULL;
193.42 + if (lt_dlinit() != 0)
193.43 + { lib_err_msg(lt_dlerror());
193.44 + goto done;
193.45 + }
193.46 + h = lt_dlopen(module);
193.47 + if (h == NULL)
193.48 + { lib_err_msg(lt_dlerror());
193.49 + if (lt_dlexit() != 0)
193.50 + xerror("xdlopen: %s\n", lt_dlerror());
193.51 + }
193.52 +done: return h;
193.53 +}
193.54 +
193.55 +void *xdlsym(void *h, const char *symbol)
193.56 +{ void *ptr;
193.57 + xassert(h != NULL);
193.58 + ptr = lt_dlsym(h, symbol);
193.59 + if (ptr == NULL)
193.60 + xerror("xdlsym: %s: %s\n", symbol, lt_dlerror());
193.61 + return ptr;
193.62 +}
193.63 +
193.64 +void xdlclose(void *h)
193.65 +{ xassert(h != NULL);
193.66 + if (lt_dlclose(h) != 0)
193.67 + xerror("xdlclose: %s\n", lt_dlerror());
193.68 + if (lt_dlexit() != 0)
193.69 + xerror("xdlclose: %s\n", lt_dlerror());
193.70 + return;
193.71 +}
193.72 +
193.73 +/* POSIX version ******************************************************/
193.74 +
193.75 +#elif defined(HAVE_DLFCN)
193.76 +
193.77 +#include <dlfcn.h>
193.78 +
193.79 +void *xdlopen(const char *module)
193.80 +{ void *h;
193.81 + h = dlopen(module, RTLD_NOW);
193.82 + if (h == NULL)
193.83 + lib_err_msg(dlerror());
193.84 + return h;
193.85 +}
193.86 +
193.87 +void *xdlsym(void *h, const char *symbol)
193.88 +{ void *ptr;
193.89 + xassert(h != NULL);
193.90 + ptr = dlsym(h, symbol);
193.91 + if (ptr == NULL)
193.92 + xerror("xdlsym: %s: %s\n", symbol, dlerror());
193.93 + return ptr;
193.94 +}
193.95 +
193.96 +void xdlclose(void *h)
193.97 +{ xassert(h != NULL);
193.98 + if (dlclose(h) != 0)
193.99 + xerror("xdlclose: %s\n", dlerror());
193.100 + return;
193.101 +}
193.102 +
193.103 +/* Windows version ****************************************************/
193.104 +
193.105 +#elif defined(__WOE__)
193.106 +
193.107 +#include <windows.h>
193.108 +
193.109 +void *xdlopen(const char *module)
193.110 +{ void *h;
193.111 + h = LoadLibrary(module);
193.112 + if (h == NULL)
193.113 + { char msg[20];
193.114 + sprintf(msg, "Error %d", GetLastError());
193.115 + lib_err_msg(msg);
193.116 + }
193.117 + return h;
193.118 +}
193.119 +
193.120 +void *xdlsym(void *h, const char *symbol)
193.121 +{ void *ptr;
193.122 + xassert(h != NULL);
193.123 + ptr = GetProcAddress(h, symbol);
193.124 + if (ptr == NULL)
193.125 + xerror("xdlsym: %s: Error %d\n", symbol, GetLastError());
193.126 + return ptr;
193.127 +}
193.128 +
193.129 +void xdlclose(void *h)
193.130 +{ xassert(h != NULL);
193.131 + if (!FreeLibrary(h))
193.132 + xerror("xdlclose: Error %d\n", GetLastError());
193.133 + return;
193.134 +}
193.135 +
193.136 +/* NULL version *******************************************************/
193.137 +
193.138 +#else
193.139 +
193.140 +void *xdlopen(const char *module)
193.141 +{ xassert(module == module);
193.142 + lib_err_msg("Shared libraries not supported");
193.143 + return NULL;
193.144 +}
193.145 +
193.146 +void *xdlsym(void *h, const char *symbol)
193.147 +{ xassert(h != h);
193.148 + xassert(symbol != symbol);
193.149 + return NULL;
193.150 +}
193.151 +
193.152 +void xdlclose(void *h)
193.153 +{ xassert(h != h);
193.154 + return;
193.155 +}
193.156 +
193.157 +#endif
193.158 +
193.159 +/* eof */
194.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
194.2 +++ b/src/glpfhv.c Mon Dec 06 13:09:21 2010 +0100
194.3 @@ -0,0 +1,774 @@
194.4 +/* glpfhv.c (LP basis factorization, FHV eta file version) */
194.5 +
194.6 +/***********************************************************************
194.7 +* This code is part of GLPK (GNU Linear Programming Kit).
194.8 +*
194.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
194.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
194.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
194.12 +* E-mail: <mao@gnu.org>.
194.13 +*
194.14 +* GLPK is free software: you can redistribute it and/or modify it
194.15 +* under the terms of the GNU General Public License as published by
194.16 +* the Free Software Foundation, either version 3 of the License, or
194.17 +* (at your option) any later version.
194.18 +*
194.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
194.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
194.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
194.22 +* License for more details.
194.23 +*
194.24 +* You should have received a copy of the GNU General Public License
194.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
194.26 +***********************************************************************/
194.27 +
194.28 +#include "glpfhv.h"
194.29 +#include "glpenv.h"
194.30 +#define xfault xerror
194.31 +
194.32 +/* CAUTION: DO NOT CHANGE THE LIMIT BELOW */
194.33 +
194.34 +#define M_MAX 100000000 /* = 100*10^6 */
194.35 +/* maximal order of the basis matrix */
194.36 +
194.37 +/***********************************************************************
194.38 +* NAME
194.39 +*
194.40 +* fhv_create_it - create LP basis factorization
194.41 +*
194.42 +* SYNOPSIS
194.43 +*
194.44 +* #include "glpfhv.h"
194.45 +* FHV *fhv_create_it(void);
194.46 +*
194.47 +* DESCRIPTION
194.48 +*
194.49 +* The routine fhv_create_it creates a program object, which represents
194.50 +* a factorization of LP basis.
194.51 +*
194.52 +* RETURNS
194.53 +*
194.54 +* The routine fhv_create_it returns a pointer to the object created. */
194.55 +
194.56 +FHV *fhv_create_it(void)
194.57 +{ FHV *fhv;
194.58 + fhv = xmalloc(sizeof(FHV));
194.59 + fhv->m_max = fhv->m = 0;
194.60 + fhv->valid = 0;
194.61 + fhv->luf = luf_create_it();
194.62 + fhv->hh_max = 50;
194.63 + fhv->hh_nfs = 0;
194.64 + fhv->hh_ind = fhv->hh_ptr = fhv->hh_len = NULL;
194.65 + fhv->p0_row = fhv->p0_col = NULL;
194.66 + fhv->cc_ind = NULL;
194.67 + fhv->cc_val = NULL;
194.68 + fhv->upd_tol = 1e-6;
194.69 + fhv->nnz_h = 0;
194.70 + return fhv;
194.71 +}
194.72 +
194.73 +/***********************************************************************
194.74 +* NAME
194.75 +*
194.76 +* fhv_factorize - compute LP basis factorization
194.77 +*
194.78 +* SYNOPSIS
194.79 +*
194.80 +* #include "glpfhv.h"
194.81 +* int fhv_factorize(FHV *fhv, int m, int (*col)(void *info, int j,
194.82 +* int ind[], double val[]), void *info);
194.83 +*
194.84 +* DESCRIPTION
194.85 +*
194.86 +* The routine fhv_factorize computes the factorization of the basis
194.87 +* matrix B specified by the routine col.
194.88 +*
194.89 +* The parameter fhv specified the basis factorization data structure
194.90 +* created by the routine fhv_create_it.
194.91 +*
194.92 +* The parameter m specifies the order of B, m > 0.
194.93 +*
194.94 +* The formal routine col specifies the matrix B to be factorized. To
194.95 +* obtain j-th column of A the routine fhv_factorize calls the routine
194.96 +* col with the parameter j (1 <= j <= n). In response the routine col
194.97 +* should store row indices and numerical values of non-zero elements
194.98 +* of j-th column of B to locations ind[1,...,len] and val[1,...,len],
194.99 +* respectively, where len is the number of non-zeros in j-th column
194.100 +* returned on exit. Neither zero nor duplicate elements are allowed.
194.101 +*
194.102 +* The parameter info is a transit pointer passed to the routine col.
194.103 +*
194.104 +* RETURNS
194.105 +*
194.106 +* 0 The factorization has been successfully computed.
194.107 +*
194.108 +* FHV_ESING
194.109 +* The specified matrix is singular within the working precision.
194.110 +*
194.111 +* FHV_ECOND
194.112 +* The specified matrix is ill-conditioned.
194.113 +*
194.114 +* For more details see comments to the routine luf_factorize.
194.115 +*
194.116 +* ALGORITHM
194.117 +*
194.118 +* The routine fhv_factorize calls the routine luf_factorize (see the
194.119 +* module GLPLUF), which actually computes LU-factorization of the basis
194.120 +* matrix B in the form
194.121 +*
194.122 +* [B] = (F, V, P, Q),
194.123 +*
194.124 +* where F and V are such matrices that
194.125 +*
194.126 +* B = F * V,
194.127 +*
194.128 +* and P and Q are such permutation matrices that the matrix
194.129 +*
194.130 +* L = P * F * inv(P)
194.131 +*
194.132 +* is lower triangular with unity diagonal, and the matrix
194.133 +*
194.134 +* U = P * V * Q
194.135 +*
194.136 +* is upper triangular.
194.137 +*
194.138 +* In order to build the complete representation of the factorization
194.139 +* (see formula (1) in the file glpfhv.h) the routine fhv_factorize just
194.140 +* additionally sets H = I and P0 = P. */
194.141 +
194.142 +int fhv_factorize(FHV *fhv, int m, int (*col)(void *info, int j,
194.143 + int ind[], double val[]), void *info)
194.144 +{ int ret;
194.145 + if (m < 1)
194.146 + xfault("fhv_factorize: m = %d; invalid parameter\n", m);
194.147 + if (m > M_MAX)
194.148 + xfault("fhv_factorize: m = %d; matrix too big\n", m);
194.149 + fhv->m = m;
194.150 + /* invalidate the factorization */
194.151 + fhv->valid = 0;
194.152 + /* allocate/reallocate arrays, if necessary */
194.153 + if (fhv->hh_ind == NULL)
194.154 + fhv->hh_ind = xcalloc(1+fhv->hh_max, sizeof(int));
194.155 + if (fhv->hh_ptr == NULL)
194.156 + fhv->hh_ptr = xcalloc(1+fhv->hh_max, sizeof(int));
194.157 + if (fhv->hh_len == NULL)
194.158 + fhv->hh_len = xcalloc(1+fhv->hh_max, sizeof(int));
194.159 + if (fhv->m_max < m)
194.160 + { if (fhv->p0_row != NULL) xfree(fhv->p0_row);
194.161 + if (fhv->p0_col != NULL) xfree(fhv->p0_col);
194.162 + if (fhv->cc_ind != NULL) xfree(fhv->cc_ind);
194.163 + if (fhv->cc_val != NULL) xfree(fhv->cc_val);
194.164 + fhv->m_max = m + 100;
194.165 + fhv->p0_row = xcalloc(1+fhv->m_max, sizeof(int));
194.166 + fhv->p0_col = xcalloc(1+fhv->m_max, sizeof(int));
194.167 + fhv->cc_ind = xcalloc(1+fhv->m_max, sizeof(int));
194.168 + fhv->cc_val = xcalloc(1+fhv->m_max, sizeof(double));
194.169 + }
194.170 + /* try to factorize the basis matrix */
194.171 + switch (luf_factorize(fhv->luf, m, col, info))
194.172 + { case 0:
194.173 + break;
194.174 + case LUF_ESING:
194.175 + ret = FHV_ESING;
194.176 + goto done;
194.177 + case LUF_ECOND:
194.178 + ret = FHV_ECOND;
194.179 + goto done;
194.180 + default:
194.181 + xassert(fhv != fhv);
194.182 + }
194.183 + /* the basis matrix has been successfully factorized */
194.184 + fhv->valid = 1;
194.185 + /* H := I */
194.186 + fhv->hh_nfs = 0;
194.187 + /* P0 := P */
194.188 + memcpy(&fhv->p0_row[1], &fhv->luf->pp_row[1], sizeof(int) * m);
194.189 + memcpy(&fhv->p0_col[1], &fhv->luf->pp_col[1], sizeof(int) * m);
194.190 + /* currently H has no factors */
194.191 + fhv->nnz_h = 0;
194.192 + ret = 0;
194.193 +done: /* return to the calling program */
194.194 + return ret;
194.195 +}
194.196 +
194.197 +/***********************************************************************
194.198 +* NAME
194.199 +*
194.200 +* fhv_h_solve - solve system H*x = b or H'*x = b
194.201 +*
194.202 +* SYNOPSIS
194.203 +*
194.204 +* #include "glpfhv.h"
194.205 +* void fhv_h_solve(FHV *fhv, int tr, double x[]);
194.206 +*
194.207 +* DESCRIPTION
194.208 +*
194.209 +* The routine fhv_h_solve solves either the system H*x = b (if the
194.210 +* flag tr is zero) or the system H'*x = b (if the flag tr is non-zero),
194.211 +* where the matrix H is a component of the factorization specified by
194.212 +* the parameter fhv, H' is a matrix transposed to H.
194.213 +*
194.214 +* On entry the array x should contain elements of the right-hand side
194.215 +* vector b in locations x[1], ..., x[m], where m is the order of the
194.216 +* matrix H. On exit this array will contain elements of the solution
194.217 +* vector x in the same locations. */
194.218 +
194.219 +void fhv_h_solve(FHV *fhv, int tr, double x[])
194.220 +{ int nfs = fhv->hh_nfs;
194.221 + int *hh_ind = fhv->hh_ind;
194.222 + int *hh_ptr = fhv->hh_ptr;
194.223 + int *hh_len = fhv->hh_len;
194.224 + int *sv_ind = fhv->luf->sv_ind;
194.225 + double *sv_val = fhv->luf->sv_val;
194.226 + int i, k, beg, end, ptr;
194.227 + double temp;
194.228 + if (!fhv->valid)
194.229 + xfault("fhv_h_solve: the factorization is not valid\n");
194.230 + if (!tr)
194.231 + { /* solve the system H*x = b */
194.232 + for (k = 1; k <= nfs; k++)
194.233 + { i = hh_ind[k];
194.234 + temp = x[i];
194.235 + beg = hh_ptr[k];
194.236 + end = beg + hh_len[k] - 1;
194.237 + for (ptr = beg; ptr <= end; ptr++)
194.238 + temp -= sv_val[ptr] * x[sv_ind[ptr]];
194.239 + x[i] = temp;
194.240 + }
194.241 + }
194.242 + else
194.243 + { /* solve the system H'*x = b */
194.244 + for (k = nfs; k >= 1; k--)
194.245 + { i = hh_ind[k];
194.246 + temp = x[i];
194.247 + if (temp == 0.0) continue;
194.248 + beg = hh_ptr[k];
194.249 + end = beg + hh_len[k] - 1;
194.250 + for (ptr = beg; ptr <= end; ptr++)
194.251 + x[sv_ind[ptr]] -= sv_val[ptr] * temp;
194.252 + }
194.253 + }
194.254 + return;
194.255 +}
194.256 +
194.257 +/***********************************************************************
194.258 +* NAME
194.259 +*
194.260 +* fhv_ftran - perform forward transformation (solve system B*x = b)
194.261 +*
194.262 +* SYNOPSIS
194.263 +*
194.264 +* #include "glpfhv.h"
194.265 +* void fhv_ftran(FHV *fhv, double x[]);
194.266 +*
194.267 +* DESCRIPTION
194.268 +*
194.269 +* The routine fhv_ftran performs forward transformation, i.e. solves
194.270 +* the system B*x = b, where B is the basis matrix, x is the vector of
194.271 +* unknowns to be computed, b is the vector of right-hand sides.
194.272 +*
194.273 +* On entry elements of the vector b should be stored in dense format
194.274 +* in locations x[1], ..., x[m], where m is the number of rows. On exit
194.275 +* the routine stores elements of the vector x in the same locations. */
194.276 +
194.277 +void fhv_ftran(FHV *fhv, double x[])
194.278 +{ int *pp_row = fhv->luf->pp_row;
194.279 + int *pp_col = fhv->luf->pp_col;
194.280 + int *p0_row = fhv->p0_row;
194.281 + int *p0_col = fhv->p0_col;
194.282 + if (!fhv->valid)
194.283 + xfault("fhv_ftran: the factorization is not valid\n");
194.284 + /* B = F*H*V, therefore inv(B) = inv(V)*inv(H)*inv(F) */
194.285 + fhv->luf->pp_row = p0_row;
194.286 + fhv->luf->pp_col = p0_col;
194.287 + luf_f_solve(fhv->luf, 0, x);
194.288 + fhv->luf->pp_row = pp_row;
194.289 + fhv->luf->pp_col = pp_col;
194.290 + fhv_h_solve(fhv, 0, x);
194.291 + luf_v_solve(fhv->luf, 0, x);
194.292 + return;
194.293 +}
194.294 +
194.295 +/***********************************************************************
194.296 +* NAME
194.297 +*
194.298 +* fhv_btran - perform backward transformation (solve system B'*x = b)
194.299 +*
194.300 +* SYNOPSIS
194.301 +*
194.302 +* #include "glpfhv.h"
194.303 +* void fhv_btran(FHV *fhv, double x[]);
194.304 +*
194.305 +* DESCRIPTION
194.306 +*
194.307 +* The routine fhv_btran performs backward transformation, i.e. solves
194.308 +* the system B'*x = b, where B' is a matrix transposed to the basis
194.309 +* matrix B, x is the vector of unknowns to be computed, b is the vector
194.310 +* of right-hand sides.
194.311 +*
194.312 +* On entry elements of the vector b should be stored in dense format
194.313 +* in locations x[1], ..., x[m], where m is the number of rows. On exit
194.314 +* the routine stores elements of the vector x in the same locations. */
194.315 +
194.316 +void fhv_btran(FHV *fhv, double x[])
194.317 +{ int *pp_row = fhv->luf->pp_row;
194.318 + int *pp_col = fhv->luf->pp_col;
194.319 + int *p0_row = fhv->p0_row;
194.320 + int *p0_col = fhv->p0_col;
194.321 + if (!fhv->valid)
194.322 + xfault("fhv_btran: the factorization is not valid\n");
194.323 + /* B = F*H*V, therefore inv(B') = inv(F')*inv(H')*inv(V') */
194.324 + luf_v_solve(fhv->luf, 1, x);
194.325 + fhv_h_solve(fhv, 1, x);
194.326 + fhv->luf->pp_row = p0_row;
194.327 + fhv->luf->pp_col = p0_col;
194.328 + luf_f_solve(fhv->luf, 1, x);
194.329 + fhv->luf->pp_row = pp_row;
194.330 + fhv->luf->pp_col = pp_col;
194.331 + return;
194.332 +}
194.333 +
194.334 +/***********************************************************************
194.335 +* NAME
194.336 +*
194.337 +* fhv_update_it - update LP basis factorization
194.338 +*
194.339 +* SYNOPSIS
194.340 +*
194.341 +* #include "glpfhv.h"
194.342 +* int fhv_update_it(FHV *fhv, int j, int len, const int ind[],
194.343 +* const double val[]);
194.344 +*
194.345 +* DESCRIPTION
194.346 +*
194.347 +* The routine fhv_update_it updates the factorization of the basis
194.348 +* matrix B after replacing its j-th column by a new vector.
194.349 +*
194.350 +* The parameter j specifies the number of column of B, which has been
194.351 +* replaced, 1 <= j <= m, where m is the order of B.
194.352 +*
194.353 +* Row indices and numerical values of non-zero elements of the new
194.354 +* column of B should be placed in locations ind[1], ..., ind[len] and
194.355 +* val[1], ..., val[len], resp., where len is the number of non-zeros
194.356 +* in the column. Neither zero nor duplicate elements are allowed.
194.357 +*
194.358 +* RETURNS
194.359 +*
194.360 +* 0 The factorization has been successfully updated.
194.361 +*
194.362 +* FHV_ESING
194.363 +* The adjacent basis matrix is structurally singular, since after
194.364 +* changing j-th column of matrix V by the new column (see algorithm
194.365 +* below) the case k1 > k2 occured.
194.366 +*
194.367 +* FHV_ECHECK
194.368 +* The factorization is inaccurate, since after transforming k2-th
194.369 +* row of matrix U = P*V*Q, its diagonal element u[k2,k2] is zero or
194.370 +* close to zero,
194.371 +*
194.372 +* FHV_ELIMIT
194.373 +* Maximal number of H factors has been reached.
194.374 +*
194.375 +* FHV_EROOM
194.376 +* Overflow of the sparse vector area.
194.377 +*
194.378 +* In case of non-zero return code the factorization becomes invalid.
194.379 +* It should not be used until it has been recomputed with the routine
194.380 +* fhv_factorize.
194.381 +*
194.382 +* ALGORITHM
194.383 +*
194.384 +* The routine fhv_update_it is based on the transformation proposed by
194.385 +* Forrest and Tomlin.
194.386 +*
194.387 +* Let j-th column of the basis matrix B have been replaced by new
194.388 +* column B[j]. In order to keep the equality B = F*H*V j-th column of
194.389 +* matrix V should be replaced by the column inv(F*H)*B[j].
194.390 +*
194.391 +* From the standpoint of matrix U = P*V*Q, replacement of j-th column
194.392 +* of matrix V is equivalent to replacement of k1-th column of matrix U,
194.393 +* where k1 is determined by permutation matrix Q. Thus, matrix U loses
194.394 +* its upper triangular form and becomes the following:
194.395 +*
194.396 +* 1 k1 k2 m
194.397 +* 1 x x * x x x x x x x
194.398 +* . x * x x x x x x x
194.399 +* k1 . . * x x x x x x x
194.400 +* . . * x x x x x x x
194.401 +* . . * . x x x x x x
194.402 +* . . * . . x x x x x
194.403 +* . . * . . . x x x x
194.404 +* k2 . . * . . . . x x x
194.405 +* . . . . . . . . x x
194.406 +* m . . . . . . . . . x
194.407 +*
194.408 +* where row index k2 corresponds to the lowest non-zero element of
194.409 +* k1-th column.
194.410 +*
194.411 +* The routine moves rows and columns k1+1, k1+2, ..., k2 of matrix U
194.412 +* by one position to the left and upwards and moves k1-th row and k1-th
194.413 +* column to position k2. As the result of such symmetric permutations
194.414 +* matrix U becomes the following:
194.415 +*
194.416 +* 1 k1 k2 m
194.417 +* 1 x x x x x x x * x x
194.418 +* . x x x x x x * x x
194.419 +* k1 . . x x x x x * x x
194.420 +* . . . x x x x * x x
194.421 +* . . . . x x x * x x
194.422 +* . . . . . x x * x x
194.423 +* . . . . . . x * x x
194.424 +* k2 . . x x x x x * x x
194.425 +* . . . . . . . . x x
194.426 +* m . . . . . . . . . x
194.427 +*
194.428 +* Then the routine performs gaussian elimination to eliminate elements
194.429 +* u[k2,k1], u[k2,k1+1], ..., u[k2,k2-1] using diagonal elements
194.430 +* u[k1,k1], u[k1+1,k1+1], ..., u[k2-1,k2-1] as pivots in the same way
194.431 +* as described in comments to the routine luf_factorize (see the module
194.432 +* GLPLUF). Note that actually all operations are performed on matrix V,
194.433 +* not on matrix U. During the elimination process the routine permutes
194.434 +* neither rows nor columns, so only k2-th row of matrix U is changed.
194.435 +*
194.436 +* To keep the main equality B = F*H*V, each time when the routine
194.437 +* applies elementary gaussian transformation to the transformed row of
194.438 +* matrix V (which corresponds to k2-th row of matrix U), it also adds
194.439 +* a new element (gaussian multiplier) to the current row-like factor
194.440 +* of matrix H, which corresponds to the transformed row of matrix V. */
194.441 +
194.442 +int fhv_update_it(FHV *fhv, int j, int len, const int ind[],
194.443 + const double val[])
194.444 +{ int m = fhv->m;
194.445 + LUF *luf = fhv->luf;
194.446 + int *vr_ptr = luf->vr_ptr;
194.447 + int *vr_len = luf->vr_len;
194.448 + int *vr_cap = luf->vr_cap;
194.449 + double *vr_piv = luf->vr_piv;
194.450 + int *vc_ptr = luf->vc_ptr;
194.451 + int *vc_len = luf->vc_len;
194.452 + int *vc_cap = luf->vc_cap;
194.453 + int *pp_row = luf->pp_row;
194.454 + int *pp_col = luf->pp_col;
194.455 + int *qq_row = luf->qq_row;
194.456 + int *qq_col = luf->qq_col;
194.457 + int *sv_ind = luf->sv_ind;
194.458 + double *sv_val = luf->sv_val;
194.459 + double *work = luf->work;
194.460 + double eps_tol = luf->eps_tol;
194.461 + int *hh_ind = fhv->hh_ind;
194.462 + int *hh_ptr = fhv->hh_ptr;
194.463 + int *hh_len = fhv->hh_len;
194.464 + int *p0_row = fhv->p0_row;
194.465 + int *p0_col = fhv->p0_col;
194.466 + int *cc_ind = fhv->cc_ind;
194.467 + double *cc_val = fhv->cc_val;
194.468 + double upd_tol = fhv->upd_tol;
194.469 + int i, i_beg, i_end, i_ptr, j_beg, j_end, j_ptr, k, k1, k2, p, q,
194.470 + p_beg, p_end, p_ptr, ptr, ret;
194.471 + double f, temp;
194.472 + if (!fhv->valid)
194.473 + xfault("fhv_update_it: the factorization is not valid\n");
194.474 + if (!(1 <= j && j <= m))
194.475 + xfault("fhv_update_it: j = %d; column number out of range\n",
194.476 + j);
194.477 + /* check if the new factor of matrix H can be created */
194.478 + if (fhv->hh_nfs == fhv->hh_max)
194.479 + { /* maximal number of updates has been reached */
194.480 + fhv->valid = 0;
194.481 + ret = FHV_ELIMIT;
194.482 + goto done;
194.483 + }
194.484 + /* convert new j-th column of B to dense format */
194.485 + for (i = 1; i <= m; i++)
194.486 + cc_val[i] = 0.0;
194.487 + for (k = 1; k <= len; k++)
194.488 + { i = ind[k];
194.489 + if (!(1 <= i && i <= m))
194.490 + xfault("fhv_update_it: ind[%d] = %d; row number out of rang"
194.491 + "e\n", k, i);
194.492 + if (cc_val[i] != 0.0)
194.493 + xfault("fhv_update_it: ind[%d] = %d; duplicate row index no"
194.494 + "t allowed\n", k, i);
194.495 + if (val[k] == 0.0)
194.496 + xfault("fhv_update_it: val[%d] = %g; zero element not allow"
194.497 + "ed\n", k, val[k]);
194.498 + cc_val[i] = val[k];
194.499 + }
194.500 + /* new j-th column of V := inv(F * H) * (new B[j]) */
194.501 + fhv->luf->pp_row = p0_row;
194.502 + fhv->luf->pp_col = p0_col;
194.503 + luf_f_solve(fhv->luf, 0, cc_val);
194.504 + fhv->luf->pp_row = pp_row;
194.505 + fhv->luf->pp_col = pp_col;
194.506 + fhv_h_solve(fhv, 0, cc_val);
194.507 + /* convert new j-th column of V to sparse format */
194.508 + len = 0;
194.509 + for (i = 1; i <= m; i++)
194.510 + { temp = cc_val[i];
194.511 + if (temp == 0.0 || fabs(temp) < eps_tol) continue;
194.512 + len++, cc_ind[len] = i, cc_val[len] = temp;
194.513 + }
194.514 + /* clear old content of j-th column of matrix V */
194.515 + j_beg = vc_ptr[j];
194.516 + j_end = j_beg + vc_len[j] - 1;
194.517 + for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
194.518 + { /* get row index of v[i,j] */
194.519 + i = sv_ind[j_ptr];
194.520 + /* find v[i,j] in the i-th row */
194.521 + i_beg = vr_ptr[i];
194.522 + i_end = i_beg + vr_len[i] - 1;
194.523 + for (i_ptr = i_beg; sv_ind[i_ptr] != j; i_ptr++) /* nop */;
194.524 + xassert(i_ptr <= i_end);
194.525 + /* remove v[i,j] from the i-th row */
194.526 + sv_ind[i_ptr] = sv_ind[i_end];
194.527 + sv_val[i_ptr] = sv_val[i_end];
194.528 + vr_len[i]--;
194.529 + }
194.530 + /* now j-th column of matrix V is empty */
194.531 + luf->nnz_v -= vc_len[j];
194.532 + vc_len[j] = 0;
194.533 + /* add new elements of j-th column of matrix V to corresponding
194.534 + row lists; determine indices k1 and k2 */
194.535 + k1 = qq_row[j], k2 = 0;
194.536 + for (ptr = 1; ptr <= len; ptr++)
194.537 + { /* get row index of v[i,j] */
194.538 + i = cc_ind[ptr];
194.539 + /* at least one unused location is needed in i-th row */
194.540 + if (vr_len[i] + 1 > vr_cap[i])
194.541 + { if (luf_enlarge_row(luf, i, vr_len[i] + 10))
194.542 + { /* overflow of the sparse vector area */
194.543 + fhv->valid = 0;
194.544 + luf->new_sva = luf->sv_size + luf->sv_size;
194.545 + xassert(luf->new_sva > luf->sv_size);
194.546 + ret = FHV_EROOM;
194.547 + goto done;
194.548 + }
194.549 + }
194.550 + /* add v[i,j] to i-th row */
194.551 + i_ptr = vr_ptr[i] + vr_len[i];
194.552 + sv_ind[i_ptr] = j;
194.553 + sv_val[i_ptr] = cc_val[ptr];
194.554 + vr_len[i]++;
194.555 + /* adjust index k2 */
194.556 + if (k2 < pp_col[i]) k2 = pp_col[i];
194.557 + }
194.558 + /* capacity of j-th column (which is currently empty) should be
194.559 + not less than len locations */
194.560 + if (vc_cap[j] < len)
194.561 + { if (luf_enlarge_col(luf, j, len))
194.562 + { /* overflow of the sparse vector area */
194.563 + fhv->valid = 0;
194.564 + luf->new_sva = luf->sv_size + luf->sv_size;
194.565 + xassert(luf->new_sva > luf->sv_size);
194.566 + ret = FHV_EROOM;
194.567 + goto done;
194.568 + }
194.569 + }
194.570 + /* add new elements of matrix V to j-th column list */
194.571 + j_ptr = vc_ptr[j];
194.572 + memmove(&sv_ind[j_ptr], &cc_ind[1], len * sizeof(int));
194.573 + memmove(&sv_val[j_ptr], &cc_val[1], len * sizeof(double));
194.574 + vc_len[j] = len;
194.575 + luf->nnz_v += len;
194.576 + /* if k1 > k2, diagonal element u[k2,k2] of matrix U is zero and
194.577 + therefore the adjacent basis matrix is structurally singular */
194.578 + if (k1 > k2)
194.579 + { fhv->valid = 0;
194.580 + ret = FHV_ESING;
194.581 + goto done;
194.582 + }
194.583 + /* perform implicit symmetric permutations of rows and columns of
194.584 + matrix U */
194.585 + i = pp_row[k1], j = qq_col[k1];
194.586 + for (k = k1; k < k2; k++)
194.587 + { pp_row[k] = pp_row[k+1], pp_col[pp_row[k]] = k;
194.588 + qq_col[k] = qq_col[k+1], qq_row[qq_col[k]] = k;
194.589 + }
194.590 + pp_row[k2] = i, pp_col[i] = k2;
194.591 + qq_col[k2] = j, qq_row[j] = k2;
194.592 + /* now i-th row of the matrix V is k2-th row of matrix U; since
194.593 + no pivoting is used, only this row will be transformed */
194.594 + /* copy elements of i-th row of matrix V to the working array and
194.595 + remove these elements from matrix V */
194.596 + for (j = 1; j <= m; j++) work[j] = 0.0;
194.597 + i_beg = vr_ptr[i];
194.598 + i_end = i_beg + vr_len[i] - 1;
194.599 + for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
194.600 + { /* get column index of v[i,j] */
194.601 + j = sv_ind[i_ptr];
194.602 + /* store v[i,j] to the working array */
194.603 + work[j] = sv_val[i_ptr];
194.604 + /* find v[i,j] in the j-th column */
194.605 + j_beg = vc_ptr[j];
194.606 + j_end = j_beg + vc_len[j] - 1;
194.607 + for (j_ptr = j_beg; sv_ind[j_ptr] != i; j_ptr++) /* nop */;
194.608 + xassert(j_ptr <= j_end);
194.609 + /* remove v[i,j] from the j-th column */
194.610 + sv_ind[j_ptr] = sv_ind[j_end];
194.611 + sv_val[j_ptr] = sv_val[j_end];
194.612 + vc_len[j]--;
194.613 + }
194.614 + /* now i-th row of matrix V is empty */
194.615 + luf->nnz_v -= vr_len[i];
194.616 + vr_len[i] = 0;
194.617 + /* create the next row-like factor of the matrix H; this factor
194.618 + corresponds to i-th (transformed) row */
194.619 + fhv->hh_nfs++;
194.620 + hh_ind[fhv->hh_nfs] = i;
194.621 + /* hh_ptr[] will be set later */
194.622 + hh_len[fhv->hh_nfs] = 0;
194.623 + /* up to (k2 - k1) free locations are needed to add new elements
194.624 + to the non-trivial row of the row-like factor */
194.625 + if (luf->sv_end - luf->sv_beg < k2 - k1)
194.626 + { luf_defrag_sva(luf);
194.627 + if (luf->sv_end - luf->sv_beg < k2 - k1)
194.628 + { /* overflow of the sparse vector area */
194.629 + fhv->valid = luf->valid = 0;
194.630 + luf->new_sva = luf->sv_size + luf->sv_size;
194.631 + xassert(luf->new_sva > luf->sv_size);
194.632 + ret = FHV_EROOM;
194.633 + goto done;
194.634 + }
194.635 + }
194.636 + /* eliminate subdiagonal elements of matrix U */
194.637 + for (k = k1; k < k2; k++)
194.638 + { /* v[p,q] = u[k,k] */
194.639 + p = pp_row[k], q = qq_col[k];
194.640 + /* this is the crucial point, where even tiny non-zeros should
194.641 + not be dropped */
194.642 + if (work[q] == 0.0) continue;
194.643 + /* compute gaussian multiplier f = v[i,q] / v[p,q] */
194.644 + f = work[q] / vr_piv[p];
194.645 + /* perform gaussian transformation:
194.646 + (i-th row) := (i-th row) - f * (p-th row)
194.647 + in order to eliminate v[i,q] = u[k2,k] */
194.648 + p_beg = vr_ptr[p];
194.649 + p_end = p_beg + vr_len[p] - 1;
194.650 + for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++)
194.651 + work[sv_ind[p_ptr]] -= f * sv_val[p_ptr];
194.652 + /* store new element (gaussian multiplier that corresponds to
194.653 + p-th row) in the current row-like factor */
194.654 + luf->sv_end--;
194.655 + sv_ind[luf->sv_end] = p;
194.656 + sv_val[luf->sv_end] = f;
194.657 + hh_len[fhv->hh_nfs]++;
194.658 + }
194.659 + /* set pointer to the current row-like factor of the matrix H
194.660 + (if no elements were added to this factor, it is unity matrix
194.661 + and therefore can be discarded) */
194.662 + if (hh_len[fhv->hh_nfs] == 0)
194.663 + fhv->hh_nfs--;
194.664 + else
194.665 + { hh_ptr[fhv->hh_nfs] = luf->sv_end;
194.666 + fhv->nnz_h += hh_len[fhv->hh_nfs];
194.667 + }
194.668 + /* store new pivot which corresponds to u[k2,k2] */
194.669 + vr_piv[i] = work[qq_col[k2]];
194.670 + /* new elements of i-th row of matrix V (which are non-diagonal
194.671 + elements u[k2,k2+1], ..., u[k2,m] of matrix U = P*V*Q) now are
194.672 + contained in the working array; add them to matrix V */
194.673 + len = 0;
194.674 + for (k = k2+1; k <= m; k++)
194.675 + { /* get column index and value of v[i,j] = u[k2,k] */
194.676 + j = qq_col[k];
194.677 + temp = work[j];
194.678 + /* if v[i,j] is close to zero, skip it */
194.679 + if (fabs(temp) < eps_tol) continue;
194.680 + /* at least one unused location is needed in j-th column */
194.681 + if (vc_len[j] + 1 > vc_cap[j])
194.682 + { if (luf_enlarge_col(luf, j, vc_len[j] + 10))
194.683 + { /* overflow of the sparse vector area */
194.684 + fhv->valid = 0;
194.685 + luf->new_sva = luf->sv_size + luf->sv_size;
194.686 + xassert(luf->new_sva > luf->sv_size);
194.687 + ret = FHV_EROOM;
194.688 + goto done;
194.689 + }
194.690 + }
194.691 + /* add v[i,j] to j-th column */
194.692 + j_ptr = vc_ptr[j] + vc_len[j];
194.693 + sv_ind[j_ptr] = i;
194.694 + sv_val[j_ptr] = temp;
194.695 + vc_len[j]++;
194.696 + /* also store v[i,j] to the auxiliary array */
194.697 + len++, cc_ind[len] = j, cc_val[len] = temp;
194.698 + }
194.699 + /* capacity of i-th row (which is currently empty) should be not
194.700 + less than len locations */
194.701 + if (vr_cap[i] < len)
194.702 + { if (luf_enlarge_row(luf, i, len))
194.703 + { /* overflow of the sparse vector area */
194.704 + fhv->valid = 0;
194.705 + luf->new_sva = luf->sv_size + luf->sv_size;
194.706 + xassert(luf->new_sva > luf->sv_size);
194.707 + ret = FHV_EROOM;
194.708 + goto done;
194.709 + }
194.710 + }
194.711 + /* add new elements to i-th row list */
194.712 + i_ptr = vr_ptr[i];
194.713 + memmove(&sv_ind[i_ptr], &cc_ind[1], len * sizeof(int));
194.714 + memmove(&sv_val[i_ptr], &cc_val[1], len * sizeof(double));
194.715 + vr_len[i] = len;
194.716 + luf->nnz_v += len;
194.717 + /* updating is finished; check that diagonal element u[k2,k2] is
194.718 + not very small in absolute value among other elements in k2-th
194.719 + row and k2-th column of matrix U = P*V*Q */
194.720 + /* temp = max(|u[k2,*]|, |u[*,k2]|) */
194.721 + temp = 0.0;
194.722 + /* walk through k2-th row of U which is i-th row of V */
194.723 + i = pp_row[k2];
194.724 + i_beg = vr_ptr[i];
194.725 + i_end = i_beg + vr_len[i] - 1;
194.726 + for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
194.727 + if (temp < fabs(sv_val[i_ptr])) temp = fabs(sv_val[i_ptr]);
194.728 + /* walk through k2-th column of U which is j-th column of V */
194.729 + j = qq_col[k2];
194.730 + j_beg = vc_ptr[j];
194.731 + j_end = j_beg + vc_len[j] - 1;
194.732 + for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
194.733 + if (temp < fabs(sv_val[j_ptr])) temp = fabs(sv_val[j_ptr]);
194.734 + /* check that u[k2,k2] is not very small */
194.735 + if (fabs(vr_piv[i]) < upd_tol * temp)
194.736 + { /* the factorization seems to be inaccurate and therefore must
194.737 + be recomputed */
194.738 + fhv->valid = 0;
194.739 + ret = FHV_ECHECK;
194.740 + goto done;
194.741 + }
194.742 + /* the factorization has been successfully updated */
194.743 + ret = 0;
194.744 +done: /* return to the calling program */
194.745 + return ret;
194.746 +}
194.747 +
194.748 +/***********************************************************************
194.749 +* NAME
194.750 +*
194.751 +* fhv_delete_it - delete LP basis factorization
194.752 +*
194.753 +* SYNOPSIS
194.754 +*
194.755 +* #include "glpfhv.h"
194.756 +* void fhv_delete_it(FHV *fhv);
194.757 +*
194.758 +* DESCRIPTION
194.759 +*
194.760 +* The routine fhv_delete_it deletes LP basis factorization specified
194.761 +* by the parameter fhv and frees all memory allocated to this program
194.762 +* object. */
194.763 +
194.764 +void fhv_delete_it(FHV *fhv)
194.765 +{ luf_delete_it(fhv->luf);
194.766 + if (fhv->hh_ind != NULL) xfree(fhv->hh_ind);
194.767 + if (fhv->hh_ptr != NULL) xfree(fhv->hh_ptr);
194.768 + if (fhv->hh_len != NULL) xfree(fhv->hh_len);
194.769 + if (fhv->p0_row != NULL) xfree(fhv->p0_row);
194.770 + if (fhv->p0_col != NULL) xfree(fhv->p0_col);
194.771 + if (fhv->cc_ind != NULL) xfree(fhv->cc_ind);
194.772 + if (fhv->cc_val != NULL) xfree(fhv->cc_val);
194.773 + xfree(fhv);
194.774 + return;
194.775 +}
194.776 +
194.777 +/* eof */
195.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
195.2 +++ b/src/glpfhv.h Mon Dec 06 13:09:21 2010 +0100
195.3 @@ -0,0 +1,170 @@
195.4 +/* glpfhv.h (LP basis factorization, FHV eta file version) */
195.5 +
195.6 +/***********************************************************************
195.7 +* This code is part of GLPK (GNU Linear Programming Kit).
195.8 +*
195.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
195.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
195.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
195.12 +* E-mail: <mao@gnu.org>.
195.13 +*
195.14 +* GLPK is free software: you can redistribute it and/or modify it
195.15 +* under the terms of the GNU General Public License as published by
195.16 +* the Free Software Foundation, either version 3 of the License, or
195.17 +* (at your option) any later version.
195.18 +*
195.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
195.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
195.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
195.22 +* License for more details.
195.23 +*
195.24 +* You should have received a copy of the GNU General Public License
195.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
195.26 +***********************************************************************/
195.27 +
195.28 +#ifndef GLPFHV_H
195.29 +#define GLPFHV_H
195.30 +
195.31 +#include "glpluf.h"
195.32 +
195.33 +/***********************************************************************
195.34 +* The structure FHV defines the factorization of the basis mxm-matrix
195.35 +* B, where m is the number of rows in corresponding problem instance.
195.36 +*
195.37 +* This factorization is the following sextet:
195.38 +*
195.39 +* [B] = (F, H, V, P0, P, Q), (1)
195.40 +*
195.41 +* where F, H, and V are such matrices that
195.42 +*
195.43 +* B = F * H * V, (2)
195.44 +*
195.45 +* and P0, P, and Q are such permutation matrices that the matrix
195.46 +*
195.47 +* L = P0 * F * inv(P0) (3)
195.48 +*
195.49 +* is lower triangular with unity diagonal, and the matrix
195.50 +*
195.51 +* U = P * V * Q (4)
195.52 +*
195.53 +* is upper triangular. All the matrices have the same order m, which
195.54 +* is the order of the basis matrix B.
195.55 +*
195.56 +* The matrices F, V, P, and Q are stored in the structure LUF (see the
195.57 +* module GLPLUF), which is a member of the structure FHV.
195.58 +*
195.59 +* The matrix H is stored in the form of eta file using row-like format
195.60 +* as follows:
195.61 +*
195.62 +* H = H[1] * H[2] * ... * H[nfs], (5)
195.63 +*
195.64 +* where H[k], k = 1, 2, ..., nfs, is a row-like factor, which differs
195.65 +* from the unity matrix only by one row, nfs is current number of row-
195.66 +* like factors. After the factorization has been built for some given
195.67 +* basis matrix B the matrix H has no factors and thus it is the unity
195.68 +* matrix. Then each time when the factorization is recomputed for an
195.69 +* adjacent basis matrix, the next factor H[k], k = 1, 2, ... is built
195.70 +* and added to the end of the eta file H.
195.71 +*
195.72 +* Being sparse vectors non-trivial rows of the factors H[k] are stored
195.73 +* in the right part of the sparse vector area (SVA) in the same manner
195.74 +* as rows and columns of the matrix F.
195.75 +*
195.76 +* For more details see the program documentation. */
195.77 +
195.78 +typedef struct FHV FHV;
195.79 +
195.80 +struct FHV
195.81 +{ /* LP basis factorization */
195.82 + int m_max;
195.83 + /* maximal value of m (increased automatically, if necessary) */
195.84 + int m;
195.85 + /* the order of matrices B, F, H, V, P0, P, Q */
195.86 + int valid;
195.87 + /* the factorization is valid only if this flag is set */
195.88 + LUF *luf;
195.89 + /* LU-factorization (contains the matrices F, V, P, Q) */
195.90 + /*--------------------------------------------------------------*/
195.91 + /* matrix H in the form of eta file */
195.92 + int hh_max;
195.93 + /* maximal number of row-like factors (which limits the number of
195.94 + updates of the factorization) */
195.95 + int hh_nfs;
195.96 + /* current number of row-like factors (0 <= hh_nfs <= hh_max) */
195.97 + int *hh_ind; /* int hh_ind[1+hh_max]; */
195.98 + /* hh_ind[k], k = 1, ..., nfs, is the number of a non-trivial row
195.99 + of factor H[k] */
195.100 + int *hh_ptr; /* int hh_ptr[1+hh_max]; */
195.101 + /* hh_ptr[k], k = 1, ..., nfs, is a pointer to the first element
195.102 + of the non-trivial row of factor H[k] in the SVA */
195.103 + int *hh_len; /* int hh_len[1+hh_max]; */
195.104 + /* hh_len[k], k = 1, ..., nfs, is the number of non-zero elements
195.105 + in the non-trivial row of factor H[k] */
195.106 + /*--------------------------------------------------------------*/
195.107 + /* matrix P0 */
195.108 + int *p0_row; /* int p0_row[1+m_max]; */
195.109 + /* p0_row[i] = j means that p0[i,j] = 1 */
195.110 + int *p0_col; /* int p0_col[1+m_max]; */
195.111 + /* p0_col[j] = i means that p0[i,j] = 1 */
195.112 + /* if i-th row or column of the matrix F corresponds to i'-th row
195.113 + or column of the matrix L = P0*F*inv(P0), then p0_row[i'] = i
195.114 + and p0_col[i] = i' */
195.115 + /*--------------------------------------------------------------*/
195.116 + /* working arrays */
195.117 + int *cc_ind; /* int cc_ind[1+m_max]; */
195.118 + /* integer working array */
195.119 + double *cc_val; /* double cc_val[1+m_max]; */
195.120 + /* floating-point working array */
195.121 + /*--------------------------------------------------------------*/
195.122 + /* control parameters */
195.123 + double upd_tol;
195.124 + /* update tolerance; if after updating the factorization absolute
195.125 + value of some diagonal element u[k,k] of matrix U = P*V*Q is
195.126 + less than upd_tol * max(|u[k,*]|, |u[*,k]|), the factorization
195.127 + is considered as inaccurate */
195.128 + /*--------------------------------------------------------------*/
195.129 + /* some statistics */
195.130 + int nnz_h;
195.131 + /* current number of non-zeros in all factors of matrix H */
195.132 +};
195.133 +
195.134 +/* return codes: */
195.135 +#define FHV_ESING 1 /* singular matrix */
195.136 +#define FHV_ECOND 2 /* ill-conditioned matrix */
195.137 +#define FHV_ECHECK 3 /* insufficient accuracy */
195.138 +#define FHV_ELIMIT 4 /* update limit reached */
195.139 +#define FHV_EROOM 5 /* SVA overflow */
195.140 +
195.141 +#define fhv_create_it _glp_fhv_create_it
195.142 +FHV *fhv_create_it(void);
195.143 +/* create LP basis factorization */
195.144 +
195.145 +#define fhv_factorize _glp_fhv_factorize
195.146 +int fhv_factorize(FHV *fhv, int m, int (*col)(void *info, int j,
195.147 + int ind[], double val[]), void *info);
195.148 +/* compute LP basis factorization */
195.149 +
195.150 +#define fhv_h_solve _glp_fhv_h_solve
195.151 +void fhv_h_solve(FHV *fhv, int tr, double x[]);
195.152 +/* solve system H*x = b or H'*x = b */
195.153 +
195.154 +#define fhv_ftran _glp_fhv_ftran
195.155 +void fhv_ftran(FHV *fhv, double x[]);
195.156 +/* perform forward transformation (solve system B*x = b) */
195.157 +
195.158 +#define fhv_btran _glp_fhv_btran
195.159 +void fhv_btran(FHV *fhv, double x[]);
195.160 +/* perform backward transformation (solve system B'*x = b) */
195.161 +
195.162 +#define fhv_update_it _glp_fhv_update_it
195.163 +int fhv_update_it(FHV *fhv, int j, int len, const int ind[],
195.164 + const double val[]);
195.165 +/* update LP basis factorization */
195.166 +
195.167 +#define fhv_delete_it _glp_fhv_delete_it
195.168 +void fhv_delete_it(FHV *fhv);
195.169 +/* delete LP basis factorization */
195.170 +
195.171 +#endif
195.172 +
195.173 +/* eof */
196.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
196.2 +++ b/src/glpgmp.c Mon Dec 06 13:09:21 2010 +0100
196.3 @@ -0,0 +1,1108 @@
196.4 +/* glpgmp.c */
196.5 +
196.6 +/***********************************************************************
196.7 +* This code is part of GLPK (GNU Linear Programming Kit).
196.8 +*
196.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
196.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
196.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
196.12 +* E-mail: <mao@gnu.org>.
196.13 +*
196.14 +* GLPK is free software: you can redistribute it and/or modify it
196.15 +* under the terms of the GNU General Public License as published by
196.16 +* the Free Software Foundation, either version 3 of the License, or
196.17 +* (at your option) any later version.
196.18 +*
196.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
196.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
196.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
196.22 +* License for more details.
196.23 +*
196.24 +* You should have received a copy of the GNU General Public License
196.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
196.26 +***********************************************************************/
196.27 +
196.28 +#define _GLPSTD_STDIO
196.29 +#include "glpdmp.h"
196.30 +#include "glpgmp.h"
196.31 +#define xfault xerror
196.32 +
196.33 +#ifdef HAVE_GMP /* use GNU MP bignum library */
196.34 +
196.35 +int gmp_pool_count(void) { return 0; }
196.36 +
196.37 +void gmp_free_mem(void) { return; }
196.38 +
196.39 +#else /* use GLPK bignum module */
196.40 +
196.41 +static DMP *gmp_pool = NULL;
196.42 +static int gmp_size = 0;
196.43 +static unsigned short *gmp_work = NULL;
196.44 +
196.45 +void *gmp_get_atom(int size)
196.46 +{ if (gmp_pool == NULL)
196.47 + gmp_pool = dmp_create_pool();
196.48 + return dmp_get_atom(gmp_pool, size);
196.49 +}
196.50 +
196.51 +void gmp_free_atom(void *ptr, int size)
196.52 +{ xassert(gmp_pool != NULL);
196.53 + dmp_free_atom(gmp_pool, ptr, size);
196.54 + return;
196.55 +}
196.56 +
196.57 +int gmp_pool_count(void)
196.58 +{ if (gmp_pool == NULL)
196.59 + return 0;
196.60 + else
196.61 + return dmp_in_use(gmp_pool).lo;
196.62 +}
196.63 +
196.64 +unsigned short *gmp_get_work(int size)
196.65 +{ xassert(size > 0);
196.66 + if (gmp_size < size)
196.67 + { if (gmp_size == 0)
196.68 + { xassert(gmp_work == NULL);
196.69 + gmp_size = 100;
196.70 + }
196.71 + else
196.72 + { xassert(gmp_work != NULL);
196.73 + xfree(gmp_work);
196.74 + }
196.75 + while (gmp_size < size) gmp_size += gmp_size;
196.76 + gmp_work = xcalloc(gmp_size, sizeof(unsigned short));
196.77 + }
196.78 + return gmp_work;
196.79 +}
196.80 +
196.81 +void gmp_free_mem(void)
196.82 +{ if (gmp_pool != NULL) dmp_delete_pool(gmp_pool);
196.83 + if (gmp_work != NULL) xfree(gmp_work);
196.84 + gmp_pool = NULL;
196.85 + gmp_size = 0;
196.86 + gmp_work = NULL;
196.87 + return;
196.88 +}
196.89 +
196.90 +/*====================================================================*/
196.91 +
196.92 +mpz_t _mpz_init(void)
196.93 +{ /* initialize x, and set its value to 0 */
196.94 + mpz_t x;
196.95 + x = gmp_get_atom(sizeof(struct mpz));
196.96 + x->val = 0;
196.97 + x->ptr = NULL;
196.98 + return x;
196.99 +}
196.100 +
196.101 +void mpz_clear(mpz_t x)
196.102 +{ /* free the space occupied by x */
196.103 + mpz_set_si(x, 0);
196.104 + xassert(x->ptr == NULL);
196.105 + /* free the number descriptor */
196.106 + gmp_free_atom(x, sizeof(struct mpz));
196.107 + return;
196.108 +}
196.109 +
196.110 +void mpz_set(mpz_t z, mpz_t x)
196.111 +{ /* set the value of z from x */
196.112 + struct mpz_seg *e, *ee, *es;
196.113 + if (z != x)
196.114 + { mpz_set_si(z, 0);
196.115 + z->val = x->val;
196.116 + xassert(z->ptr == NULL);
196.117 + for (e = x->ptr, es = NULL; e != NULL; e = e->next)
196.118 + { ee = gmp_get_atom(sizeof(struct mpz_seg));
196.119 + memcpy(ee->d, e->d, 12);
196.120 + ee->next = NULL;
196.121 + if (z->ptr == NULL)
196.122 + z->ptr = ee;
196.123 + else
196.124 + es->next = ee;
196.125 + es = ee;
196.126 + }
196.127 + }
196.128 + return;
196.129 +}
196.130 +
196.131 +void mpz_set_si(mpz_t x, int val)
196.132 +{ /* set the value of x to val */
196.133 + struct mpz_seg *e;
196.134 + /* free existing segments, if any */
196.135 + while (x->ptr != NULL)
196.136 + { e = x->ptr;
196.137 + x->ptr = e->next;
196.138 + gmp_free_atom(e, sizeof(struct mpz_seg));
196.139 + }
196.140 + /* assign new value */
196.141 + if (val == 0x80000000)
196.142 + { /* long format is needed */
196.143 + x->val = -1;
196.144 + x->ptr = e = gmp_get_atom(sizeof(struct mpz_seg));
196.145 + memset(e->d, 0, 12);
196.146 + e->d[1] = 0x8000;
196.147 + e->next = NULL;
196.148 + }
196.149 + else
196.150 + { /* short format is enough */
196.151 + x->val = val;
196.152 + }
196.153 + return;
196.154 +}
196.155 +
196.156 +double mpz_get_d(mpz_t x)
196.157 +{ /* convert x to a double, truncating if necessary */
196.158 + struct mpz_seg *e;
196.159 + int j;
196.160 + double val, deg;
196.161 + if (x->ptr == NULL)
196.162 + val = (double)x->val;
196.163 + else
196.164 + { xassert(x->val != 0);
196.165 + val = 0.0;
196.166 + deg = 1.0;
196.167 + for (e = x->ptr; e != NULL; e = e->next)
196.168 + { for (j = 0; j <= 5; j++)
196.169 + { val += deg * (double)((int)e->d[j]);
196.170 + deg *= 65536.0;
196.171 + }
196.172 + }
196.173 + if (x->val < 0) val = - val;
196.174 + }
196.175 + return val;
196.176 +}
196.177 +
196.178 +double mpz_get_d_2exp(int *exp, mpz_t x)
196.179 +{ /* convert x to a double, truncating if necessary (i.e. rounding
196.180 + towards zero), and returning the exponent separately;
196.181 + the return value is in the range 0.5 <= |d| < 1 and the
196.182 + exponent is stored to *exp; d*2^exp is the (truncated) x value;
196.183 + if x is zero, the return is 0.0 and 0 is stored to *exp;
196.184 + this is similar to the standard C frexp function */
196.185 + struct mpz_seg *e;
196.186 + int j, n, n1;
196.187 + double val;
196.188 + if (x->ptr == NULL)
196.189 + val = (double)x->val, n = 0;
196.190 + else
196.191 + { xassert(x->val != 0);
196.192 + val = 0.0, n = 0;
196.193 + for (e = x->ptr; e != NULL; e = e->next)
196.194 + { for (j = 0; j <= 5; j++)
196.195 + { val += (double)((int)e->d[j]);
196.196 + val /= 65536.0, n += 16;
196.197 + }
196.198 + }
196.199 + if (x->val < 0) val = - val;
196.200 + }
196.201 + val = frexp(val, &n1);
196.202 + *exp = n + n1;
196.203 + return val;
196.204 +}
196.205 +
196.206 +void mpz_swap(mpz_t x, mpz_t y)
196.207 +{ /* swap the values x and y efficiently */
196.208 + int val;
196.209 + void *ptr;
196.210 + val = x->val, ptr = x->ptr;
196.211 + x->val = y->val, x->ptr = y->ptr;
196.212 + y->val = val, y->ptr = ptr;
196.213 + return;
196.214 +}
196.215 +
196.216 +static void normalize(mpz_t x)
196.217 +{ /* normalize integer x that includes removing non-significant
196.218 + (leading) zeros and converting to short format, if possible */
196.219 + struct mpz_seg *es, *e;
196.220 + /* if the integer is in short format, it remains unchanged */
196.221 + if (x->ptr == NULL)
196.222 + { xassert(x->val != 0x80000000);
196.223 + goto done;
196.224 + }
196.225 + xassert(x->val == +1 || x->val == -1);
196.226 + /* find the last (most significant) non-zero segment */
196.227 + es = NULL;
196.228 + for (e = x->ptr; e != NULL; e = e->next)
196.229 + { if (e->d[0] || e->d[1] || e->d[2] ||
196.230 + e->d[3] || e->d[4] || e->d[5]) es = e;
196.231 + }
196.232 + /* if all segments contain zeros, the integer is zero */
196.233 + if (es == NULL)
196.234 + { mpz_set_si(x, 0);
196.235 + goto done;
196.236 + }
196.237 + /* remove non-significant (leading) zero segments */
196.238 + while (es->next != NULL)
196.239 + { e = es->next;
196.240 + es->next = e->next;
196.241 + gmp_free_atom(e, sizeof(struct mpz_seg));
196.242 + }
196.243 + /* convert the integer to short format, if possible */
196.244 + e = x->ptr;
196.245 + if (e->next == NULL && e->d[1] <= 0x7FFF &&
196.246 + !e->d[2] && !e->d[3] && !e->d[4] && !e->d[5])
196.247 + { int val;
196.248 + val = (int)e->d[0] + ((int)e->d[1] << 16);
196.249 + if (x->val < 0) val = - val;
196.250 + mpz_set_si(x, val);
196.251 + }
196.252 +done: return;
196.253 +}
196.254 +
196.255 +void mpz_add(mpz_t z, mpz_t x, mpz_t y)
196.256 +{ /* set z to x + y */
196.257 + static struct mpz_seg zero = { { 0, 0, 0, 0, 0, 0 }, NULL };
196.258 + struct mpz_seg dumx, dumy, *ex, *ey, *ez, *es, *ee;
196.259 + int k, sx, sy, sz;
196.260 + unsigned int t;
196.261 + /* if [x] = 0 then [z] = [y] */
196.262 + if (x->val == 0)
196.263 + { xassert(x->ptr == NULL);
196.264 + mpz_set(z, y);
196.265 + goto done;
196.266 + }
196.267 + /* if [y] = 0 then [z] = [x] */
196.268 + if (y->val == 0)
196.269 + { xassert(y->ptr == NULL);
196.270 + mpz_set(z, x);
196.271 + goto done;
196.272 + }
196.273 + /* special case when both [x] and [y] are in short format */
196.274 + if (x->ptr == NULL && y->ptr == NULL)
196.275 + { int xval = x->val, yval = y->val, zval = x->val + y->val;
196.276 + xassert(xval != 0x80000000 && yval != 0x80000000);
196.277 + if (!(xval > 0 && yval > 0 && zval <= 0 ||
196.278 + xval < 0 && yval < 0 && zval >= 0))
196.279 + { mpz_set_si(z, zval);
196.280 + goto done;
196.281 + }
196.282 + }
196.283 + /* convert [x] to long format, if necessary */
196.284 + if (x->ptr == NULL)
196.285 + { xassert(x->val != 0x80000000);
196.286 + if (x->val >= 0)
196.287 + { sx = +1;
196.288 + t = (unsigned int)(+ x->val);
196.289 + }
196.290 + else
196.291 + { sx = -1;
196.292 + t = (unsigned int)(- x->val);
196.293 + }
196.294 + ex = &dumx;
196.295 + ex->d[0] = (unsigned short)t;
196.296 + ex->d[1] = (unsigned short)(t >> 16);
196.297 + ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0;
196.298 + ex->next = NULL;
196.299 + }
196.300 + else
196.301 + { sx = x->val;
196.302 + xassert(sx == +1 || sx == -1);
196.303 + ex = x->ptr;
196.304 + }
196.305 + /* convert [y] to long format, if necessary */
196.306 + if (y->ptr == NULL)
196.307 + { xassert(y->val != 0x80000000);
196.308 + if (y->val >= 0)
196.309 + { sy = +1;
196.310 + t = (unsigned int)(+ y->val);
196.311 + }
196.312 + else
196.313 + { sy = -1;
196.314 + t = (unsigned int)(- y->val);
196.315 + }
196.316 + ey = &dumy;
196.317 + ey->d[0] = (unsigned short)t;
196.318 + ey->d[1] = (unsigned short)(t >> 16);
196.319 + ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0;
196.320 + ey->next = NULL;
196.321 + }
196.322 + else
196.323 + { sy = y->val;
196.324 + xassert(sy == +1 || sy == -1);
196.325 + ey = y->ptr;
196.326 + }
196.327 + /* main fragment */
196.328 + sz = sx;
196.329 + ez = es = NULL;
196.330 + if (sx > 0 && sy > 0 || sx < 0 && sy < 0)
196.331 + { /* [x] and [y] have identical signs -- addition */
196.332 + t = 0;
196.333 + for (; ex || ey; ex = ex->next, ey = ey->next)
196.334 + { if (ex == NULL) ex = &zero;
196.335 + if (ey == NULL) ey = &zero;
196.336 + ee = gmp_get_atom(sizeof(struct mpz_seg));
196.337 + for (k = 0; k <= 5; k++)
196.338 + { t += (unsigned int)ex->d[k];
196.339 + t += (unsigned int)ey->d[k];
196.340 + ee->d[k] = (unsigned short)t;
196.341 + t >>= 16;
196.342 + }
196.343 + ee->next = NULL;
196.344 + if (ez == NULL)
196.345 + ez = ee;
196.346 + else
196.347 + es->next = ee;
196.348 + es = ee;
196.349 + }
196.350 + if (t)
196.351 + { /* overflow -- one extra digit is needed */
196.352 + ee = gmp_get_atom(sizeof(struct mpz_seg));
196.353 + ee->d[0] = 1;
196.354 + ee->d[1] = ee->d[2] = ee->d[3] = ee->d[4] = ee->d[5] = 0;
196.355 + ee->next = NULL;
196.356 + xassert(es != NULL);
196.357 + es->next = ee;
196.358 + }
196.359 + }
196.360 + else
196.361 + { /* [x] and [y] have different signs -- subtraction */
196.362 + t = 1;
196.363 + for (; ex || ey; ex = ex->next, ey = ey->next)
196.364 + { if (ex == NULL) ex = &zero;
196.365 + if (ey == NULL) ey = &zero;
196.366 + ee = gmp_get_atom(sizeof(struct mpz_seg));
196.367 + for (k = 0; k <= 5; k++)
196.368 + { t += (unsigned int)ex->d[k];
196.369 + t += (0xFFFF - (unsigned int)ey->d[k]);
196.370 + ee->d[k] = (unsigned short)t;
196.371 + t >>= 16;
196.372 + }
196.373 + ee->next = NULL;
196.374 + if (ez == NULL)
196.375 + ez = ee;
196.376 + else
196.377 + es->next = ee;
196.378 + es = ee;
196.379 + }
196.380 + if (!t)
196.381 + { /* |[x]| < |[y]| -- result in complement coding */
196.382 + sz = - sz;
196.383 + t = 1;
196.384 + for (ee = ez; ee != NULL; ee = ee->next)
196.385 + for (k = 0; k <= 5; k++)
196.386 + { t += (0xFFFF - (unsigned int)ee->d[k]);
196.387 + ee->d[k] = (unsigned short)t;
196.388 + t >>= 16;
196.389 + }
196.390 + }
196.391 + }
196.392 + /* contruct and normalize result */
196.393 + mpz_set_si(z, 0);
196.394 + z->val = sz;
196.395 + z->ptr = ez;
196.396 + normalize(z);
196.397 +done: return;
196.398 +}
196.399 +
196.400 +void mpz_sub(mpz_t z, mpz_t x, mpz_t y)
196.401 +{ /* set z to x - y */
196.402 + if (x == y)
196.403 + mpz_set_si(z, 0);
196.404 + else
196.405 + { y->val = - y->val;
196.406 + mpz_add(z, x, y);
196.407 + if (y != z) y->val = - y->val;
196.408 + }
196.409 + return;
196.410 +}
196.411 +
196.412 +void mpz_mul(mpz_t z, mpz_t x, mpz_t y)
196.413 +{ /* set z to x * y */
196.414 + struct mpz_seg dumx, dumy, *ex, *ey, *es, *e;
196.415 + int sx, sy, k, nx, ny, n;
196.416 + unsigned int t;
196.417 + unsigned short *work, *wx, *wy;
196.418 + /* if [x] = 0 then [z] = 0 */
196.419 + if (x->val == 0)
196.420 + { xassert(x->ptr == NULL);
196.421 + mpz_set_si(z, 0);
196.422 + goto done;
196.423 + }
196.424 + /* if [y] = 0 then [z] = 0 */
196.425 + if (y->val == 0)
196.426 + { xassert(y->ptr == NULL);
196.427 + mpz_set_si(z, 0);
196.428 + goto done;
196.429 + }
196.430 + /* special case when both [x] and [y] are in short format */
196.431 + if (x->ptr == NULL && y->ptr == NULL)
196.432 + { int xval = x->val, yval = y->val, sz = +1;
196.433 + xassert(xval != 0x80000000 && yval != 0x80000000);
196.434 + if (xval < 0) xval = - xval, sz = - sz;
196.435 + if (yval < 0) yval = - yval, sz = - sz;
196.436 + if (xval <= 0x7FFFFFFF / yval)
196.437 + { mpz_set_si(z, sz * (xval * yval));
196.438 + goto done;
196.439 + }
196.440 + }
196.441 + /* convert [x] to long format, if necessary */
196.442 + if (x->ptr == NULL)
196.443 + { xassert(x->val != 0x80000000);
196.444 + if (x->val >= 0)
196.445 + { sx = +1;
196.446 + t = (unsigned int)(+ x->val);
196.447 + }
196.448 + else
196.449 + { sx = -1;
196.450 + t = (unsigned int)(- x->val);
196.451 + }
196.452 + ex = &dumx;
196.453 + ex->d[0] = (unsigned short)t;
196.454 + ex->d[1] = (unsigned short)(t >> 16);
196.455 + ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0;
196.456 + ex->next = NULL;
196.457 + }
196.458 + else
196.459 + { sx = x->val;
196.460 + xassert(sx == +1 || sx == -1);
196.461 + ex = x->ptr;
196.462 + }
196.463 + /* convert [y] to long format, if necessary */
196.464 + if (y->ptr == NULL)
196.465 + { xassert(y->val != 0x80000000);
196.466 + if (y->val >= 0)
196.467 + { sy = +1;
196.468 + t = (unsigned int)(+ y->val);
196.469 + }
196.470 + else
196.471 + { sy = -1;
196.472 + t = (unsigned int)(- y->val);
196.473 + }
196.474 + ey = &dumy;
196.475 + ey->d[0] = (unsigned short)t;
196.476 + ey->d[1] = (unsigned short)(t >> 16);
196.477 + ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0;
196.478 + ey->next = NULL;
196.479 + }
196.480 + else
196.481 + { sy = y->val;
196.482 + xassert(sy == +1 || sy == -1);
196.483 + ey = y->ptr;
196.484 + }
196.485 + /* determine the number of digits of [x] */
196.486 + nx = n = 0;
196.487 + for (e = ex; e != NULL; e = e->next)
196.488 + for (k = 0; k <= 5; k++)
196.489 + { n++;
196.490 + if (e->d[k]) nx = n;
196.491 + }
196.492 + xassert(nx > 0);
196.493 + /* determine the number of digits of [y] */
196.494 + ny = n = 0;
196.495 + for (e = ey; e != NULL; e = e->next)
196.496 + for (k = 0; k <= 5; k++)
196.497 + { n++;
196.498 + if (e->d[k]) ny = n;
196.499 + }
196.500 + xassert(ny > 0);
196.501 + /* we need working array containing at least nx+ny+ny places */
196.502 + work = gmp_get_work(nx+ny+ny);
196.503 + /* load digits of [x] */
196.504 + wx = &work[0];
196.505 + for (n = 0; n < nx; n++) wx[ny+n] = 0;
196.506 + for (n = 0, e = ex; e != NULL; e = e->next)
196.507 + for (k = 0; k <= 5; k++, n++)
196.508 + if (e->d[k]) wx[ny+n] = e->d[k];
196.509 + /* load digits of [y] */
196.510 + wy = &work[nx+ny];
196.511 + for (n = 0; n < ny; n++) wy[n] = 0;
196.512 + for (n = 0, e = ey; e != NULL; e = e->next)
196.513 + for (k = 0; k <= 5; k++, n++)
196.514 + if (e->d[k]) wy[n] = e->d[k];
196.515 + /* compute [x] * [y] */
196.516 + bigmul(nx, ny, wx, wy);
196.517 + /* construct and normalize result */
196.518 + mpz_set_si(z, 0);
196.519 + z->val = sx * sy;
196.520 + es = NULL;
196.521 + k = 6;
196.522 + for (n = 0; n < nx+ny; n++)
196.523 + { if (k > 5)
196.524 + { e = gmp_get_atom(sizeof(struct mpz_seg));
196.525 + e->d[0] = e->d[1] = e->d[2] = 0;
196.526 + e->d[3] = e->d[4] = e->d[5] = 0;
196.527 + e->next = NULL;
196.528 + if (z->ptr == NULL)
196.529 + z->ptr = e;
196.530 + else
196.531 + es->next = e;
196.532 + es = e;
196.533 + k = 0;
196.534 + }
196.535 + es->d[k++] = wx[n];
196.536 + }
196.537 + normalize(z);
196.538 +done: return;
196.539 +}
196.540 +
196.541 +void mpz_neg(mpz_t z, mpz_t x)
196.542 +{ /* set z to 0 - x */
196.543 + mpz_set(z, x);
196.544 + z->val = - z->val;
196.545 + return;
196.546 +}
196.547 +
196.548 +void mpz_abs(mpz_t z, mpz_t x)
196.549 +{ /* set z to the absolute value of x */
196.550 + mpz_set(z, x);
196.551 + if (z->val < 0) z->val = - z->val;
196.552 + return;
196.553 +}
196.554 +
196.555 +void mpz_div(mpz_t q, mpz_t r, mpz_t x, mpz_t y)
196.556 +{ /* divide x by y, forming quotient q and/or remainder r
196.557 + if q = NULL then quotient is not stored; if r = NULL then
196.558 + remainder is not stored
196.559 + the sign of quotient is determined as in algebra while the
196.560 + sign of remainder is the same as the sign of dividend:
196.561 + +26 : +7 = +3, remainder is +5
196.562 + -26 : +7 = -3, remainder is -5
196.563 + +26 : -7 = -3, remainder is +5
196.564 + -26 : -7 = +3, remainder is -5 */
196.565 + struct mpz_seg dumx, dumy, *ex, *ey, *es, *e;
196.566 + int sx, sy, k, nx, ny, n;
196.567 + unsigned int t;
196.568 + unsigned short *work, *wx, *wy;
196.569 + /* divide by zero is not allowed */
196.570 + if (y->val == 0)
196.571 + { xassert(y->ptr == NULL);
196.572 + xfault("mpz_div: divide by zero not allowed\n");
196.573 + }
196.574 + /* if [x] = 0 then [q] = [r] = 0 */
196.575 + if (x->val == 0)
196.576 + { xassert(x->ptr == NULL);
196.577 + if (q != NULL) mpz_set_si(q, 0);
196.578 + if (r != NULL) mpz_set_si(r, 0);
196.579 + goto done;
196.580 + }
196.581 + /* special case when both [x] and [y] are in short format */
196.582 + if (x->ptr == NULL && y->ptr == NULL)
196.583 + { int xval = x->val, yval = y->val;
196.584 + xassert(xval != 0x80000000 && yval != 0x80000000);
196.585 + if (q != NULL) mpz_set_si(q, xval / yval);
196.586 + if (r != NULL) mpz_set_si(r, xval % yval);
196.587 + goto done;
196.588 + }
196.589 + /* convert [x] to long format, if necessary */
196.590 + if (x->ptr == NULL)
196.591 + { xassert(x->val != 0x80000000);
196.592 + if (x->val >= 0)
196.593 + { sx = +1;
196.594 + t = (unsigned int)(+ x->val);
196.595 + }
196.596 + else
196.597 + { sx = -1;
196.598 + t = (unsigned int)(- x->val);
196.599 + }
196.600 + ex = &dumx;
196.601 + ex->d[0] = (unsigned short)t;
196.602 + ex->d[1] = (unsigned short)(t >> 16);
196.603 + ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0;
196.604 + ex->next = NULL;
196.605 + }
196.606 + else
196.607 + { sx = x->val;
196.608 + xassert(sx == +1 || sx == -1);
196.609 + ex = x->ptr;
196.610 + }
196.611 + /* convert [y] to long format, if necessary */
196.612 + if (y->ptr == NULL)
196.613 + { xassert(y->val != 0x80000000);
196.614 + if (y->val >= 0)
196.615 + { sy = +1;
196.616 + t = (unsigned int)(+ y->val);
196.617 + }
196.618 + else
196.619 + { sy = -1;
196.620 + t = (unsigned int)(- y->val);
196.621 + }
196.622 + ey = &dumy;
196.623 + ey->d[0] = (unsigned short)t;
196.624 + ey->d[1] = (unsigned short)(t >> 16);
196.625 + ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0;
196.626 + ey->next = NULL;
196.627 + }
196.628 + else
196.629 + { sy = y->val;
196.630 + xassert(sy == +1 || sy == -1);
196.631 + ey = y->ptr;
196.632 + }
196.633 + /* determine the number of digits of [x] */
196.634 + nx = n = 0;
196.635 + for (e = ex; e != NULL; e = e->next)
196.636 + for (k = 0; k <= 5; k++)
196.637 + { n++;
196.638 + if (e->d[k]) nx = n;
196.639 + }
196.640 + xassert(nx > 0);
196.641 + /* determine the number of digits of [y] */
196.642 + ny = n = 0;
196.643 + for (e = ey; e != NULL; e = e->next)
196.644 + for (k = 0; k <= 5; k++)
196.645 + { n++;
196.646 + if (e->d[k]) ny = n;
196.647 + }
196.648 + xassert(ny > 0);
196.649 + /* if nx < ny then [q] = 0 and [r] = [x] */
196.650 + if (nx < ny)
196.651 + { if (r != NULL) mpz_set(r, x);
196.652 + if (q != NULL) mpz_set_si(q, 0);
196.653 + goto done;
196.654 + }
196.655 + /* we need working array containing at least nx+ny+1 places */
196.656 + work = gmp_get_work(nx+ny+1);
196.657 + /* load digits of [x] */
196.658 + wx = &work[0];
196.659 + for (n = 0; n < nx; n++) wx[n] = 0;
196.660 + for (n = 0, e = ex; e != NULL; e = e->next)
196.661 + for (k = 0; k <= 5; k++, n++)
196.662 + if (e->d[k]) wx[n] = e->d[k];
196.663 + /* load digits of [y] */
196.664 + wy = &work[nx+1];
196.665 + for (n = 0; n < ny; n++) wy[n] = 0;
196.666 + for (n = 0, e = ey; e != NULL; e = e->next)
196.667 + for (k = 0; k <= 5; k++, n++)
196.668 + if (e->d[k]) wy[n] = e->d[k];
196.669 + /* compute quotient and remainder */
196.670 + xassert(wy[ny-1] != 0);
196.671 + bigdiv(nx-ny, ny, wx, wy);
196.672 + /* construct and normalize quotient */
196.673 + if (q != NULL)
196.674 + { mpz_set_si(q, 0);
196.675 + q->val = sx * sy;
196.676 + es = NULL;
196.677 + k = 6;
196.678 + for (n = ny; n <= nx; n++)
196.679 + { if (k > 5)
196.680 + { e = gmp_get_atom(sizeof(struct mpz_seg));
196.681 + e->d[0] = e->d[1] = e->d[2] = 0;
196.682 + e->d[3] = e->d[4] = e->d[5] = 0;
196.683 + e->next = NULL;
196.684 + if (q->ptr == NULL)
196.685 + q->ptr = e;
196.686 + else
196.687 + es->next = e;
196.688 + es = e;
196.689 + k = 0;
196.690 + }
196.691 + es->d[k++] = wx[n];
196.692 + }
196.693 + normalize(q);
196.694 + }
196.695 + /* construct and normalize remainder */
196.696 + if (r != NULL)
196.697 + { mpz_set_si(r, 0);
196.698 + r->val = sx;
196.699 + es = NULL;
196.700 + k = 6;
196.701 + for (n = 0; n < ny; n++)
196.702 + { if (k > 5)
196.703 + { e = gmp_get_atom(sizeof(struct mpz_seg));
196.704 + e->d[0] = e->d[1] = e->d[2] = 0;
196.705 + e->d[3] = e->d[4] = e->d[5] = 0;
196.706 + e->next = NULL;
196.707 + if (r->ptr == NULL)
196.708 + r->ptr = e;
196.709 + else
196.710 + es->next = e;
196.711 + es = e;
196.712 + k = 0;
196.713 + }
196.714 + es->d[k++] = wx[n];
196.715 + }
196.716 + normalize(r);
196.717 + }
196.718 +done: return;
196.719 +}
196.720 +
196.721 +void mpz_gcd(mpz_t z, mpz_t x, mpz_t y)
196.722 +{ /* set z to the greatest common divisor of x and y */
196.723 + /* in case of arbitrary integers GCD(x, y) = GCD(|x|, |y|), and,
196.724 + in particular, GCD(0, 0) = 0 */
196.725 + mpz_t u, v, r;
196.726 + mpz_init(u);
196.727 + mpz_init(v);
196.728 + mpz_init(r);
196.729 + mpz_abs(u, x);
196.730 + mpz_abs(v, y);
196.731 + while (mpz_sgn(v))
196.732 + { mpz_div(NULL, r, u, v);
196.733 + mpz_set(u, v);
196.734 + mpz_set(v, r);
196.735 + }
196.736 + mpz_set(z, u);
196.737 + mpz_clear(u);
196.738 + mpz_clear(v);
196.739 + mpz_clear(r);
196.740 + return;
196.741 +}
196.742 +
196.743 +int mpz_cmp(mpz_t x, mpz_t y)
196.744 +{ /* compare x and y; return a positive value if x > y, zero if
196.745 + x = y, or a nefative value if x < y */
196.746 + static struct mpz_seg zero = { { 0, 0, 0, 0, 0, 0 }, NULL };
196.747 + struct mpz_seg dumx, dumy, *ex, *ey;
196.748 + int cc, sx, sy, k;
196.749 + unsigned int t;
196.750 + if (x == y)
196.751 + { cc = 0;
196.752 + goto done;
196.753 + }
196.754 + /* special case when both [x] and [y] are in short format */
196.755 + if (x->ptr == NULL && y->ptr == NULL)
196.756 + { int xval = x->val, yval = y->val;
196.757 + xassert(xval != 0x80000000 && yval != 0x80000000);
196.758 + cc = (xval > yval ? +1 : xval < yval ? -1 : 0);
196.759 + goto done;
196.760 + }
196.761 + /* special case when [x] and [y] have different signs */
196.762 + if (x->val > 0 && y->val <= 0 || x->val == 0 && y->val < 0)
196.763 + { cc = +1;
196.764 + goto done;
196.765 + }
196.766 + if (x->val < 0 && y->val >= 0 || x->val == 0 && y->val > 0)
196.767 + { cc = -1;
196.768 + goto done;
196.769 + }
196.770 + /* convert [x] to long format, if necessary */
196.771 + if (x->ptr == NULL)
196.772 + { xassert(x->val != 0x80000000);
196.773 + if (x->val >= 0)
196.774 + { sx = +1;
196.775 + t = (unsigned int)(+ x->val);
196.776 + }
196.777 + else
196.778 + { sx = -1;
196.779 + t = (unsigned int)(- x->val);
196.780 + }
196.781 + ex = &dumx;
196.782 + ex->d[0] = (unsigned short)t;
196.783 + ex->d[1] = (unsigned short)(t >> 16);
196.784 + ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0;
196.785 + ex->next = NULL;
196.786 + }
196.787 + else
196.788 + { sx = x->val;
196.789 + xassert(sx == +1 || sx == -1);
196.790 + ex = x->ptr;
196.791 + }
196.792 + /* convert [y] to long format, if necessary */
196.793 + if (y->ptr == NULL)
196.794 + { xassert(y->val != 0x80000000);
196.795 + if (y->val >= 0)
196.796 + { sy = +1;
196.797 + t = (unsigned int)(+ y->val);
196.798 + }
196.799 + else
196.800 + { sy = -1;
196.801 + t = (unsigned int)(- y->val);
196.802 + }
196.803 + ey = &dumy;
196.804 + ey->d[0] = (unsigned short)t;
196.805 + ey->d[1] = (unsigned short)(t >> 16);
196.806 + ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0;
196.807 + ey->next = NULL;
196.808 + }
196.809 + else
196.810 + { sy = y->val;
196.811 + xassert(sy == +1 || sy == -1);
196.812 + ey = y->ptr;
196.813 + }
196.814 + /* main fragment */
196.815 + xassert(sx > 0 && sy > 0 || sx < 0 && sy < 0);
196.816 + cc = 0;
196.817 + for (; ex || ey; ex = ex->next, ey = ey->next)
196.818 + { if (ex == NULL) ex = &zero;
196.819 + if (ey == NULL) ey = &zero;
196.820 + for (k = 0; k <= 5; k++)
196.821 + { if (ex->d[k] > ey->d[k]) cc = +1;
196.822 + if (ex->d[k] < ey->d[k]) cc = -1;
196.823 + }
196.824 + }
196.825 + if (sx < 0) cc = - cc;
196.826 +done: return cc;
196.827 +}
196.828 +
196.829 +int mpz_sgn(mpz_t x)
196.830 +{ /* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */
196.831 + int s;
196.832 + s = (x->val > 0 ? +1 : x->val < 0 ? -1 : 0);
196.833 + return s;
196.834 +}
196.835 +
196.836 +int mpz_out_str(void *_fp, int base, mpz_t x)
196.837 +{ /* output x on stream fp, as a string in given base; the base
196.838 + may vary from 2 to 36;
196.839 + return the number of bytes written, or if an error occurred,
196.840 + return 0 */
196.841 + FILE *fp = _fp;
196.842 + mpz_t b, y, r;
196.843 + int n, j, nwr = 0;
196.844 + unsigned char *d;
196.845 + static char *set = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
196.846 + if (!(2 <= base && base <= 36))
196.847 + xfault("mpz_out_str: base = %d; invalid base\n", base);
196.848 + mpz_init(b);
196.849 + mpz_set_si(b, base);
196.850 + mpz_init(y);
196.851 + mpz_init(r);
196.852 + /* determine the number of digits */
196.853 + mpz_abs(y, x);
196.854 + for (n = 0; mpz_sgn(y) != 0; n++)
196.855 + mpz_div(y, NULL, y, b);
196.856 + if (n == 0) n = 1;
196.857 + /* compute the digits */
196.858 + d = xmalloc(n);
196.859 + mpz_abs(y, x);
196.860 + for (j = 0; j < n; j++)
196.861 + { mpz_div(y, r, y, b);
196.862 + xassert(0 <= r->val && r->val < base && r->ptr == NULL);
196.863 + d[j] = (unsigned char)r->val;
196.864 + }
196.865 + /* output the integer to the stream */
196.866 + if (fp == NULL) fp = stdout;
196.867 + if (mpz_sgn(x) < 0)
196.868 + fputc('-', fp), nwr++;
196.869 + for (j = n-1; j >= 0; j--)
196.870 + fputc(set[d[j]], fp), nwr++;
196.871 + if (ferror(fp)) nwr = 0;
196.872 + mpz_clear(b);
196.873 + mpz_clear(y);
196.874 + mpz_clear(r);
196.875 + xfree(d);
196.876 + return nwr;
196.877 +}
196.878 +
196.879 +/*====================================================================*/
196.880 +
196.881 +mpq_t _mpq_init(void)
196.882 +{ /* initialize x, and set its value to 0/1 */
196.883 + mpq_t x;
196.884 + x = gmp_get_atom(sizeof(struct mpq));
196.885 + x->p.val = 0;
196.886 + x->p.ptr = NULL;
196.887 + x->q.val = 1;
196.888 + x->q.ptr = NULL;
196.889 + return x;
196.890 +}
196.891 +
196.892 +void mpq_clear(mpq_t x)
196.893 +{ /* free the space occupied by x */
196.894 + mpz_set_si(&x->p, 0);
196.895 + xassert(x->p.ptr == NULL);
196.896 + mpz_set_si(&x->q, 0);
196.897 + xassert(x->q.ptr == NULL);
196.898 + /* free the number descriptor */
196.899 + gmp_free_atom(x, sizeof(struct mpq));
196.900 + return;
196.901 +}
196.902 +
196.903 +void mpq_canonicalize(mpq_t x)
196.904 +{ /* remove any factors that are common to the numerator and
196.905 + denominator of x, and make the denominator positive */
196.906 + mpz_t f;
196.907 + xassert(x->q.val != 0);
196.908 + if (x->q.val < 0)
196.909 + { mpz_neg(&x->p, &x->p);
196.910 + mpz_neg(&x->q, &x->q);
196.911 + }
196.912 + mpz_init(f);
196.913 + mpz_gcd(f, &x->p, &x->q);
196.914 + if (!(f->val == 1 && f->ptr == NULL))
196.915 + { mpz_div(&x->p, NULL, &x->p, f);
196.916 + mpz_div(&x->q, NULL, &x->q, f);
196.917 + }
196.918 + mpz_clear(f);
196.919 + return;
196.920 +}
196.921 +
196.922 +void mpq_set(mpq_t z, mpq_t x)
196.923 +{ /* set the value of z from x */
196.924 + if (z != x)
196.925 + { mpz_set(&z->p, &x->p);
196.926 + mpz_set(&z->q, &x->q);
196.927 + }
196.928 + return;
196.929 +}
196.930 +
196.931 +void mpq_set_si(mpq_t x, int p, unsigned int q)
196.932 +{ /* set the value of x to p/q */
196.933 + if (q == 0)
196.934 + xfault("mpq_set_si: zero denominator not allowed\n");
196.935 + mpz_set_si(&x->p, p);
196.936 + xassert(q <= 0x7FFFFFFF);
196.937 + mpz_set_si(&x->q, q);
196.938 + return;
196.939 +}
196.940 +
196.941 +double mpq_get_d(mpq_t x)
196.942 +{ /* convert x to a double, truncating if necessary */
196.943 + int np, nq;
196.944 + double p, q;
196.945 + p = mpz_get_d_2exp(&np, &x->p);
196.946 + q = mpz_get_d_2exp(&nq, &x->q);
196.947 + return ldexp(p / q, np - nq);
196.948 +}
196.949 +
196.950 +void mpq_set_d(mpq_t x, double val)
196.951 +{ /* set x to val; there is no rounding, the conversion is exact */
196.952 + int s, n, d, j;
196.953 + double f;
196.954 + mpz_t temp;
196.955 + xassert(-DBL_MAX <= val && val <= +DBL_MAX);
196.956 + mpq_set_si(x, 0, 1);
196.957 + if (val > 0.0)
196.958 + s = +1;
196.959 + else if (val < 0.0)
196.960 + s = -1;
196.961 + else
196.962 + goto done;
196.963 + f = frexp(fabs(val), &n);
196.964 + /* |val| = f * 2^n, where 0.5 <= f < 1.0 */
196.965 + mpz_init(temp);
196.966 + while (f != 0.0)
196.967 + { f *= 16.0, n -= 4;
196.968 + d = (int)f;
196.969 + xassert(0 <= d && d <= 15);
196.970 + f -= (double)d;
196.971 + /* x := 16 * x + d */
196.972 + mpz_set_si(temp, 16);
196.973 + mpz_mul(&x->p, &x->p, temp);
196.974 + mpz_set_si(temp, d);
196.975 + mpz_add(&x->p, &x->p, temp);
196.976 + }
196.977 + mpz_clear(temp);
196.978 + /* x := x * 2^n */
196.979 + if (n > 0)
196.980 + { for (j = 1; j <= n; j++)
196.981 + mpz_add(&x->p, &x->p, &x->p);
196.982 + }
196.983 + else if (n < 0)
196.984 + { for (j = 1; j <= -n; j++)
196.985 + mpz_add(&x->q, &x->q, &x->q);
196.986 + mpq_canonicalize(x);
196.987 + }
196.988 + if (s < 0) mpq_neg(x, x);
196.989 +done: return;
196.990 +}
196.991 +
196.992 +void mpq_add(mpq_t z, mpq_t x, mpq_t y)
196.993 +{ /* set z to x + y */
196.994 + mpz_t p, q;
196.995 + mpz_init(p);
196.996 + mpz_init(q);
196.997 + mpz_mul(p, &x->p, &y->q);
196.998 + mpz_mul(q, &x->q, &y->p);
196.999 + mpz_add(p, p, q);
196.1000 + mpz_mul(q, &x->q, &y->q);
196.1001 + mpz_set(&z->p, p);
196.1002 + mpz_set(&z->q, q);
196.1003 + mpz_clear(p);
196.1004 + mpz_clear(q);
196.1005 + mpq_canonicalize(z);
196.1006 + return;
196.1007 +}
196.1008 +
196.1009 +void mpq_sub(mpq_t z, mpq_t x, mpq_t y)
196.1010 +{ /* set z to x - y */
196.1011 + mpz_t p, q;
196.1012 + mpz_init(p);
196.1013 + mpz_init(q);
196.1014 + mpz_mul(p, &x->p, &y->q);
196.1015 + mpz_mul(q, &x->q, &y->p);
196.1016 + mpz_sub(p, p, q);
196.1017 + mpz_mul(q, &x->q, &y->q);
196.1018 + mpz_set(&z->p, p);
196.1019 + mpz_set(&z->q, q);
196.1020 + mpz_clear(p);
196.1021 + mpz_clear(q);
196.1022 + mpq_canonicalize(z);
196.1023 + return;
196.1024 +}
196.1025 +
196.1026 +void mpq_mul(mpq_t z, mpq_t x, mpq_t y)
196.1027 +{ /* set z to x * y */
196.1028 + mpz_mul(&z->p, &x->p, &y->p);
196.1029 + mpz_mul(&z->q, &x->q, &y->q);
196.1030 + mpq_canonicalize(z);
196.1031 + return;
196.1032 +}
196.1033 +
196.1034 +void mpq_div(mpq_t z, mpq_t x, mpq_t y)
196.1035 +{ /* set z to x / y */
196.1036 + mpz_t p, q;
196.1037 + if (mpq_sgn(y) == 0)
196.1038 + xfault("mpq_div: zero divisor not allowed\n");
196.1039 + mpz_init(p);
196.1040 + mpz_init(q);
196.1041 + mpz_mul(p, &x->p, &y->q);
196.1042 + mpz_mul(q, &x->q, &y->p);
196.1043 + mpz_set(&z->p, p);
196.1044 + mpz_set(&z->q, q);
196.1045 + mpz_clear(p);
196.1046 + mpz_clear(q);
196.1047 + mpq_canonicalize(z);
196.1048 + return;
196.1049 +}
196.1050 +
196.1051 +void mpq_neg(mpq_t z, mpq_t x)
196.1052 +{ /* set z to 0 - x */
196.1053 + mpq_set(z, x);
196.1054 + mpz_neg(&z->p, &z->p);
196.1055 + return;
196.1056 +}
196.1057 +
196.1058 +void mpq_abs(mpq_t z, mpq_t x)
196.1059 +{ /* set z to the absolute value of x */
196.1060 + mpq_set(z, x);
196.1061 + mpz_abs(&z->p, &z->p);
196.1062 + xassert(mpz_sgn(&x->q) > 0);
196.1063 + return;
196.1064 +}
196.1065 +
196.1066 +int mpq_cmp(mpq_t x, mpq_t y)
196.1067 +{ /* compare x and y; return a positive value if x > y, zero if
196.1068 + x = y, or a nefative value if x < y */
196.1069 + mpq_t temp;
196.1070 + int s;
196.1071 + mpq_init(temp);
196.1072 + mpq_sub(temp, x, y);
196.1073 + s = mpq_sgn(temp);
196.1074 + mpq_clear(temp);
196.1075 + return s;
196.1076 +}
196.1077 +
196.1078 +int mpq_sgn(mpq_t x)
196.1079 +{ /* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */
196.1080 + int s;
196.1081 + s = mpz_sgn(&x->p);
196.1082 + xassert(mpz_sgn(&x->q) > 0);
196.1083 + return s;
196.1084 +}
196.1085 +
196.1086 +int mpq_out_str(void *_fp, int base, mpq_t x)
196.1087 +{ /* output x on stream fp, as a string in given base; the base
196.1088 + may vary from 2 to 36; output is in the form 'num/den' or if
196.1089 + the denominator is 1 then just 'num';
196.1090 + if the parameter fp is a null pointer, stdout is assumed;
196.1091 + return the number of bytes written, or if an error occurred,
196.1092 + return 0 */
196.1093 + FILE *fp = _fp;
196.1094 + int nwr;
196.1095 + if (!(2 <= base && base <= 36))
196.1096 + xfault("mpq_out_str: base = %d; invalid base\n", base);
196.1097 + if (fp == NULL) fp = stdout;
196.1098 + nwr = mpz_out_str(fp, base, &x->p);
196.1099 + if (x->q.val == 1 && x->q.ptr == NULL)
196.1100 + ;
196.1101 + else
196.1102 + { fputc('/', fp), nwr++;
196.1103 + nwr += mpz_out_str(fp, base, &x->q);
196.1104 + }
196.1105 + if (ferror(fp)) nwr = 0;
196.1106 + return nwr;
196.1107 +}
196.1108 +
196.1109 +#endif
196.1110 +
196.1111 +/* eof */
197.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
197.2 +++ b/src/glpgmp.h Mon Dec 06 13:09:21 2010 +0100
197.3 @@ -0,0 +1,190 @@
197.4 +/* glpgmp.h (bignum arithmetic) */
197.5 +
197.6 +/***********************************************************************
197.7 +* This code is part of GLPK (GNU Linear Programming Kit).
197.8 +*
197.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
197.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
197.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
197.12 +* E-mail: <mao@gnu.org>.
197.13 +*
197.14 +* GLPK is free software: you can redistribute it and/or modify it
197.15 +* under the terms of the GNU General Public License as published by
197.16 +* the Free Software Foundation, either version 3 of the License, or
197.17 +* (at your option) any later version.
197.18 +*
197.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
197.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
197.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
197.22 +* License for more details.
197.23 +*
197.24 +* You should have received a copy of the GNU General Public License
197.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
197.26 +***********************************************************************/
197.27 +
197.28 +#ifndef GLPGMP_H
197.29 +#define GLPGMP_H
197.30 +
197.31 +#ifdef HAVE_CONFIG_H
197.32 +#include <config.h>
197.33 +#endif
197.34 +
197.35 +#ifdef HAVE_GMP /* use GNU MP bignum library */
197.36 +
197.37 +#include <gmp.h>
197.38 +
197.39 +#define gmp_pool_count _glp_gmp_pool_count
197.40 +#define gmp_free_mem _glp_gmp_free_mem
197.41 +
197.42 +int gmp_pool_count(void);
197.43 +void gmp_free_mem(void);
197.44 +
197.45 +#else /* use GLPK bignum module */
197.46 +
197.47 +/*----------------------------------------------------------------------
197.48 +// INTEGER NUMBERS
197.49 +//
197.50 +// Depending on its magnitude an integer number of arbitrary precision
197.51 +// is represented either in short format or in long format.
197.52 +//
197.53 +// Short format corresponds to the int type and allows representing
197.54 +// integer numbers in the range [-(2^31-1), +(2^31-1)]. Note that for
197.55 +// the most negative number of int type the short format is not used.
197.56 +//
197.57 +// In long format integer numbers are represented using the positional
197.58 +// system with the base (radix) 2^16 = 65536:
197.59 +//
197.60 +// x = (-1)^s sum{j in 0..n-1} d[j] * 65536^j,
197.61 +//
197.62 +// where x is the integer to be represented, s is its sign (+1 or -1),
197.63 +// d[j] are its digits (0 <= d[j] <= 65535).
197.64 +//
197.65 +// RATIONAL NUMBERS
197.66 +//
197.67 +// A rational number is represented as an irreducible fraction:
197.68 +//
197.69 +// p / q,
197.70 +//
197.71 +// where p (numerator) and q (denominator) are integer numbers (q > 0)
197.72 +// having no common divisors. */
197.73 +
197.74 +struct mpz
197.75 +{ /* integer number */
197.76 + int val;
197.77 + /* if ptr is a null pointer, the number is in short format, and
197.78 + val is its value; otherwise, the number is in long format, and
197.79 + val is its sign (+1 or -1) */
197.80 + struct mpz_seg *ptr;
197.81 + /* pointer to the linked list of the number segments ordered in
197.82 + ascending of powers of the base */
197.83 +};
197.84 +
197.85 +struct mpz_seg
197.86 +{ /* integer number segment */
197.87 + unsigned short d[6];
197.88 + /* six digits of the number ordered in ascending of powers of the
197.89 + base */
197.90 + struct mpz_seg *next;
197.91 + /* pointer to the next number segment */
197.92 +};
197.93 +
197.94 +struct mpq
197.95 +{ /* rational number (p / q) */
197.96 + struct mpz p;
197.97 + /* numerator */
197.98 + struct mpz q;
197.99 + /* denominator */
197.100 +};
197.101 +
197.102 +typedef struct mpz *mpz_t;
197.103 +typedef struct mpq *mpq_t;
197.104 +
197.105 +#define gmp_get_atom _glp_gmp_get_atom
197.106 +#define gmp_free_atom _glp_gmp_free_atom
197.107 +#define gmp_pool_count _glp_gmp_pool_count
197.108 +#define gmp_get_work _glp_gmp_get_work
197.109 +#define gmp_free_mem _glp_gmp_free_mem
197.110 +
197.111 +#define _mpz_init _glp_mpz_init
197.112 +#define mpz_clear _glp_mpz_clear
197.113 +#define mpz_set _glp_mpz_set
197.114 +#define mpz_set_si _glp_mpz_set_si
197.115 +#define mpz_get_d _glp_mpz_get_d
197.116 +#define mpz_get_d_2exp _glp_mpz_get_d_2exp
197.117 +#define mpz_swap _glp_mpz_swap
197.118 +#define mpz_add _glp_mpz_add
197.119 +#define mpz_sub _glp_mpz_sub
197.120 +#define mpz_mul _glp_mpz_mul
197.121 +#define mpz_neg _glp_mpz_neg
197.122 +#define mpz_abs _glp_mpz_abs
197.123 +#define mpz_div _glp_mpz_div
197.124 +#define mpz_gcd _glp_mpz_gcd
197.125 +#define mpz_cmp _glp_mpz_cmp
197.126 +#define mpz_sgn _glp_mpz_sgn
197.127 +#define mpz_out_str _glp_mpz_out_str
197.128 +
197.129 +#define _mpq_init _glp_mpq_init
197.130 +#define mpq_clear _glp_mpq_clear
197.131 +#define mpq_canonicalize _glp_mpq_canonicalize
197.132 +#define mpq_set _glp_mpq_set
197.133 +#define mpq_set_si _glp_mpq_set_si
197.134 +#define mpq_get_d _glp_mpq_get_d
197.135 +#define mpq_set_d _glp_mpq_set_d
197.136 +#define mpq_add _glp_mpq_add
197.137 +#define mpq_sub _glp_mpq_sub
197.138 +#define mpq_mul _glp_mpq_mul
197.139 +#define mpq_div _glp_mpq_div
197.140 +#define mpq_neg _glp_mpq_neg
197.141 +#define mpq_abs _glp_mpq_abs
197.142 +#define mpq_cmp _glp_mpq_cmp
197.143 +#define mpq_sgn _glp_mpq_sgn
197.144 +#define mpq_out_str _glp_mpq_out_str
197.145 +
197.146 +void *gmp_get_atom(int size);
197.147 +void gmp_free_atom(void *ptr, int size);
197.148 +int gmp_pool_count(void);
197.149 +unsigned short *gmp_get_work(int size);
197.150 +void gmp_free_mem(void);
197.151 +
197.152 +mpz_t _mpz_init(void);
197.153 +#define mpz_init(x) (void)((x) = _mpz_init())
197.154 +void mpz_clear(mpz_t x);
197.155 +void mpz_set(mpz_t z, mpz_t x);
197.156 +void mpz_set_si(mpz_t x, int val);
197.157 +double mpz_get_d(mpz_t x);
197.158 +double mpz_get_d_2exp(int *exp, mpz_t x);
197.159 +void mpz_swap(mpz_t x, mpz_t y);
197.160 +void mpz_add(mpz_t, mpz_t, mpz_t);
197.161 +void mpz_sub(mpz_t, mpz_t, mpz_t);
197.162 +void mpz_mul(mpz_t, mpz_t, mpz_t);
197.163 +void mpz_neg(mpz_t z, mpz_t x);
197.164 +void mpz_abs(mpz_t z, mpz_t x);
197.165 +void mpz_div(mpz_t q, mpz_t r, mpz_t x, mpz_t y);
197.166 +void mpz_gcd(mpz_t z, mpz_t x, mpz_t y);
197.167 +int mpz_cmp(mpz_t x, mpz_t y);
197.168 +int mpz_sgn(mpz_t x);
197.169 +int mpz_out_str(void *fp, int base, mpz_t x);
197.170 +
197.171 +mpq_t _mpq_init(void);
197.172 +#define mpq_init(x) (void)((x) = _mpq_init())
197.173 +void mpq_clear(mpq_t x);
197.174 +void mpq_canonicalize(mpq_t x);
197.175 +void mpq_set(mpq_t z, mpq_t x);
197.176 +void mpq_set_si(mpq_t x, int p, unsigned int q);
197.177 +double mpq_get_d(mpq_t x);
197.178 +void mpq_set_d(mpq_t x, double val);
197.179 +void mpq_add(mpq_t z, mpq_t x, mpq_t y);
197.180 +void mpq_sub(mpq_t z, mpq_t x, mpq_t y);
197.181 +void mpq_mul(mpq_t z, mpq_t x, mpq_t y);
197.182 +void mpq_div(mpq_t z, mpq_t x, mpq_t y);
197.183 +void mpq_neg(mpq_t z, mpq_t x);
197.184 +void mpq_abs(mpq_t z, mpq_t x);
197.185 +int mpq_cmp(mpq_t x, mpq_t y);
197.186 +int mpq_sgn(mpq_t x);
197.187 +int mpq_out_str(void *fp, int base, mpq_t x);
197.188 +
197.189 +#endif
197.190 +
197.191 +#endif
197.192 +
197.193 +/* eof */
198.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
198.2 +++ b/src/glphbm.c Mon Dec 06 13:09:21 2010 +0100
198.3 @@ -0,0 +1,519 @@
198.4 +/* glphbm.c */
198.5 +
198.6 +/***********************************************************************
198.7 +* This code is part of GLPK (GNU Linear Programming Kit).
198.8 +*
198.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
198.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
198.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
198.12 +* E-mail: <mao@gnu.org>.
198.13 +*
198.14 +* GLPK is free software: you can redistribute it and/or modify it
198.15 +* under the terms of the GNU General Public License as published by
198.16 +* the Free Software Foundation, either version 3 of the License, or
198.17 +* (at your option) any later version.
198.18 +*
198.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
198.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
198.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
198.22 +* License for more details.
198.23 +*
198.24 +* You should have received a copy of the GNU General Public License
198.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
198.26 +***********************************************************************/
198.27 +
198.28 +#define _GLPSTD_ERRNO
198.29 +#define _GLPSTD_STDIO
198.30 +#include "glphbm.h"
198.31 +#include "glpenv.h"
198.32 +
198.33 +/***********************************************************************
198.34 +* NAME
198.35 +*
198.36 +* hbm_read_mat - read sparse matrix in Harwell-Boeing format
198.37 +*
198.38 +* SYNOPSIS
198.39 +*
198.40 +* #include "glphbm.h"
198.41 +* HBM *hbm_read_mat(const char *fname);
198.42 +*
198.43 +* DESCRIPTION
198.44 +*
198.45 +* The routine hbm_read_mat reads a sparse matrix in the Harwell-Boeing
198.46 +* format from a text file whose name is the character string fname.
198.47 +*
198.48 +* Detailed description of the Harwell-Boeing format recognised by this
198.49 +* routine is given in the following report:
198.50 +*
198.51 +* I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the Harwell-Boeing
198.52 +* Sparse Matrix Collection (Release I), TR/PA/92/86, October 1992.
198.53 +*
198.54 +* RETURNS
198.55 +*
198.56 +* If no error occured, the routine hbm_read_mat returns a pointer to
198.57 +* a data structure containing the matrix. In case of error the routine
198.58 +* prints an appropriate error message and returns NULL. */
198.59 +
198.60 +struct dsa
198.61 +{ /* working area used by routine hbm_read_mat */
198.62 + const char *fname;
198.63 + /* name of input text file */
198.64 + FILE *fp;
198.65 + /* stream assigned to input text file */
198.66 + int seqn;
198.67 + /* card sequential number */
198.68 + char card[80+1];
198.69 + /* card image buffer */
198.70 + int fmt_p;
198.71 + /* scale factor */
198.72 + int fmt_k;
198.73 + /* iterator */
198.74 + int fmt_f;
198.75 + /* format code */
198.76 + int fmt_w;
198.77 + /* field width */
198.78 + int fmt_d;
198.79 + /* number of decimal places after point */
198.80 +};
198.81 +
198.82 +/***********************************************************************
198.83 +* read_card - read next data card
198.84 +*
198.85 +* This routine reads the next 80-column card from the input text file
198.86 +* and stores its image into the character string card. If the card was
198.87 +* read successfully, the routine returns zero, otherwise non-zero. */
198.88 +
198.89 +static int read_card(struct dsa *dsa)
198.90 +{ int k, c;
198.91 + dsa->seqn++;
198.92 + memset(dsa->card, ' ', 80), dsa->card[80] = '\0';
198.93 + k = 0;
198.94 + for (;;)
198.95 + { c = fgetc(dsa->fp);
198.96 + if (ferror(dsa->fp))
198.97 + { xprintf("%s:%d: read error - %s\n", dsa->fname, dsa->seqn,
198.98 + strerror(errno));
198.99 + return 1;
198.100 + }
198.101 + if (feof(dsa->fp))
198.102 + { if (k == 0)
198.103 + xprintf("%s:%d: unexpected EOF\n", dsa->fname,
198.104 + dsa->seqn);
198.105 + else
198.106 + xprintf("%s:%d: missing final LF\n", dsa->fname,
198.107 + dsa->seqn);
198.108 + return 1;
198.109 + }
198.110 + if (c == '\r') continue;
198.111 + if (c == '\n') break;
198.112 + if (iscntrl(c))
198.113 + { xprintf("%s:%d: invalid control character 0x%02X\n",
198.114 + dsa->fname, dsa->seqn, c);
198.115 + return 1;
198.116 + }
198.117 + if (k == 80)
198.118 + { xprintf("%s:%d: card image too long\n", dsa->fname,
198.119 + dsa->seqn);
198.120 + return 1;
198.121 + }
198.122 + dsa->card[k++] = (char)c;
198.123 + }
198.124 + return 0;
198.125 +}
198.126 +
198.127 +/***********************************************************************
198.128 +* scan_int - scan integer value from the current card
198.129 +*
198.130 +* This routine scans an integer value from the current card, where fld
198.131 +* is the name of the field, pos is the position of the field, width is
198.132 +* the width of the field, val points to a location to which the scanned
198.133 +* value should be stored. If the value was scanned successfully, the
198.134 +* routine returns zero, otherwise non-zero. */
198.135 +
198.136 +static int scan_int(struct dsa *dsa, char *fld, int pos, int width,
198.137 + int *val)
198.138 +{ char str[80+1];
198.139 + xassert(1 <= width && width <= 80);
198.140 + memcpy(str, dsa->card + pos, width), str[width] = '\0';
198.141 + if (str2int(strspx(str), val))
198.142 + { xprintf("%s:%d: field `%s' contains invalid value `%s'\n",
198.143 + dsa->fname, dsa->seqn, fld, str);
198.144 + return 1;
198.145 + }
198.146 + return 0;
198.147 +}
198.148 +
198.149 +/***********************************************************************
198.150 +* parse_fmt - parse Fortran format specification
198.151 +*
198.152 +* This routine parses the Fortran format specification represented as
198.153 +* character string which fmt points to and stores format elements into
198.154 +* appropriate static locations. Should note that not all valid Fortran
198.155 +* format specifications may be recognised. If the format specification
198.156 +* was recognised, the routine returns zero, otherwise non-zero. */
198.157 +
198.158 +static int parse_fmt(struct dsa *dsa, char *fmt)
198.159 +{ int k, s, val;
198.160 + char str[80+1];
198.161 + /* first character should be left parenthesis */
198.162 + if (fmt[0] != '(')
198.163 +fail: { xprintf("hbm_read_mat: format `%s' not recognised\n", fmt);
198.164 + return 1;
198.165 + }
198.166 + k = 1;
198.167 + /* optional scale factor */
198.168 + dsa->fmt_p = 0;
198.169 + if (isdigit((unsigned char)fmt[k]))
198.170 + { s = 0;
198.171 + while (isdigit((unsigned char)fmt[k]))
198.172 + { if (s == 80) goto fail;
198.173 + str[s++] = fmt[k++];
198.174 + }
198.175 + str[s] = '\0';
198.176 + if (str2int(str, &val)) goto fail;
198.177 + if (toupper((unsigned char)fmt[k]) != 'P') goto iter;
198.178 + dsa->fmt_p = val, k++;
198.179 + if (!(0 <= dsa->fmt_p && dsa->fmt_p <= 255)) goto fail;
198.180 + /* optional comma may follow scale factor */
198.181 + if (fmt[k] == ',') k++;
198.182 + }
198.183 + /* optional iterator */
198.184 + dsa->fmt_k = 1;
198.185 + if (isdigit((unsigned char)fmt[k]))
198.186 + { s = 0;
198.187 + while (isdigit((unsigned char)fmt[k]))
198.188 + { if (s == 80) goto fail;
198.189 + str[s++] = fmt[k++];
198.190 + }
198.191 + str[s] = '\0';
198.192 + if (str2int(str, &val)) goto fail;
198.193 +iter: dsa->fmt_k = val;
198.194 + if (!(1 <= dsa->fmt_k && dsa->fmt_k <= 255)) goto fail;
198.195 + }
198.196 + /* format code */
198.197 + dsa->fmt_f = toupper((unsigned char)fmt[k++]);
198.198 + if (!(dsa->fmt_f == 'D' || dsa->fmt_f == 'E' ||
198.199 + dsa->fmt_f == 'F' || dsa->fmt_f == 'G' ||
198.200 + dsa->fmt_f == 'I')) goto fail;
198.201 + /* field width */
198.202 + if (!isdigit((unsigned char)fmt[k])) goto fail;
198.203 + s = 0;
198.204 + while (isdigit((unsigned char)fmt[k]))
198.205 + { if (s == 80) goto fail;
198.206 + str[s++] = fmt[k++];
198.207 + }
198.208 + str[s] = '\0';
198.209 + if (str2int(str, &dsa->fmt_w)) goto fail;
198.210 + if (!(1 <= dsa->fmt_w && dsa->fmt_w <= 255)) goto fail;
198.211 + /* optional number of decimal places after point */
198.212 + dsa->fmt_d = 0;
198.213 + if (fmt[k] == '.')
198.214 + { k++;
198.215 + if (!isdigit((unsigned char)fmt[k])) goto fail;
198.216 + s = 0;
198.217 + while (isdigit((unsigned char)fmt[k]))
198.218 + { if (s == 80) goto fail;
198.219 + str[s++] = fmt[k++];
198.220 + }
198.221 + str[s] = '\0';
198.222 + if (str2int(str, &dsa->fmt_d)) goto fail;
198.223 + if (!(0 <= dsa->fmt_d && dsa->fmt_d <= 255)) goto fail;
198.224 + }
198.225 + /* last character should be right parenthesis */
198.226 + if (!(fmt[k] == ')' && fmt[k+1] == '\0')) goto fail;
198.227 + return 0;
198.228 +}
198.229 +
198.230 +/***********************************************************************
198.231 +* read_int_array - read array of integer type
198.232 +*
198.233 +* This routine reads an integer array from the input text file, where
198.234 +* name is array name, fmt is Fortran format specification that controls
198.235 +* reading, n is number of array elements, val is array of integer type.
198.236 +* If the array was read successful, the routine returns zero, otherwise
198.237 +* non-zero. */
198.238 +
198.239 +static int read_int_array(struct dsa *dsa, char *name, char *fmt,
198.240 + int n, int val[])
198.241 +{ int k, pos;
198.242 + char str[80+1];
198.243 + if (parse_fmt(dsa, fmt)) return 1;
198.244 + if (!(dsa->fmt_f == 'I' && dsa->fmt_w <= 80 &&
198.245 + dsa->fmt_k * dsa->fmt_w <= 80))
198.246 + { xprintf(
198.247 + "%s:%d: can't read array `%s' - invalid format `%s'\n",
198.248 + dsa->fname, dsa->seqn, name, fmt);
198.249 + return 1;
198.250 + }
198.251 + for (k = 1, pos = INT_MAX; k <= n; k++, pos++)
198.252 + { if (pos >= dsa->fmt_k)
198.253 + { if (read_card(dsa)) return 1;
198.254 + pos = 0;
198.255 + }
198.256 + memcpy(str, dsa->card + dsa->fmt_w * pos, dsa->fmt_w);
198.257 + str[dsa->fmt_w] = '\0';
198.258 + strspx(str);
198.259 + if (str2int(str, &val[k]))
198.260 + { xprintf(
198.261 + "%s:%d: can't read array `%s' - invalid value `%s'\n",
198.262 + dsa->fname, dsa->seqn, name, str);
198.263 + return 1;
198.264 + }
198.265 + }
198.266 + return 0;
198.267 +}
198.268 +
198.269 +/***********************************************************************
198.270 +* read_real_array - read array of real type
198.271 +*
198.272 +* This routine reads a real array from the input text file, where name
198.273 +* is array name, fmt is Fortran format specification that controls
198.274 +* reading, n is number of array elements, val is array of real type.
198.275 +* If the array was read successful, the routine returns zero, otherwise
198.276 +* non-zero. */
198.277 +
198.278 +static int read_real_array(struct dsa *dsa, char *name, char *fmt,
198.279 + int n, double val[])
198.280 +{ int k, pos;
198.281 + char str[80+1], *ptr;
198.282 + if (parse_fmt(dsa, fmt)) return 1;
198.283 + if (!(dsa->fmt_f != 'I' && dsa->fmt_w <= 80 &&
198.284 + dsa->fmt_k * dsa->fmt_w <= 80))
198.285 + { xprintf(
198.286 + "%s:%d: can't read array `%s' - invalid format `%s'\n",
198.287 + dsa->fname, dsa->seqn, name, fmt);
198.288 + return 1;
198.289 + }
198.290 + for (k = 1, pos = INT_MAX; k <= n; k++, pos++)
198.291 + { if (pos >= dsa->fmt_k)
198.292 + { if (read_card(dsa)) return 1;
198.293 + pos = 0;
198.294 + }
198.295 + memcpy(str, dsa->card + dsa->fmt_w * pos, dsa->fmt_w);
198.296 + str[dsa->fmt_w] = '\0';
198.297 + strspx(str);
198.298 + if (strchr(str, '.') == NULL && strcmp(str, "0"))
198.299 + { xprintf("%s(%d): can't read array `%s' - value `%s' has no "
198.300 + "decimal point\n", dsa->fname, dsa->seqn, name, str);
198.301 + return 1;
198.302 + }
198.303 + /* sometimes lower case letters appear */
198.304 + for (ptr = str; *ptr; ptr++)
198.305 + *ptr = (char)toupper((unsigned char)*ptr);
198.306 + ptr = strchr(str, 'D');
198.307 + if (ptr != NULL) *ptr = 'E';
198.308 + /* value may appear with decimal exponent but without letters
198.309 + E or D (for example, -123.456-012), so missing letter should
198.310 + be inserted */
198.311 + ptr = strchr(str+1, '+');
198.312 + if (ptr == NULL) ptr = strchr(str+1, '-');
198.313 + if (ptr != NULL && *(ptr-1) != 'E')
198.314 + { xassert(strlen(str) < 80);
198.315 + memmove(ptr+1, ptr, strlen(ptr)+1);
198.316 + *ptr = 'E';
198.317 + }
198.318 + if (str2num(str, &val[k]))
198.319 + { xprintf(
198.320 + "%s:%d: can't read array `%s' - invalid value `%s'\n",
198.321 + dsa->fname, dsa->seqn, name, str);
198.322 + return 1;
198.323 + }
198.324 + }
198.325 + return 0;
198.326 +}
198.327 +
198.328 +HBM *hbm_read_mat(const char *fname)
198.329 +{ struct dsa _dsa, *dsa = &_dsa;
198.330 + HBM *hbm = NULL;
198.331 + dsa->fname = fname;
198.332 + xprintf("hbm_read_mat: reading matrix from `%s'...\n",
198.333 + dsa->fname);
198.334 + dsa->fp = fopen(dsa->fname, "r");
198.335 + if (dsa->fp == NULL)
198.336 + { xprintf("hbm_read_mat: unable to open `%s' - %s\n",
198.337 + dsa->fname, strerror(errno));
198.338 + goto fail;
198.339 + }
198.340 + dsa->seqn = 0;
198.341 + hbm = xmalloc(sizeof(HBM));
198.342 + memset(hbm, 0, sizeof(HBM));
198.343 + /* read the first heading card */
198.344 + if (read_card(dsa)) goto fail;
198.345 + memcpy(hbm->title, dsa->card, 72), hbm->title[72] = '\0';
198.346 + strtrim(hbm->title);
198.347 + xprintf("%s\n", hbm->title);
198.348 + memcpy(hbm->key, dsa->card+72, 8), hbm->key[8] = '\0';
198.349 + strspx(hbm->key);
198.350 + xprintf("key = %s\n", hbm->key);
198.351 + /* read the second heading card */
198.352 + if (read_card(dsa)) goto fail;
198.353 + if (scan_int(dsa, "totcrd", 0, 14, &hbm->totcrd)) goto fail;
198.354 + if (scan_int(dsa, "ptrcrd", 14, 14, &hbm->ptrcrd)) goto fail;
198.355 + if (scan_int(dsa, "indcrd", 28, 14, &hbm->indcrd)) goto fail;
198.356 + if (scan_int(dsa, "valcrd", 42, 14, &hbm->valcrd)) goto fail;
198.357 + if (scan_int(dsa, "rhscrd", 56, 14, &hbm->rhscrd)) goto fail;
198.358 + xprintf("totcrd = %d; ptrcrd = %d; indcrd = %d; valcrd = %d; rhsc"
198.359 + "rd = %d\n", hbm->totcrd, hbm->ptrcrd, hbm->indcrd,
198.360 + hbm->valcrd, hbm->rhscrd);
198.361 + /* read the third heading card */
198.362 + if (read_card(dsa)) goto fail;
198.363 + memcpy(hbm->mxtype, dsa->card, 3), hbm->mxtype[3] = '\0';
198.364 + if (strchr("RCP", hbm->mxtype[0]) == NULL ||
198.365 + strchr("SUHZR", hbm->mxtype[1]) == NULL ||
198.366 + strchr("AE", hbm->mxtype[2]) == NULL)
198.367 + { xprintf("%s:%d: matrix type `%s' not recognised\n",
198.368 + dsa->fname, dsa->seqn, hbm->mxtype);
198.369 + goto fail;
198.370 + }
198.371 + if (scan_int(dsa, "nrow", 14, 14, &hbm->nrow)) goto fail;
198.372 + if (scan_int(dsa, "ncol", 28, 14, &hbm->ncol)) goto fail;
198.373 + if (scan_int(dsa, "nnzero", 42, 14, &hbm->nnzero)) goto fail;
198.374 + if (scan_int(dsa, "neltvl", 56, 14, &hbm->neltvl)) goto fail;
198.375 + xprintf("mxtype = %s; nrow = %d; ncol = %d; nnzero = %d; neltvl ="
198.376 + " %d\n", hbm->mxtype, hbm->nrow, hbm->ncol, hbm->nnzero,
198.377 + hbm->neltvl);
198.378 + /* read the fourth heading card */
198.379 + if (read_card(dsa)) goto fail;
198.380 + memcpy(hbm->ptrfmt, dsa->card, 16), hbm->ptrfmt[16] = '\0';
198.381 + strspx(hbm->ptrfmt);
198.382 + memcpy(hbm->indfmt, dsa->card+16, 16), hbm->indfmt[16] = '\0';
198.383 + strspx(hbm->indfmt);
198.384 + memcpy(hbm->valfmt, dsa->card+32, 20), hbm->valfmt[20] = '\0';
198.385 + strspx(hbm->valfmt);
198.386 + memcpy(hbm->rhsfmt, dsa->card+52, 20), hbm->rhsfmt[20] = '\0';
198.387 + strspx(hbm->rhsfmt);
198.388 + xprintf("ptrfmt = %s; indfmt = %s; valfmt = %s; rhsfmt = %s\n",
198.389 + hbm->ptrfmt, hbm->indfmt, hbm->valfmt, hbm->rhsfmt);
198.390 + /* read the fifth heading card (optional) */
198.391 + if (hbm->rhscrd <= 0)
198.392 + { strcpy(hbm->rhstyp, "???");
198.393 + hbm->nrhs = 0;
198.394 + hbm->nrhsix = 0;
198.395 + }
198.396 + else
198.397 + { if (read_card(dsa)) goto fail;
198.398 + memcpy(hbm->rhstyp, dsa->card, 3), hbm->rhstyp[3] = '\0';
198.399 + if (scan_int(dsa, "nrhs", 14, 14, &hbm->nrhs)) goto fail;
198.400 + if (scan_int(dsa, "nrhsix", 28, 14, &hbm->nrhsix)) goto fail;
198.401 + xprintf("rhstyp = `%s'; nrhs = %d; nrhsix = %d\n",
198.402 + hbm->rhstyp, hbm->nrhs, hbm->nrhsix);
198.403 + }
198.404 + /* read matrix structure */
198.405 + hbm->colptr = xcalloc(1+hbm->ncol+1, sizeof(int));
198.406 + if (read_int_array(dsa, "colptr", hbm->ptrfmt, hbm->ncol+1,
198.407 + hbm->colptr)) goto fail;
198.408 + hbm->rowind = xcalloc(1+hbm->nnzero, sizeof(int));
198.409 + if (read_int_array(dsa, "rowind", hbm->indfmt, hbm->nnzero,
198.410 + hbm->rowind)) goto fail;
198.411 + /* read matrix values */
198.412 + if (hbm->valcrd <= 0) goto done;
198.413 + if (hbm->mxtype[2] == 'A')
198.414 + { /* assembled matrix */
198.415 + hbm->values = xcalloc(1+hbm->nnzero, sizeof(double));
198.416 + if (read_real_array(dsa, "values", hbm->valfmt, hbm->nnzero,
198.417 + hbm->values)) goto fail;
198.418 + }
198.419 + else
198.420 + { /* elemental (unassembled) matrix */
198.421 + hbm->values = xcalloc(1+hbm->neltvl, sizeof(double));
198.422 + if (read_real_array(dsa, "values", hbm->valfmt, hbm->neltvl,
198.423 + hbm->values)) goto fail;
198.424 + }
198.425 + /* read right-hand sides */
198.426 + if (hbm->nrhs <= 0) goto done;
198.427 + if (hbm->rhstyp[0] == 'F')
198.428 + { /* dense format */
198.429 + hbm->nrhsvl = hbm->nrow * hbm->nrhs;
198.430 + hbm->rhsval = xcalloc(1+hbm->nrhsvl, sizeof(double));
198.431 + if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsvl,
198.432 + hbm->rhsval)) goto fail;
198.433 + }
198.434 + else if (hbm->rhstyp[0] == 'M' && hbm->mxtype[2] == 'A')
198.435 + { /* sparse format */
198.436 + /* read pointers */
198.437 + hbm->rhsptr = xcalloc(1+hbm->nrhs+1, sizeof(int));
198.438 + if (read_int_array(dsa, "rhsptr", hbm->ptrfmt, hbm->nrhs+1,
198.439 + hbm->rhsptr)) goto fail;
198.440 + /* read sparsity pattern */
198.441 + hbm->rhsind = xcalloc(1+hbm->nrhsix, sizeof(int));
198.442 + if (read_int_array(dsa, "rhsind", hbm->indfmt, hbm->nrhsix,
198.443 + hbm->rhsind)) goto fail;
198.444 + /* read values */
198.445 + hbm->rhsval = xcalloc(1+hbm->nrhsix, sizeof(double));
198.446 + if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsix,
198.447 + hbm->rhsval)) goto fail;
198.448 + }
198.449 + else if (hbm->rhstyp[0] == 'M' && hbm->mxtype[2] == 'E')
198.450 + { /* elemental format */
198.451 + hbm->rhsval = xcalloc(1+hbm->nrhsvl, sizeof(double));
198.452 + if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsvl,
198.453 + hbm->rhsval)) goto fail;
198.454 + }
198.455 + else
198.456 + { xprintf("%s:%d: right-hand side type `%c' not recognised\n",
198.457 + dsa->fname, dsa->seqn, hbm->rhstyp[0]);
198.458 + goto fail;
198.459 + }
198.460 + /* read starting guesses */
198.461 + if (hbm->rhstyp[1] == 'G')
198.462 + { hbm->nguess = hbm->nrow * hbm->nrhs;
198.463 + hbm->sguess = xcalloc(1+hbm->nguess, sizeof(double));
198.464 + if (read_real_array(dsa, "sguess", hbm->rhsfmt, hbm->nguess,
198.465 + hbm->sguess)) goto fail;
198.466 + }
198.467 + /* read solution vectors */
198.468 + if (hbm->rhstyp[2] == 'X')
198.469 + { hbm->nexact = hbm->nrow * hbm->nrhs;
198.470 + hbm->xexact = xcalloc(1+hbm->nexact, sizeof(double));
198.471 + if (read_real_array(dsa, "xexact", hbm->rhsfmt, hbm->nexact,
198.472 + hbm->xexact)) goto fail;
198.473 + }
198.474 +done: /* reading has been completed */
198.475 + xprintf("hbm_read_mat: %d cards were read\n", dsa->seqn);
198.476 + fclose(dsa->fp);
198.477 + return hbm;
198.478 +fail: /* something wrong in Danish kingdom */
198.479 + if (hbm != NULL)
198.480 + { if (hbm->colptr != NULL) xfree(hbm->colptr);
198.481 + if (hbm->rowind != NULL) xfree(hbm->rowind);
198.482 + if (hbm->rhsptr != NULL) xfree(hbm->rhsptr);
198.483 + if (hbm->rhsind != NULL) xfree(hbm->rhsind);
198.484 + if (hbm->values != NULL) xfree(hbm->values);
198.485 + if (hbm->rhsval != NULL) xfree(hbm->rhsval);
198.486 + if (hbm->sguess != NULL) xfree(hbm->sguess);
198.487 + if (hbm->xexact != NULL) xfree(hbm->xexact);
198.488 + xfree(hbm);
198.489 + }
198.490 + if (dsa->fp != NULL) fclose(dsa->fp);
198.491 + return NULL;
198.492 +}
198.493 +
198.494 +/***********************************************************************
198.495 +* NAME
198.496 +*
198.497 +* hbm_free_mat - free sparse matrix in Harwell-Boeing format
198.498 +*
198.499 +* SYNOPSIS
198.500 +*
198.501 +* #include "glphbm.h"
198.502 +* void hbm_free_mat(HBM *hbm);
198.503 +*
198.504 +* DESCRIPTION
198.505 +*
198.506 +* The hbm_free_mat routine frees all the memory allocated to the data
198.507 +* structure containing a sparse matrix in the Harwell-Boeing format. */
198.508 +
198.509 +void hbm_free_mat(HBM *hbm)
198.510 +{ if (hbm->colptr != NULL) xfree(hbm->colptr);
198.511 + if (hbm->rowind != NULL) xfree(hbm->rowind);
198.512 + if (hbm->rhsptr != NULL) xfree(hbm->rhsptr);
198.513 + if (hbm->rhsind != NULL) xfree(hbm->rhsind);
198.514 + if (hbm->values != NULL) xfree(hbm->values);
198.515 + if (hbm->rhsval != NULL) xfree(hbm->rhsval);
198.516 + if (hbm->sguess != NULL) xfree(hbm->sguess);
198.517 + if (hbm->xexact != NULL) xfree(hbm->xexact);
198.518 + xfree(hbm);
198.519 + return;
198.520 +}
198.521 +
198.522 +/* eof */
199.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
199.2 +++ b/src/glphbm.h Mon Dec 06 13:09:21 2010 +0100
199.3 @@ -0,0 +1,127 @@
199.4 +/* glphbm.h (Harwell-Boeing sparse matrix format) */
199.5 +
199.6 +/***********************************************************************
199.7 +* This code is part of GLPK (GNU Linear Programming Kit).
199.8 +*
199.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
199.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
199.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
199.12 +* E-mail: <mao@gnu.org>.
199.13 +*
199.14 +* GLPK is free software: you can redistribute it and/or modify it
199.15 +* under the terms of the GNU General Public License as published by
199.16 +* the Free Software Foundation, either version 3 of the License, or
199.17 +* (at your option) any later version.
199.18 +*
199.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
199.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
199.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
199.22 +* License for more details.
199.23 +*
199.24 +* You should have received a copy of the GNU General Public License
199.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
199.26 +***********************************************************************/
199.27 +
199.28 +#ifndef GLPHBM_H
199.29 +#define GLPHBM_H
199.30 +
199.31 +typedef struct HBM HBM;
199.32 +
199.33 +struct HBM
199.34 +{ /* sparse matrix in Harwell-Boeing format; for details see the
199.35 + report: I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the
199.36 + Harwell-Boeing Sparse Matrix Collection (Release I), 1992 */
199.37 + char title[72+1];
199.38 + /* matrix title (informative) */
199.39 + char key[8+1];
199.40 + /* matrix key (informative) */
199.41 + char mxtype[3+1];
199.42 + /* matrix type:
199.43 + R.. real matrix
199.44 + C.. complex matrix
199.45 + P.. pattern only (no numerical values supplied)
199.46 + .S. symmetric (lower triangle + main diagonal)
199.47 + .U. unsymmetric
199.48 + .H. hermitian (lower triangle + main diagonal)
199.49 + .Z. skew symmetric (lower triangle only)
199.50 + .R. rectangular
199.51 + ..A assembled
199.52 + ..E elemental (unassembled) */
199.53 + char rhstyp[3+1];
199.54 + /* optional types:
199.55 + F.. right-hand sides in dense format
199.56 + M.. right-hand sides in same format as matrix
199.57 + .G. starting vector(s) (guess) is supplied
199.58 + ..X exact solution vector(s) is supplied */
199.59 + char ptrfmt[16+1];
199.60 + /* format for pointers */
199.61 + char indfmt[16+1];
199.62 + /* format for row (or variable) indices */
199.63 + char valfmt[20+1];
199.64 + /* format for numerical values of coefficient matrix */
199.65 + char rhsfmt[20+1];
199.66 + /* format for numerical values of right-hand sides */
199.67 + int totcrd;
199.68 + /* total number of cards excluding header */
199.69 + int ptrcrd;
199.70 + /* number of cards for ponters */
199.71 + int indcrd;
199.72 + /* number of cards for row (or variable) indices */
199.73 + int valcrd;
199.74 + /* number of cards for numerical values */
199.75 + int rhscrd;
199.76 + /* number of lines for right-hand sides;
199.77 + including starting guesses and solution vectors if present;
199.78 + zero indicates no right-hand side data is present */
199.79 + int nrow;
199.80 + /* number of rows (or variables) */
199.81 + int ncol;
199.82 + /* number of columns (or elements) */
199.83 + int nnzero;
199.84 + /* number of row (or variable) indices;
199.85 + equal to number of entries for assembled matrix */
199.86 + int neltvl;
199.87 + /* number of elemental matrix entries;
199.88 + zero in case of assembled matrix */
199.89 + int nrhs;
199.90 + /* number of right-hand sides */
199.91 + int nrhsix;
199.92 + /* number of row indices;
199.93 + ignored in case of unassembled matrix */
199.94 + int nrhsvl;
199.95 + /* total number of entries in all right-hand sides */
199.96 + int nguess;
199.97 + /* total number of entries in all starting guesses */
199.98 + int nexact;
199.99 + /* total number of entries in all solution vectors */
199.100 + int *colptr; /* alias: eltptr */
199.101 + /* column pointers (in case of assembled matrix);
199.102 + elemental matrix pointers (in case of unassembled matrix) */
199.103 + int *rowind; /* alias: varind */
199.104 + /* row indices (in case of assembled matrix);
199.105 + variable indices (in case of unassembled matrix) */
199.106 + int *rhsptr;
199.107 + /* right-hand side pointers */
199.108 + int *rhsind;
199.109 + /* right-hand side indices */
199.110 + double *values;
199.111 + /* matrix values */
199.112 + double *rhsval;
199.113 + /* right-hand side values */
199.114 + double *sguess;
199.115 + /* starting guess values */
199.116 + double *xexact;
199.117 + /* solution vector values */
199.118 +};
199.119 +
199.120 +#define hbm_read_mat _glp_hbm_read_mat
199.121 +HBM *hbm_read_mat(const char *fname);
199.122 +/* read sparse matrix in Harwell-Boeing format */
199.123 +
199.124 +#define hbm_free_mat _glp_hbm_free_mat
199.125 +void hbm_free_mat(HBM *hbm);
199.126 +/* free sparse matrix in Harwell-Boeing format */
199.127 +
199.128 +#endif
199.129 +
199.130 +/* eof */
200.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
200.2 +++ b/src/glpini01.c Mon Dec 06 13:09:21 2010 +0100
200.3 @@ -0,0 +1,577 @@
200.4 +/* glpini01.c */
200.5 +
200.6 +/***********************************************************************
200.7 +* This code is part of GLPK (GNU Linear Programming Kit).
200.8 +*
200.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
200.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
200.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
200.12 +* E-mail: <mao@gnu.org>.
200.13 +*
200.14 +* GLPK is free software: you can redistribute it and/or modify it
200.15 +* under the terms of the GNU General Public License as published by
200.16 +* the Free Software Foundation, either version 3 of the License, or
200.17 +* (at your option) any later version.
200.18 +*
200.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
200.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
200.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
200.22 +* License for more details.
200.23 +*
200.24 +* You should have received a copy of the GNU General Public License
200.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
200.26 +***********************************************************************/
200.27 +
200.28 +#include "glpapi.h"
200.29 +
200.30 +/*----------------------------------------------------------------------
200.31 +-- triang - find maximal triangular part of a rectangular matrix.
200.32 +--
200.33 +-- *Synopsis*
200.34 +--
200.35 +-- int triang(int m, int n,
200.36 +-- void *info, int (*mat)(void *info, int k, int ndx[]),
200.37 +-- int rn[], int cn[]);
200.38 +--
200.39 +-- *Description*
200.40 +--
200.41 +-- For a given rectangular (sparse) matrix A with m rows and n columns
200.42 +-- the routine triang tries to find such permutation matrices P and Q
200.43 +-- that the first rows and columns of the matrix B = P*A*Q form a lower
200.44 +-- triangular submatrix of as greatest size as possible:
200.45 +--
200.46 +-- 1 n
200.47 +-- 1 * . . . . . . x x x x x x
200.48 +-- * * . . . . . x x x x x x
200.49 +-- * * * . . . . x x x x x x
200.50 +-- * * * * . . . x x x x x x
200.51 +-- B = P*A*Q = * * * * * . . x x x x x x
200.52 +-- * * * * * * . x x x x x x
200.53 +-- * * * * * * * x x x x x x
200.54 +-- x x x x x x x x x x x x x
200.55 +-- x x x x x x x x x x x x x
200.56 +-- m x x x x x x x x x x x x x
200.57 +--
200.58 +-- where: '*' - elements of the lower triangular part, '.' - structural
200.59 +-- zeros, 'x' - other (either non-zero or zero) elements.
200.60 +--
200.61 +-- The parameter info is a transit pointer passed to the formal routine
200.62 +-- mat (see below).
200.63 +--
200.64 +-- The formal routine mat specifies the given matrix A in both row- and
200.65 +-- column-wise formats. In order to obtain an i-th row of the matrix A
200.66 +-- the routine triang calls the routine mat with the parameter k = +i,
200.67 +-- 1 <= i <= m. In response the routine mat should store column indices
200.68 +-- of (non-zero) elements of the i-th row to the locations ndx[1], ...,
200.69 +-- ndx[len], where len is number of non-zeros in the i-th row returned
200.70 +-- on exit. Analogously, in order to obtain a j-th column of the matrix
200.71 +-- A, the routine mat is called with the parameter k = -j, 1 <= j <= n,
200.72 +-- and should return pattern of the j-th column in the same way as for
200.73 +-- row patterns. Note that the routine mat may be called more than once
200.74 +-- for the same rows and columns.
200.75 +--
200.76 +-- On exit the routine computes two resultant arrays rn and cn, which
200.77 +-- define the permutation matrices P and Q, respectively. The array rn
200.78 +-- should have at least 1+m locations, where rn[i] = i' (1 <= i <= m)
200.79 +-- means that i-th row of the original matrix A corresponds to i'-th row
200.80 +-- of the matrix B = P*A*Q. Similarly, the array cn should have at least
200.81 +-- 1+n locations, where cn[j] = j' (1 <= j <= n) means that j-th column
200.82 +-- of the matrix A corresponds to j'-th column of the matrix B.
200.83 +--
200.84 +-- *Returns*
200.85 +--
200.86 +-- The routine triang returns the size of the lower tringular part of
200.87 +-- the matrix B = P*A*Q (see the figure above).
200.88 +--
200.89 +-- *Complexity*
200.90 +--
200.91 +-- The time complexity of the routine triang is O(nnz), where nnz is
200.92 +-- number of non-zeros in the given matrix A.
200.93 +--
200.94 +-- *Algorithm*
200.95 +--
200.96 +-- The routine triang starts from the matrix B = P*Q*A, where P and Q
200.97 +-- are unity matrices, so initially B = A.
200.98 +--
200.99 +-- Before the next iteration B = (B1 | B2 | B3), where B1 is partially
200.100 +-- built a lower triangular submatrix, B2 is the active submatrix, and
200.101 +-- B3 is a submatrix that contains rejected columns. Thus, the current
200.102 +-- matrix B looks like follows (initially k1 = 1 and k2 = n):
200.103 +--
200.104 +-- 1 k1 k2 n
200.105 +-- 1 x . . . . . . . . . . . . . # # #
200.106 +-- x x . . . . . . . . . . . . # # #
200.107 +-- x x x . . . . . . . . . . # # # #
200.108 +-- x x x x . . . . . . . . . # # # #
200.109 +-- x x x x x . . . . . . . # # # # #
200.110 +-- k1 x x x x x * * * * * * * # # # # #
200.111 +-- x x x x x * * * * * * * # # # # #
200.112 +-- x x x x x * * * * * * * # # # # #
200.113 +-- x x x x x * * * * * * * # # # # #
200.114 +-- m x x x x x * * * * * * * # # # # #
200.115 +-- <--B1---> <----B2-----> <---B3-->
200.116 +--
200.117 +-- On each iteartion the routine looks for a singleton row, i.e. some
200.118 +-- row that has the only non-zero in the active submatrix B2. If such
200.119 +-- row exists and the corresponding non-zero is b[i,j], where (by the
200.120 +-- definition) k1 <= i <= m and k1 <= j <= k2, the routine permutes
200.121 +-- k1-th and i-th rows and k1-th and j-th columns of the matrix B (in
200.122 +-- order to place the element in the position b[k1,k1]), removes the
200.123 +-- k1-th column from the active submatrix B2, and adds this column to
200.124 +-- the submatrix B1. If no row singletons exist, but B2 is not empty
200.125 +-- yet, the routine chooses a j-th column, which has maximal number of
200.126 +-- non-zeros among other columns of B2, removes this column from B2 and
200.127 +-- adds it to the submatrix B3 in the hope that new row singletons will
200.128 +-- appear in the active submatrix. */
200.129 +
200.130 +static int triang(int m, int n,
200.131 + void *info, int (*mat)(void *info, int k, int ndx[]),
200.132 + int rn[], int cn[])
200.133 +{ int *ndx; /* int ndx[1+max(m,n)]; */
200.134 + /* this array is used for querying row and column patterns of the
200.135 + given matrix A (the third parameter to the routine mat) */
200.136 + int *rs_len; /* int rs_len[1+m]; */
200.137 + /* rs_len[0] is not used;
200.138 + rs_len[i], 1 <= i <= m, is number of non-zeros in the i-th row
200.139 + of the matrix A, which (non-zeros) belong to the current active
200.140 + submatrix */
200.141 + int *rs_head; /* int rs_head[1+n]; */
200.142 + /* rs_head[len], 0 <= len <= n, is the number i of the first row
200.143 + of the matrix A, for which rs_len[i] = len */
200.144 + int *rs_prev; /* int rs_prev[1+m]; */
200.145 + /* rs_prev[0] is not used;
200.146 + rs_prev[i], 1 <= i <= m, is a number i' of the previous row of
200.147 + the matrix A, for which rs_len[i] = rs_len[i'] (zero marks the
200.148 + end of this linked list) */
200.149 + int *rs_next; /* int rs_next[1+m]; */
200.150 + /* rs_next[0] is not used;
200.151 + rs_next[i], 1 <= i <= m, is a number i' of the next row of the
200.152 + matrix A, for which rs_len[i] = rs_len[i'] (zero marks the end
200.153 + this linked list) */
200.154 + int cs_head;
200.155 + /* is a number j of the first column of the matrix A, which has
200.156 + maximal number of non-zeros among other columns */
200.157 + int *cs_prev; /* cs_prev[1+n]; */
200.158 + /* cs_prev[0] is not used;
200.159 + cs_prev[j], 1 <= j <= n, is a number of the previous column of
200.160 + the matrix A with the same or greater number of non-zeros than
200.161 + in the j-th column (zero marks the end of this linked list) */
200.162 + int *cs_next; /* cs_next[1+n]; */
200.163 + /* cs_next[0] is not used;
200.164 + cs_next[j], 1 <= j <= n, is a number of the next column of
200.165 + the matrix A with the same or lesser number of non-zeros than
200.166 + in the j-th column (zero marks the end of this linked list) */
200.167 + int i, j, ii, jj, k1, k2, len, t, size = 0;
200.168 + int *head, *rn_inv, *cn_inv;
200.169 + if (!(m > 0 && n > 0))
200.170 + xerror("triang: m = %d; n = %d; invalid dimension\n", m, n);
200.171 + /* allocate working arrays */
200.172 + ndx = xcalloc(1+(m >= n ? m : n), sizeof(int));
200.173 + rs_len = xcalloc(1+m, sizeof(int));
200.174 + rs_head = xcalloc(1+n, sizeof(int));
200.175 + rs_prev = xcalloc(1+m, sizeof(int));
200.176 + rs_next = xcalloc(1+m, sizeof(int));
200.177 + cs_prev = xcalloc(1+n, sizeof(int));
200.178 + cs_next = xcalloc(1+n, sizeof(int));
200.179 + /* build linked lists of columns of the matrix A with the same
200.180 + number of non-zeros */
200.181 + head = rs_len; /* currently rs_len is used as working array */
200.182 + for (len = 0; len <= m; len ++) head[len] = 0;
200.183 + for (j = 1; j <= n; j++)
200.184 + { /* obtain length of the j-th column */
200.185 + len = mat(info, -j, ndx);
200.186 + xassert(0 <= len && len <= m);
200.187 + /* include the j-th column in the corresponding linked list */
200.188 + cs_prev[j] = head[len];
200.189 + head[len] = j;
200.190 + }
200.191 + /* merge all linked lists of columns in one linked list, where
200.192 + columns are ordered by descending of their lengths */
200.193 + cs_head = 0;
200.194 + for (len = 0; len <= m; len++)
200.195 + { for (j = head[len]; j != 0; j = cs_prev[j])
200.196 + { cs_next[j] = cs_head;
200.197 + cs_head = j;
200.198 + }
200.199 + }
200.200 + jj = 0;
200.201 + for (j = cs_head; j != 0; j = cs_next[j])
200.202 + { cs_prev[j] = jj;
200.203 + jj = j;
200.204 + }
200.205 + /* build initial doubly linked lists of rows of the matrix A with
200.206 + the same number of non-zeros */
200.207 + for (len = 0; len <= n; len++) rs_head[len] = 0;
200.208 + for (i = 1; i <= m; i++)
200.209 + { /* obtain length of the i-th row */
200.210 + rs_len[i] = len = mat(info, +i, ndx);
200.211 + xassert(0 <= len && len <= n);
200.212 + /* include the i-th row in the correspondng linked list */
200.213 + rs_prev[i] = 0;
200.214 + rs_next[i] = rs_head[len];
200.215 + if (rs_next[i] != 0) rs_prev[rs_next[i]] = i;
200.216 + rs_head[len] = i;
200.217 + }
200.218 + /* initially all rows and columns of the matrix A are active */
200.219 + for (i = 1; i <= m; i++) rn[i] = 0;
200.220 + for (j = 1; j <= n; j++) cn[j] = 0;
200.221 + /* set initial bounds of the active submatrix */
200.222 + k1 = 1, k2 = n;
200.223 + /* main loop starts here */
200.224 + while (k1 <= k2)
200.225 + { i = rs_head[1];
200.226 + if (i != 0)
200.227 + { /* the i-th row of the matrix A is a row singleton, since
200.228 + it has the only non-zero in the active submatrix */
200.229 + xassert(rs_len[i] == 1);
200.230 + /* determine the number j of an active column of the matrix
200.231 + A, in which this non-zero is placed */
200.232 + j = 0;
200.233 + t = mat(info, +i, ndx);
200.234 + xassert(0 <= t && t <= n);
200.235 + for (t = t; t >= 1; t--)
200.236 + { jj = ndx[t];
200.237 + xassert(1 <= jj && jj <= n);
200.238 + if (cn[jj] == 0)
200.239 + { xassert(j == 0);
200.240 + j = jj;
200.241 + }
200.242 + }
200.243 + xassert(j != 0);
200.244 + /* the singleton is a[i,j]; move a[i,j] to the position
200.245 + b[k1,k1] of the matrix B */
200.246 + rn[i] = cn[j] = k1;
200.247 + /* shift the left bound of the active submatrix */
200.248 + k1++;
200.249 + /* increase the size of the lower triangular part */
200.250 + size++;
200.251 + }
200.252 + else
200.253 + { /* the current active submatrix has no row singletons */
200.254 + /* remove an active column with maximal number of non-zeros
200.255 + from the active submatrix */
200.256 + j = cs_head;
200.257 + xassert(j != 0);
200.258 + cn[j] = k2;
200.259 + /* shift the right bound of the active submatrix */
200.260 + k2--;
200.261 + }
200.262 + /* the j-th column of the matrix A has been removed from the
200.263 + active submatrix */
200.264 + /* remove the j-th column from the linked list */
200.265 + if (cs_prev[j] == 0)
200.266 + cs_head = cs_next[j];
200.267 + else
200.268 + cs_next[cs_prev[j]] = cs_next[j];
200.269 + if (cs_next[j] == 0)
200.270 + /* nop */;
200.271 + else
200.272 + cs_prev[cs_next[j]] = cs_prev[j];
200.273 + /* go through non-zeros of the j-th columns and update active
200.274 + lengths of the corresponding rows */
200.275 + t = mat(info, -j, ndx);
200.276 + xassert(0 <= t && t <= m);
200.277 + for (t = t; t >= 1; t--)
200.278 + { i = ndx[t];
200.279 + xassert(1 <= i && i <= m);
200.280 + /* the non-zero a[i,j] has left the active submatrix */
200.281 + len = rs_len[i];
200.282 + xassert(len >= 1);
200.283 + /* remove the i-th row from the linked list of rows with
200.284 + active length len */
200.285 + if (rs_prev[i] == 0)
200.286 + rs_head[len] = rs_next[i];
200.287 + else
200.288 + rs_next[rs_prev[i]] = rs_next[i];
200.289 + if (rs_next[i] == 0)
200.290 + /* nop */;
200.291 + else
200.292 + rs_prev[rs_next[i]] = rs_prev[i];
200.293 + /* decrease the active length of the i-th row */
200.294 + rs_len[i] = --len;
200.295 + /* return the i-th row to the corresponding linked list */
200.296 + rs_prev[i] = 0;
200.297 + rs_next[i] = rs_head[len];
200.298 + if (rs_next[i] != 0) rs_prev[rs_next[i]] = i;
200.299 + rs_head[len] = i;
200.300 + }
200.301 + }
200.302 + /* other rows of the matrix A, which are still active, correspond
200.303 + to rows k1, ..., m of the matrix B (in arbitrary order) */
200.304 + for (i = 1; i <= m; i++) if (rn[i] == 0) rn[i] = k1++;
200.305 + /* but for columns this is not needed, because now the submatrix
200.306 + B2 has no columns */
200.307 + for (j = 1; j <= n; j++) xassert(cn[j] != 0);
200.308 + /* perform some optional checks */
200.309 + /* make sure that rn is a permutation of {1, ..., m} and cn is a
200.310 + permutation of {1, ..., n} */
200.311 + rn_inv = rs_len; /* used as working array */
200.312 + for (ii = 1; ii <= m; ii++) rn_inv[ii] = 0;
200.313 + for (i = 1; i <= m; i++)
200.314 + { ii = rn[i];
200.315 + xassert(1 <= ii && ii <= m);
200.316 + xassert(rn_inv[ii] == 0);
200.317 + rn_inv[ii] = i;
200.318 + }
200.319 + cn_inv = rs_head; /* used as working array */
200.320 + for (jj = 1; jj <= n; jj++) cn_inv[jj] = 0;
200.321 + for (j = 1; j <= n; j++)
200.322 + { jj = cn[j];
200.323 + xassert(1 <= jj && jj <= n);
200.324 + xassert(cn_inv[jj] == 0);
200.325 + cn_inv[jj] = j;
200.326 + }
200.327 + /* make sure that the matrix B = P*A*Q really has the form, which
200.328 + was declared */
200.329 + for (ii = 1; ii <= size; ii++)
200.330 + { int diag = 0;
200.331 + i = rn_inv[ii];
200.332 + t = mat(info, +i, ndx);
200.333 + xassert(0 <= t && t <= n);
200.334 + for (t = t; t >= 1; t--)
200.335 + { j = ndx[t];
200.336 + xassert(1 <= j && j <= n);
200.337 + jj = cn[j];
200.338 + if (jj <= size) xassert(jj <= ii);
200.339 + if (jj == ii)
200.340 + { xassert(!diag);
200.341 + diag = 1;
200.342 + }
200.343 + }
200.344 + xassert(diag);
200.345 + }
200.346 + /* free working arrays */
200.347 + xfree(ndx);
200.348 + xfree(rs_len);
200.349 + xfree(rs_head);
200.350 + xfree(rs_prev);
200.351 + xfree(rs_next);
200.352 + xfree(cs_prev);
200.353 + xfree(cs_next);
200.354 + /* return to the calling program */
200.355 + return size;
200.356 +}
200.357 +
200.358 +/*----------------------------------------------------------------------
200.359 +-- adv_basis - construct advanced initial LP basis.
200.360 +--
200.361 +-- *Synopsis*
200.362 +--
200.363 +-- #include "glpini.h"
200.364 +-- void adv_basis(glp_prob *lp);
200.365 +--
200.366 +-- *Description*
200.367 +--
200.368 +-- The routine adv_basis constructs an advanced initial basis for an LP
200.369 +-- problem object, which the parameter lp points to.
200.370 +--
200.371 +-- In order to build the initial basis the routine does the following:
200.372 +--
200.373 +-- 1) includes in the basis all non-fixed auxiliary variables;
200.374 +--
200.375 +-- 2) includes in the basis as many as possible non-fixed structural
200.376 +-- variables preserving triangular form of the basis matrix;
200.377 +--
200.378 +-- 3) includes in the basis appropriate (fixed) auxiliary variables
200.379 +-- in order to complete the basis.
200.380 +--
200.381 +-- As a result the initial basis has minimum of fixed variables and the
200.382 +-- corresponding basis matrix is triangular. */
200.383 +
200.384 +static int mat(void *info, int k, int ndx[])
200.385 +{ /* this auxiliary routine returns the pattern of a given row or
200.386 + a given column of the augmented constraint matrix A~ = (I|-A),
200.387 + in which columns of fixed variables are implicitly cleared */
200.388 + LPX *lp = info;
200.389 + int m = lpx_get_num_rows(lp);
200.390 + int n = lpx_get_num_cols(lp);
200.391 + int typx, i, j, lll, len = 0;
200.392 + if (k > 0)
200.393 + { /* the pattern of the i-th row is required */
200.394 + i = +k;
200.395 + xassert(1 <= i && i <= m);
200.396 +#if 0 /* 22/XII-2003 */
200.397 + /* if the auxiliary variable x[i] is non-fixed, include its
200.398 + element (placed in the i-th column) in the pattern */
200.399 + lpx_get_row_bnds(lp, i, &typx, NULL, NULL);
200.400 + if (typx != LPX_FX) ndx[++len] = i;
200.401 + /* include in the pattern elements placed in columns, which
200.402 + correspond to non-fixed structural varables */
200.403 + i_beg = aa_ptr[i];
200.404 + i_end = i_beg + aa_len[i] - 1;
200.405 + for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
200.406 + { j = m + sv_ndx[i_ptr];
200.407 + lpx_get_col_bnds(lp, j-m, &typx, NULL, NULL);
200.408 + if (typx != LPX_FX) ndx[++len] = j;
200.409 + }
200.410 +#else
200.411 + lll = lpx_get_mat_row(lp, i, ndx, NULL);
200.412 + for (k = 1; k <= lll; k++)
200.413 + { lpx_get_col_bnds(lp, ndx[k], &typx, NULL, NULL);
200.414 + if (typx != LPX_FX) ndx[++len] = m + ndx[k];
200.415 + }
200.416 + lpx_get_row_bnds(lp, i, &typx, NULL, NULL);
200.417 + if (typx != LPX_FX) ndx[++len] = i;
200.418 +#endif
200.419 + }
200.420 + else
200.421 + { /* the pattern of the j-th column is required */
200.422 + j = -k;
200.423 + xassert(1 <= j && j <= m+n);
200.424 + /* if the (auxiliary or structural) variable x[j] is fixed,
200.425 + the pattern of its column is empty */
200.426 + if (j <= m)
200.427 + lpx_get_row_bnds(lp, j, &typx, NULL, NULL);
200.428 + else
200.429 + lpx_get_col_bnds(lp, j-m, &typx, NULL, NULL);
200.430 + if (typx != LPX_FX)
200.431 + { if (j <= m)
200.432 + { /* x[j] is non-fixed auxiliary variable */
200.433 + ndx[++len] = j;
200.434 + }
200.435 + else
200.436 + { /* x[j] is non-fixed structural variables */
200.437 +#if 0 /* 22/XII-2003 */
200.438 + j_beg = aa_ptr[j];
200.439 + j_end = j_beg + aa_len[j] - 1;
200.440 + for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
200.441 + ndx[++len] = sv_ndx[j_ptr];
200.442 +#else
200.443 + len = lpx_get_mat_col(lp, j-m, ndx, NULL);
200.444 +#endif
200.445 + }
200.446 + }
200.447 + }
200.448 + /* return the length of the row/column pattern */
200.449 + return len;
200.450 +}
200.451 +
200.452 +static void adv_basis(glp_prob *lp)
200.453 +{ int m = lpx_get_num_rows(lp);
200.454 + int n = lpx_get_num_cols(lp);
200.455 + int i, j, jj, k, size;
200.456 + int *rn, *cn, *rn_inv, *cn_inv;
200.457 + int typx, *tagx = xcalloc(1+m+n, sizeof(int));
200.458 + double lb, ub;
200.459 + xprintf("Constructing initial basis...\n");
200.460 +#if 0 /* 13/V-2009 */
200.461 + if (m == 0)
200.462 + xerror("glp_adv_basis: problem has no rows\n");
200.463 + if (n == 0)
200.464 + xerror("glp_adv_basis: problem has no columns\n");
200.465 +#else
200.466 + if (m == 0 || n == 0)
200.467 + { glp_std_basis(lp);
200.468 + return;
200.469 + }
200.470 +#endif
200.471 + /* use the routine triang (see above) to find maximal triangular
200.472 + part of the augmented constraint matrix A~ = (I|-A); in order
200.473 + to prevent columns of fixed variables to be included in the
200.474 + triangular part, such columns are implictly removed from the
200.475 + matrix A~ by the routine adv_mat */
200.476 + rn = xcalloc(1+m, sizeof(int));
200.477 + cn = xcalloc(1+m+n, sizeof(int));
200.478 + size = triang(m, m+n, lp, mat, rn, cn);
200.479 + if (lpx_get_int_parm(lp, LPX_K_MSGLEV) >= 3)
200.480 + xprintf("Size of triangular part = %d\n", size);
200.481 + /* the first size rows and columns of the matrix P*A~*Q (where
200.482 + P and Q are permutation matrices defined by the arrays rn and
200.483 + cn) form a lower triangular matrix; build the arrays (rn_inv
200.484 + and cn_inv), which define the matrices inv(P) and inv(Q) */
200.485 + rn_inv = xcalloc(1+m, sizeof(int));
200.486 + cn_inv = xcalloc(1+m+n, sizeof(int));
200.487 + for (i = 1; i <= m; i++) rn_inv[rn[i]] = i;
200.488 + for (j = 1; j <= m+n; j++) cn_inv[cn[j]] = j;
200.489 + /* include the columns of the matrix A~, which correspond to the
200.490 + first size columns of the matrix P*A~*Q, in the basis */
200.491 + for (k = 1; k <= m+n; k++) tagx[k] = -1;
200.492 + for (jj = 1; jj <= size; jj++)
200.493 + { j = cn_inv[jj];
200.494 + /* the j-th column of A~ is the jj-th column of P*A~*Q */
200.495 + tagx[j] = LPX_BS;
200.496 + }
200.497 + /* if size < m, we need to add appropriate columns of auxiliary
200.498 + variables to the basis */
200.499 + for (jj = size + 1; jj <= m; jj++)
200.500 + { /* the jj-th column of P*A~*Q should be replaced by the column
200.501 + of the auxiliary variable, for which the only unity element
200.502 + is placed in the position [jj,jj] */
200.503 + i = rn_inv[jj];
200.504 + /* the jj-th row of P*A~*Q is the i-th row of A~, but in the
200.505 + i-th row of A~ the unity element belongs to the i-th column
200.506 + of A~; therefore the disired column corresponds to the i-th
200.507 + auxiliary variable (note that this column doesn't belong to
200.508 + the triangular part found by the routine triang) */
200.509 + xassert(1 <= i && i <= m);
200.510 + xassert(cn[i] > size);
200.511 + tagx[i] = LPX_BS;
200.512 + }
200.513 + /* free working arrays */
200.514 + xfree(rn);
200.515 + xfree(cn);
200.516 + xfree(rn_inv);
200.517 + xfree(cn_inv);
200.518 + /* build tags of non-basic variables */
200.519 + for (k = 1; k <= m+n; k++)
200.520 + { if (tagx[k] != LPX_BS)
200.521 + { if (k <= m)
200.522 + lpx_get_row_bnds(lp, k, &typx, &lb, &ub);
200.523 + else
200.524 + lpx_get_col_bnds(lp, k-m, &typx, &lb, &ub);
200.525 + switch (typx)
200.526 + { case LPX_FR:
200.527 + tagx[k] = LPX_NF; break;
200.528 + case LPX_LO:
200.529 + tagx[k] = LPX_NL; break;
200.530 + case LPX_UP:
200.531 + tagx[k] = LPX_NU; break;
200.532 + case LPX_DB:
200.533 + tagx[k] =
200.534 + (fabs(lb) <= fabs(ub) ? LPX_NL : LPX_NU);
200.535 + break;
200.536 + case LPX_FX:
200.537 + tagx[k] = LPX_NS; break;
200.538 + default:
200.539 + xassert(typx != typx);
200.540 + }
200.541 + }
200.542 + }
200.543 + for (k = 1; k <= m+n; k++)
200.544 + { if (k <= m)
200.545 + lpx_set_row_stat(lp, k, tagx[k]);
200.546 + else
200.547 + lpx_set_col_stat(lp, k-m, tagx[k]);
200.548 + }
200.549 + xfree(tagx);
200.550 + return;
200.551 +}
200.552 +
200.553 +/***********************************************************************
200.554 +* NAME
200.555 +*
200.556 +* glp_adv_basis - construct advanced initial LP basis
200.557 +*
200.558 +* SYNOPSIS
200.559 +*
200.560 +* void glp_adv_basis(glp_prob *lp, int flags);
200.561 +*
200.562 +* DESCRIPTION
200.563 +*
200.564 +* The routine glp_adv_basis constructs an advanced initial basis for
200.565 +* the specified problem object.
200.566 +*
200.567 +* The parameter flags is reserved for use in the future and must be
200.568 +* specified as zero. */
200.569 +
200.570 +void glp_adv_basis(glp_prob *lp, int flags)
200.571 +{ if (flags != 0)
200.572 + xerror("glp_adv_basis: flags = %d; invalid flags\n", flags);
200.573 + if (lp->m == 0 || lp->n == 0)
200.574 + glp_std_basis(lp);
200.575 + else
200.576 + adv_basis(lp);
200.577 + return;
200.578 +}
200.579 +
200.580 +/* eof */
201.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
201.2 +++ b/src/glpini02.c Mon Dec 06 13:09:21 2010 +0100
201.3 @@ -0,0 +1,269 @@
201.4 +/* glpini02.c */
201.5 +
201.6 +/***********************************************************************
201.7 +* This code is part of GLPK (GNU Linear Programming Kit).
201.8 +*
201.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
201.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
201.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
201.12 +* E-mail: <mao@gnu.org>.
201.13 +*
201.14 +* GLPK is free software: you can redistribute it and/or modify it
201.15 +* under the terms of the GNU General Public License as published by
201.16 +* the Free Software Foundation, either version 3 of the License, or
201.17 +* (at your option) any later version.
201.18 +*
201.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
201.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
201.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
201.22 +* License for more details.
201.23 +*
201.24 +* You should have received a copy of the GNU General Public License
201.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
201.26 +***********************************************************************/
201.27 +
201.28 +#include "glpapi.h"
201.29 +
201.30 +struct var
201.31 +{ /* structural variable */
201.32 + int j;
201.33 + /* ordinal number */
201.34 + double q;
201.35 + /* penalty value */
201.36 +};
201.37 +
201.38 +static int fcmp(const void *ptr1, const void *ptr2)
201.39 +{ /* this routine is passed to the qsort() function */
201.40 + struct var *col1 = (void *)ptr1, *col2 = (void *)ptr2;
201.41 + if (col1->q < col2->q) return -1;
201.42 + if (col1->q > col2->q) return +1;
201.43 + return 0;
201.44 +}
201.45 +
201.46 +static int get_column(glp_prob *lp, int j, int ind[], double val[])
201.47 +{ /* Bixby's algorithm assumes that the constraint matrix is scaled
201.48 + such that the maximum absolute value in every non-zero row and
201.49 + column is 1 */
201.50 + int k, len;
201.51 + double big;
201.52 + len = glp_get_mat_col(lp, j, ind, val);
201.53 + big = 0.0;
201.54 + for (k = 1; k <= len; k++)
201.55 + if (big < fabs(val[k])) big = fabs(val[k]);
201.56 + if (big == 0.0) big = 1.0;
201.57 + for (k = 1; k <= len; k++) val[k] /= big;
201.58 + return len;
201.59 +}
201.60 +
201.61 +static void cpx_basis(glp_prob *lp)
201.62 +{ /* main routine */
201.63 + struct var *C, *C2, *C3, *C4;
201.64 + int m, n, i, j, jk, k, l, ll, t, n2, n3, n4, type, len, *I, *r,
201.65 + *ind;
201.66 + double alpha, gamma, cmax, temp, *v, *val;
201.67 + xprintf("Constructing initial basis...\n");
201.68 + /* determine the number of rows and columns */
201.69 + m = glp_get_num_rows(lp);
201.70 + n = glp_get_num_cols(lp);
201.71 + /* allocate working arrays */
201.72 + C = xcalloc(1+n, sizeof(struct var));
201.73 + I = xcalloc(1+m, sizeof(int));
201.74 + r = xcalloc(1+m, sizeof(int));
201.75 + v = xcalloc(1+m, sizeof(double));
201.76 + ind = xcalloc(1+m, sizeof(int));
201.77 + val = xcalloc(1+m, sizeof(double));
201.78 + /* make all auxiliary variables non-basic */
201.79 + for (i = 1; i <= m; i++)
201.80 + { if (glp_get_row_type(lp, i) != GLP_DB)
201.81 + glp_set_row_stat(lp, i, GLP_NS);
201.82 + else if (fabs(glp_get_row_lb(lp, i)) <=
201.83 + fabs(glp_get_row_ub(lp, i)))
201.84 + glp_set_row_stat(lp, i, GLP_NL);
201.85 + else
201.86 + glp_set_row_stat(lp, i, GLP_NU);
201.87 + }
201.88 + /* make all structural variables non-basic */
201.89 + for (j = 1; j <= n; j++)
201.90 + { if (glp_get_col_type(lp, j) != GLP_DB)
201.91 + glp_set_col_stat(lp, j, GLP_NS);
201.92 + else if (fabs(glp_get_col_lb(lp, j)) <=
201.93 + fabs(glp_get_col_ub(lp, j)))
201.94 + glp_set_col_stat(lp, j, GLP_NL);
201.95 + else
201.96 + glp_set_col_stat(lp, j, GLP_NU);
201.97 + }
201.98 + /* C2 is a set of free structural variables */
201.99 + n2 = 0, C2 = C + 0;
201.100 + for (j = 1; j <= n; j++)
201.101 + { type = glp_get_col_type(lp, j);
201.102 + if (type == GLP_FR)
201.103 + { n2++;
201.104 + C2[n2].j = j;
201.105 + C2[n2].q = 0.0;
201.106 + }
201.107 + }
201.108 + /* C3 is a set of structural variables having excatly one (lower
201.109 + or upper) bound */
201.110 + n3 = 0, C3 = C2 + n2;
201.111 + for (j = 1; j <= n; j++)
201.112 + { type = glp_get_col_type(lp, j);
201.113 + if (type == GLP_LO)
201.114 + { n3++;
201.115 + C3[n3].j = j;
201.116 + C3[n3].q = + glp_get_col_lb(lp, j);
201.117 + }
201.118 + else if (type == GLP_UP)
201.119 + { n3++;
201.120 + C3[n3].j = j;
201.121 + C3[n3].q = - glp_get_col_ub(lp, j);
201.122 + }
201.123 + }
201.124 + /* C4 is a set of structural variables having both (lower and
201.125 + upper) bounds */
201.126 + n4 = 0, C4 = C3 + n3;
201.127 + for (j = 1; j <= n; j++)
201.128 + { type = glp_get_col_type(lp, j);
201.129 + if (type == GLP_DB)
201.130 + { n4++;
201.131 + C4[n4].j = j;
201.132 + C4[n4].q = glp_get_col_lb(lp, j) - glp_get_col_ub(lp, j);
201.133 + }
201.134 + }
201.135 + /* compute gamma = max{|c[j]|: 1 <= j <= n} */
201.136 + gamma = 0.0;
201.137 + for (j = 1; j <= n; j++)
201.138 + { temp = fabs(glp_get_obj_coef(lp, j));
201.139 + if (gamma < temp) gamma = temp;
201.140 + }
201.141 + /* compute cmax */
201.142 + cmax = (gamma == 0.0 ? 1.0 : 1000.0 * gamma);
201.143 + /* compute final penalty for all structural variables within sets
201.144 + C2, C3, and C4 */
201.145 + switch (glp_get_obj_dir(lp))
201.146 + { case GLP_MIN: temp = +1.0; break;
201.147 + case GLP_MAX: temp = -1.0; break;
201.148 + default: xassert(lp != lp);
201.149 + }
201.150 + for (k = 1; k <= n2+n3+n4; k++)
201.151 + { j = C[k].j;
201.152 + C[k].q += (temp * glp_get_obj_coef(lp, j)) / cmax;
201.153 + }
201.154 + /* sort structural variables within C2, C3, and C4 in ascending
201.155 + order of penalty value */
201.156 + qsort(C2+1, n2, sizeof(struct var), fcmp);
201.157 + for (k = 1; k < n2; k++) xassert(C2[k].q <= C2[k+1].q);
201.158 + qsort(C3+1, n3, sizeof(struct var), fcmp);
201.159 + for (k = 1; k < n3; k++) xassert(C3[k].q <= C3[k+1].q);
201.160 + qsort(C4+1, n4, sizeof(struct var), fcmp);
201.161 + for (k = 1; k < n4; k++) xassert(C4[k].q <= C4[k+1].q);
201.162 + /*** STEP 1 ***/
201.163 + for (i = 1; i <= m; i++)
201.164 + { type = glp_get_row_type(lp, i);
201.165 + if (type != GLP_FX)
201.166 + { /* row i is either free or inequality constraint */
201.167 + glp_set_row_stat(lp, i, GLP_BS);
201.168 + I[i] = 1;
201.169 + r[i] = 1;
201.170 + }
201.171 + else
201.172 + { /* row i is equality constraint */
201.173 + I[i] = 0;
201.174 + r[i] = 0;
201.175 + }
201.176 + v[i] = +DBL_MAX;
201.177 + }
201.178 + /*** STEP 2 ***/
201.179 + for (k = 1; k <= n2+n3+n4; k++)
201.180 + { jk = C[k].j;
201.181 + len = get_column(lp, jk, ind, val);
201.182 + /* let alpha = max{|A[l,jk]|: r[l] = 0} and let l' be such
201.183 + that alpha = |A[l',jk]| */
201.184 + alpha = 0.0, ll = 0;
201.185 + for (t = 1; t <= len; t++)
201.186 + { l = ind[t];
201.187 + if (r[l] == 0 && alpha < fabs(val[t]))
201.188 + alpha = fabs(val[t]), ll = l;
201.189 + }
201.190 + if (alpha >= 0.99)
201.191 + { /* B := B union {jk} */
201.192 + glp_set_col_stat(lp, jk, GLP_BS);
201.193 + I[ll] = 1;
201.194 + v[ll] = alpha;
201.195 + /* r[l] := r[l] + 1 for all l such that |A[l,jk]| != 0 */
201.196 + for (t = 1; t <= len; t++)
201.197 + { l = ind[t];
201.198 + if (val[t] != 0.0) r[l]++;
201.199 + }
201.200 + /* continue to the next k */
201.201 + continue;
201.202 + }
201.203 + /* if |A[l,jk]| > 0.01 * v[l] for some l, continue to the
201.204 + next k */
201.205 + for (t = 1; t <= len; t++)
201.206 + { l = ind[t];
201.207 + if (fabs(val[t]) > 0.01 * v[l]) break;
201.208 + }
201.209 + if (t <= len) continue;
201.210 + /* otherwise, let alpha = max{|A[l,jk]|: I[l] = 0} and let l'
201.211 + be such that alpha = |A[l',jk]| */
201.212 + alpha = 0.0, ll = 0;
201.213 + for (t = 1; t <= len; t++)
201.214 + { l = ind[t];
201.215 + if (I[l] == 0 && alpha < fabs(val[t]))
201.216 + alpha = fabs(val[t]), ll = l;
201.217 + }
201.218 + /* if alpha = 0, continue to the next k */
201.219 + if (alpha == 0.0) continue;
201.220 + /* B := B union {jk} */
201.221 + glp_set_col_stat(lp, jk, GLP_BS);
201.222 + I[ll] = 1;
201.223 + v[ll] = alpha;
201.224 + /* r[l] := r[l] + 1 for all l such that |A[l,jk]| != 0 */
201.225 + for (t = 1; t <= len; t++)
201.226 + { l = ind[t];
201.227 + if (val[t] != 0.0) r[l]++;
201.228 + }
201.229 + }
201.230 + /*** STEP 3 ***/
201.231 + /* add an artificial variable (auxiliary variable for equality
201.232 + constraint) to cover each remaining uncovered row */
201.233 + for (i = 1; i <= m; i++)
201.234 + if (I[i] == 0) glp_set_row_stat(lp, i, GLP_BS);
201.235 + /* free working arrays */
201.236 + xfree(C);
201.237 + xfree(I);
201.238 + xfree(r);
201.239 + xfree(v);
201.240 + xfree(ind);
201.241 + xfree(val);
201.242 + return;
201.243 +}
201.244 +
201.245 +/***********************************************************************
201.246 +* NAME
201.247 +*
201.248 +* glp_cpx_basis - construct Bixby's initial LP basis
201.249 +*
201.250 +* SYNOPSIS
201.251 +*
201.252 +* void glp_cpx_basis(glp_prob *lp);
201.253 +*
201.254 +* DESCRIPTION
201.255 +*
201.256 +* The routine glp_cpx_basis constructs an advanced initial basis for
201.257 +* the specified problem object.
201.258 +*
201.259 +* The routine is based on Bixby's algorithm described in the paper:
201.260 +*
201.261 +* Robert E. Bixby. Implementing the Simplex Method: The Initial Basis.
201.262 +* ORSA Journal on Computing, Vol. 4, No. 3, 1992, pp. 267-84. */
201.263 +
201.264 +void glp_cpx_basis(glp_prob *lp)
201.265 +{ if (lp->m == 0 || lp->n == 0)
201.266 + glp_std_basis(lp);
201.267 + else
201.268 + cpx_basis(lp);
201.269 + return;
201.270 +}
201.271 +
201.272 +/* eof */
202.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
202.2 +++ b/src/glpios.h Mon Dec 06 13:09:21 2010 +0100
202.3 @@ -0,0 +1,593 @@
202.4 +/* glpios.h (integer optimization suite) */
202.5 +
202.6 +/***********************************************************************
202.7 +* This code is part of GLPK (GNU Linear Programming Kit).
202.8 +*
202.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
202.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
202.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
202.12 +* E-mail: <mao@gnu.org>.
202.13 +*
202.14 +* GLPK is free software: you can redistribute it and/or modify it
202.15 +* under the terms of the GNU General Public License as published by
202.16 +* the Free Software Foundation, either version 3 of the License, or
202.17 +* (at your option) any later version.
202.18 +*
202.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
202.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
202.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
202.22 +* License for more details.
202.23 +*
202.24 +* You should have received a copy of the GNU General Public License
202.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
202.26 +***********************************************************************/
202.27 +
202.28 +#ifndef GLPIOS_H
202.29 +#define GLPIOS_H
202.30 +
202.31 +#define GLP_TREE_DEFINED
202.32 +typedef struct glp_tree glp_tree;
202.33 +
202.34 +#include "glpapi.h"
202.35 +
202.36 +typedef struct IOSLOT IOSLOT;
202.37 +typedef struct IOSNPD IOSNPD;
202.38 +typedef struct IOSBND IOSBND;
202.39 +typedef struct IOSTAT IOSTAT;
202.40 +typedef struct IOSROW IOSROW;
202.41 +typedef struct IOSAIJ IOSAIJ;
202.42 +typedef struct IOSPOOL IOSPOOL;
202.43 +typedef struct IOSCUT IOSCUT;
202.44 +
202.45 +struct glp_tree
202.46 +{ /* branch-and-bound tree */
202.47 + int magic;
202.48 + /* magic value used for debugging */
202.49 + DMP *pool;
202.50 + /* memory pool to store all IOS components */
202.51 + int n;
202.52 + /* number of columns (variables) */
202.53 + /*--------------------------------------------------------------*/
202.54 + /* problem components corresponding to the original MIP and its
202.55 + LP relaxation (used to restore the original problem object on
202.56 + exit from the solver) */
202.57 + int orig_m;
202.58 + /* number of rows */
202.59 + unsigned char *orig_type; /* uchar orig_type[1+orig_m+n]; */
202.60 + /* types of all variables */
202.61 + double *orig_lb; /* double orig_lb[1+orig_m+n]; */
202.62 + /* lower bounds of all variables */
202.63 + double *orig_ub; /* double orig_ub[1+orig_m+n]; */
202.64 + /* upper bounds of all variables */
202.65 + unsigned char *orig_stat; /* uchar orig_stat[1+orig_m+n]; */
202.66 + /* statuses of all variables */
202.67 + double *orig_prim; /* double orig_prim[1+orig_m+n]; */
202.68 + /* primal values of all variables */
202.69 + double *orig_dual; /* double orig_dual[1+orig_m+n]; */
202.70 + /* dual values of all variables */
202.71 + double orig_obj;
202.72 + /* optimal objective value for LP relaxation */
202.73 + /*--------------------------------------------------------------*/
202.74 + /* branch-and-bound tree */
202.75 + int nslots;
202.76 + /* length of the array of slots (enlarged automatically) */
202.77 + int avail;
202.78 + /* index of the first free slot; 0 means all slots are in use */
202.79 + IOSLOT *slot; /* IOSLOT slot[1+nslots]; */
202.80 + /* array of slots:
202.81 + slot[0] is not used;
202.82 + slot[p], 1 <= p <= nslots, either contains a pointer to some
202.83 + node of the branch-and-bound tree, in which case p is used on
202.84 + API level as the reference number of corresponding subproblem,
202.85 + or is free; all free slots are linked into single linked list;
202.86 + slot[1] always contains a pointer to the root node (it is free
202.87 + only if the tree is empty) */
202.88 + IOSNPD *head;
202.89 + /* pointer to the head of the active list */
202.90 + IOSNPD *tail;
202.91 + /* pointer to the tail of the active list */
202.92 + /* the active list is a doubly linked list of active subproblems
202.93 + which correspond to leaves of the tree; all subproblems in the
202.94 + active list are ordered chronologically (each a new subproblem
202.95 + is always added to the tail of the list) */
202.96 + int a_cnt;
202.97 + /* current number of active nodes (including the current one) */
202.98 + int n_cnt;
202.99 + /* current number of all (active and inactive) nodes */
202.100 + int t_cnt;
202.101 + /* total number of nodes including those which have been already
202.102 + removed from the tree; this count is increased by one whenever
202.103 + a new node is created and never decreased */
202.104 + /*--------------------------------------------------------------*/
202.105 + /* problem components corresponding to the root subproblem */
202.106 + int root_m;
202.107 + /* number of rows */
202.108 + unsigned char *root_type; /* uchar root_type[1+root_m+n]; */
202.109 + /* types of all variables */
202.110 + double *root_lb; /* double root_lb[1+root_m+n]; */
202.111 + /* lower bounds of all variables */
202.112 + double *root_ub; /* double root_ub[1+root_m+n]; */
202.113 + /* upper bounds of all variables */
202.114 + unsigned char *root_stat; /* uchar root_stat[1+root_m+n]; */
202.115 + /* statuses of all variables */
202.116 + /*--------------------------------------------------------------*/
202.117 + /* current subproblem and its LP relaxation */
202.118 + IOSNPD *curr;
202.119 + /* pointer to the current subproblem (which can be only active);
202.120 + NULL means the current subproblem does not exist */
202.121 + glp_prob *mip;
202.122 + /* original problem object passed to the solver; if the current
202.123 + subproblem exists, its LP segment corresponds to LP relaxation
202.124 + of the current subproblem; if the current subproblem does not
202.125 + exist, its LP segment corresponds to LP relaxation of the root
202.126 + subproblem (note that the root subproblem may differ from the
202.127 + original MIP, because it may be preprocessed and/or may have
202.128 + additional rows) */
202.129 + unsigned char *non_int; /* uchar non_int[1+n]; */
202.130 + /* these column flags are set each time when LP relaxation of the
202.131 + current subproblem has been solved;
202.132 + non_int[0] is not used;
202.133 + non_int[j], 1 <= j <= n, is j-th column flag; if this flag is
202.134 + set, corresponding variable is required to be integer, but its
202.135 + value in basic solution is fractional */
202.136 + /*--------------------------------------------------------------*/
202.137 + /* problem components corresponding to the parent (predecessor)
202.138 + subproblem for the current subproblem; used to inspect changes
202.139 + on freezing the current subproblem */
202.140 + int pred_m;
202.141 + /* number of rows */
202.142 + int pred_max;
202.143 + /* length of the following four arrays (enlarged automatically),
202.144 + pred_max >= pred_m + n */
202.145 + unsigned char *pred_type; /* uchar pred_type[1+pred_m+n]; */
202.146 + /* types of all variables */
202.147 + double *pred_lb; /* double pred_lb[1+pred_m+n]; */
202.148 + /* lower bounds of all variables */
202.149 + double *pred_ub; /* double pred_ub[1+pred_m+n]; */
202.150 + /* upper bounds of all variables */
202.151 + unsigned char *pred_stat; /* uchar pred_stat[1+pred_m+n]; */
202.152 + /* statuses of all variables */
202.153 + /****************************************************************/
202.154 + /* built-in cut generators segment */
202.155 + IOSPOOL *local;
202.156 + /* local cut pool */
202.157 + void *mir_gen;
202.158 + /* pointer to working area used by the MIR cut generator */
202.159 + void *clq_gen;
202.160 + /* pointer to working area used by the clique cut generator */
202.161 + /*--------------------------------------------------------------*/
202.162 + void *pcost;
202.163 + /* pointer to working area used on pseudocost branching */
202.164 + int *iwrk; /* int iwrk[1+n]; */
202.165 + /* working array */
202.166 + double *dwrk; /* double dwrk[1+n]; */
202.167 + /* working array */
202.168 + /*--------------------------------------------------------------*/
202.169 + /* control parameters and statistics */
202.170 + const glp_iocp *parm;
202.171 + /* copy of control parameters passed to the solver */
202.172 + glp_long tm_beg;
202.173 + /* starting time of the search, in seconds; the total time of the
202.174 + search is the difference between xtime() and tm_beg */
202.175 + glp_long tm_lag;
202.176 + /* the most recent time, in seconds, at which the progress of the
202.177 + the search was displayed */
202.178 + int sol_cnt;
202.179 + /* number of integer feasible solutions found */
202.180 + /*--------------------------------------------------------------*/
202.181 + /* advanced solver interface */
202.182 + int reason;
202.183 + /* flag indicating the reason why the callback routine is being
202.184 + called (see glpk.h) */
202.185 + int stop;
202.186 + /* flag indicating that the callback routine requires premature
202.187 + termination of the search */
202.188 + int next_p;
202.189 + /* reference number of active subproblem selected to continue
202.190 + the search; 0 means no subproblem has been selected */
202.191 + int reopt;
202.192 + /* flag indicating that the current LP relaxation needs to be
202.193 + re-optimized */
202.194 + int reinv;
202.195 + /* flag indicating that some (non-active) rows were removed from
202.196 + the current LP relaxation, so if there no new rows appear, the
202.197 + basis must be re-factorized */
202.198 + int br_var;
202.199 + /* the number of variable chosen to branch on */
202.200 + int br_sel;
202.201 + /* flag indicating which branch (subproblem) is suggested to be
202.202 + selected to continue the search:
202.203 + GLP_DN_BRNCH - select down-branch
202.204 + GLP_UP_BRNCH - select up-branch
202.205 + GLP_NO_BRNCH - use general selection technique */
202.206 + int child;
202.207 + /* subproblem reference number corresponding to br_sel */
202.208 +};
202.209 +
202.210 +struct IOSLOT
202.211 +{ /* node subproblem slot */
202.212 + IOSNPD *node;
202.213 + /* pointer to subproblem descriptor; NULL means free slot */
202.214 + int next;
202.215 + /* index of another free slot (only if this slot is free) */
202.216 +};
202.217 +
202.218 +struct IOSNPD
202.219 +{ /* node subproblem descriptor */
202.220 + int p;
202.221 + /* subproblem reference number (it is the index to corresponding
202.222 + slot, i.e. slot[p] points to this descriptor) */
202.223 + IOSNPD *up;
202.224 + /* pointer to the parent subproblem; NULL means this node is the
202.225 + root of the tree, in which case p = 1 */
202.226 + int level;
202.227 + /* node level (the root node has level 0) */
202.228 + int count;
202.229 + /* if count = 0, this subproblem is active; if count > 0, this
202.230 + subproblem is inactive, in which case count is the number of
202.231 + its child subproblems */
202.232 + /* the following three linked lists are destroyed on reviving and
202.233 + built anew on freezing the subproblem: */
202.234 + IOSBND *b_ptr;
202.235 + /* linked list of rows and columns of the parent subproblem whose
202.236 + types and bounds were changed */
202.237 + IOSTAT *s_ptr;
202.238 + /* linked list of rows and columns of the parent subproblem whose
202.239 + statuses were changed */
202.240 + IOSROW *r_ptr;
202.241 + /* linked list of rows (cuts) added to the parent subproblem */
202.242 + int solved;
202.243 + /* how many times LP relaxation of this subproblem was solved;
202.244 + for inactive subproblem this count is always non-zero;
202.245 + for active subproblem, which is not current, this count may be
202.246 + non-zero, if the subproblem was temporarily suspended */
202.247 + double lp_obj;
202.248 + /* optimal objective value to LP relaxation of this subproblem;
202.249 + on creating a subproblem this value is inherited from its
202.250 + parent; for the root subproblem, which has no parent, this
202.251 + value is initially set to -DBL_MAX (minimization) or +DBL_MAX
202.252 + (maximization); each time the subproblem is re-optimized, this
202.253 + value is appropriately changed */
202.254 + double bound;
202.255 + /* local lower (minimization) or upper (maximization) bound for
202.256 + integer optimal solution to *this* subproblem; this bound is
202.257 + local in the sense that only subproblems in the subtree rooted
202.258 + at this node cannot have better integer feasible solutions;
202.259 + on creating a subproblem its local bound is inherited from its
202.260 + parent and then can be made stronger (never weaker); for the
202.261 + root subproblem its local bound is initially set to -DBL_MAX
202.262 + (minimization) or +DBL_MAX (maximization) and then improved as
202.263 + the root LP relaxation has been solved */
202.264 + /* the following two quantities are defined only if LP relaxation
202.265 + of this subproblem was solved at least once (solved > 0): */
202.266 + int ii_cnt;
202.267 + /* number of integer variables whose value in optimal solution to
202.268 + LP relaxation of this subproblem is fractional */
202.269 + double ii_sum;
202.270 + /* sum of integer infeasibilities */
202.271 +#if 1 /* 30/XI-2009 */
202.272 + int changed;
202.273 + /* how many times this subproblem was re-formulated (by adding
202.274 + cutting plane constraints) */
202.275 +#endif
202.276 + int br_var;
202.277 + /* ordinal number of branching variable, 1 <= br_var <= n, used
202.278 + to split this subproblem; 0 means that either this subproblem
202.279 + is active or branching was made on a constraint */
202.280 + double br_val;
202.281 + /* (fractional) value of branching variable in optimal solution
202.282 + to final LP relaxation of this subproblem */
202.283 + void *data; /* char data[tree->cb_size]; */
202.284 + /* pointer to the application-specific data */
202.285 + IOSNPD *temp;
202.286 + /* working pointer used by some routines */
202.287 + IOSNPD *prev;
202.288 + /* pointer to previous subproblem in the active list */
202.289 + IOSNPD *next;
202.290 + /* pointer to next subproblem in the active list */
202.291 +};
202.292 +
202.293 +struct IOSBND
202.294 +{ /* bounds change entry */
202.295 + int k;
202.296 + /* ordinal number of corresponding row (1 <= k <= m) or column
202.297 + (m+1 <= k <= m+n), where m and n are the number of rows and
202.298 + columns, resp., in the parent subproblem */
202.299 + unsigned char type;
202.300 + /* new type */
202.301 + double lb;
202.302 + /* new lower bound */
202.303 + double ub;
202.304 + /* new upper bound */
202.305 + IOSBND *next;
202.306 + /* pointer to next entry for the same subproblem */
202.307 +};
202.308 +
202.309 +struct IOSTAT
202.310 +{ /* status change entry */
202.311 + int k;
202.312 + /* ordinal number of corresponding row (1 <= k <= m) or column
202.313 + (m+1 <= k <= m+n), where m and n are the number of rows and
202.314 + columns, resp., in the parent subproblem */
202.315 + unsigned char stat;
202.316 + /* new status */
202.317 + IOSTAT *next;
202.318 + /* pointer to next entry for the same subproblem */
202.319 +};
202.320 +
202.321 +struct IOSROW
202.322 +{ /* row (constraint) addition entry */
202.323 + char *name;
202.324 + /* row name or NULL */
202.325 + unsigned char origin;
202.326 + /* row origin flag (see glp_attr.origin) */
202.327 + unsigned char klass;
202.328 + /* row class descriptor (see glp_attr.klass) */
202.329 + unsigned char type;
202.330 + /* row type (GLP_LO, GLP_UP, etc.) */
202.331 + double lb;
202.332 + /* row lower bound */
202.333 + double ub;
202.334 + /* row upper bound */
202.335 + IOSAIJ *ptr;
202.336 + /* pointer to the row coefficient list */
202.337 + double rii;
202.338 + /* row scale factor */
202.339 + unsigned char stat;
202.340 + /* row status (GLP_BS, GLP_NL, etc.) */
202.341 + IOSROW *next;
202.342 + /* pointer to next entry for the same subproblem */
202.343 +};
202.344 +
202.345 +struct IOSAIJ
202.346 +{ /* constraint coefficient */
202.347 + int j;
202.348 + /* variable (column) number, 1 <= j <= n */
202.349 + double val;
202.350 + /* non-zero coefficient value */
202.351 + IOSAIJ *next;
202.352 + /* pointer to next coefficient for the same row */
202.353 +};
202.354 +
202.355 +struct IOSPOOL
202.356 +{ /* cut pool */
202.357 + int size;
202.358 + /* pool size = number of cuts in the pool */
202.359 + IOSCUT *head;
202.360 + /* pointer to the first cut */
202.361 + IOSCUT *tail;
202.362 + /* pointer to the last cut */
202.363 + int ord;
202.364 + /* ordinal number of the current cut, 1 <= ord <= size */
202.365 + IOSCUT *curr;
202.366 + /* pointer to the current cut */
202.367 +};
202.368 +
202.369 +struct IOSCUT
202.370 +{ /* cut (cutting plane constraint) */
202.371 + char *name;
202.372 + /* cut name or NULL */
202.373 + unsigned char klass;
202.374 + /* cut class descriptor (see glp_attr.klass) */
202.375 + IOSAIJ *ptr;
202.376 + /* pointer to the cut coefficient list */
202.377 + unsigned char type;
202.378 + /* cut type:
202.379 + GLP_LO: sum a[j] * x[j] >= b
202.380 + GLP_UP: sum a[j] * x[j] <= b
202.381 + GLP_FX: sum a[j] * x[j] = b */
202.382 + double rhs;
202.383 + /* cut right-hand side */
202.384 + IOSCUT *prev;
202.385 + /* pointer to previous cut */
202.386 + IOSCUT *next;
202.387 + /* pointer to next cut */
202.388 +};
202.389 +
202.390 +#define ios_create_tree _glp_ios_create_tree
202.391 +glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm);
202.392 +/* create branch-and-bound tree */
202.393 +
202.394 +#define ios_revive_node _glp_ios_revive_node
202.395 +void ios_revive_node(glp_tree *tree, int p);
202.396 +/* revive specified subproblem */
202.397 +
202.398 +#define ios_freeze_node _glp_ios_freeze_node
202.399 +void ios_freeze_node(glp_tree *tree);
202.400 +/* freeze current subproblem */
202.401 +
202.402 +#define ios_clone_node _glp_ios_clone_node
202.403 +void ios_clone_node(glp_tree *tree, int p, int nnn, int ref[]);
202.404 +/* clone specified subproblem */
202.405 +
202.406 +#define ios_delete_node _glp_ios_delete_node
202.407 +void ios_delete_node(glp_tree *tree, int p);
202.408 +/* delete specified subproblem */
202.409 +
202.410 +#define ios_delete_tree _glp_ios_delete_tree
202.411 +void ios_delete_tree(glp_tree *tree);
202.412 +/* delete branch-and-bound tree */
202.413 +
202.414 +#define ios_eval_degrad _glp_ios_eval_degrad
202.415 +void ios_eval_degrad(glp_tree *tree, int j, double *dn, double *up);
202.416 +/* estimate obj. degrad. for down- and up-branches */
202.417 +
202.418 +#define ios_round_bound _glp_ios_round_bound
202.419 +double ios_round_bound(glp_tree *tree, double bound);
202.420 +/* improve local bound by rounding */
202.421 +
202.422 +#define ios_is_hopeful _glp_ios_is_hopeful
202.423 +int ios_is_hopeful(glp_tree *tree, double bound);
202.424 +/* check if subproblem is hopeful */
202.425 +
202.426 +#define ios_best_node _glp_ios_best_node
202.427 +int ios_best_node(glp_tree *tree);
202.428 +/* find active node with best local bound */
202.429 +
202.430 +#define ios_relative_gap _glp_ios_relative_gap
202.431 +double ios_relative_gap(glp_tree *tree);
202.432 +/* compute relative mip gap */
202.433 +
202.434 +#define ios_solve_node _glp_ios_solve_node
202.435 +int ios_solve_node(glp_tree *tree);
202.436 +/* solve LP relaxation of current subproblem */
202.437 +
202.438 +#define ios_create_pool _glp_ios_create_pool
202.439 +IOSPOOL *ios_create_pool(glp_tree *tree);
202.440 +/* create cut pool */
202.441 +
202.442 +#define ios_add_row _glp_ios_add_row
202.443 +int ios_add_row(glp_tree *tree, IOSPOOL *pool,
202.444 + const char *name, int klass, int flags, int len, const int ind[],
202.445 + const double val[], int type, double rhs);
202.446 +/* add row (constraint) to the cut pool */
202.447 +
202.448 +#define ios_find_row _glp_ios_find_row
202.449 +IOSCUT *ios_find_row(IOSPOOL *pool, int i);
202.450 +/* find row (constraint) in the cut pool */
202.451 +
202.452 +#define ios_del_row _glp_ios_del_row
202.453 +void ios_del_row(glp_tree *tree, IOSPOOL *pool, int i);
202.454 +/* remove row (constraint) from the cut pool */
202.455 +
202.456 +#define ios_clear_pool _glp_ios_clear_pool
202.457 +void ios_clear_pool(glp_tree *tree, IOSPOOL *pool);
202.458 +/* remove all rows (constraints) from the cut pool */
202.459 +
202.460 +#define ios_delete_pool _glp_ios_delete_pool
202.461 +void ios_delete_pool(glp_tree *tree, IOSPOOL *pool);
202.462 +/* delete cut pool */
202.463 +
202.464 +#define ios_preprocess_node _glp_ios_preprocess_node
202.465 +int ios_preprocess_node(glp_tree *tree, int max_pass);
202.466 +/* preprocess current subproblem */
202.467 +
202.468 +#define ios_driver _glp_ios_driver
202.469 +int ios_driver(glp_tree *tree);
202.470 +/* branch-and-bound driver */
202.471 +
202.472 +/**********************************************************************/
202.473 +
202.474 +typedef struct IOSVEC IOSVEC;
202.475 +
202.476 +struct IOSVEC
202.477 +{ /* sparse vector v = (v[j]) */
202.478 + int n;
202.479 + /* dimension, n >= 0 */
202.480 + int nnz;
202.481 + /* number of non-zero components, 0 <= nnz <= n */
202.482 + int *pos; /* int pos[1+n]; */
202.483 + /* pos[j] = k, 1 <= j <= n, is position of (non-zero) v[j] in the
202.484 + arrays ind and val, where 1 <= k <= nnz; pos[j] = 0 means that
202.485 + v[j] is structural zero */
202.486 + int *ind; /* int ind[1+n]; */
202.487 + /* ind[k] = j, 1 <= k <= nnz, is index of v[j] */
202.488 + double *val; /* double val[1+n]; */
202.489 + /* val[k], 1 <= k <= nnz, is a numeric value of v[j] */
202.490 +};
202.491 +
202.492 +#define ios_create_vec _glp_ios_create_vec
202.493 +IOSVEC *ios_create_vec(int n);
202.494 +/* create sparse vector */
202.495 +
202.496 +#define ios_check_vec _glp_ios_check_vec
202.497 +void ios_check_vec(IOSVEC *v);
202.498 +/* check that sparse vector has correct representation */
202.499 +
202.500 +#define ios_get_vj _glp_ios_get_vj
202.501 +double ios_get_vj(IOSVEC *v, int j);
202.502 +/* retrieve component of sparse vector */
202.503 +
202.504 +#define ios_set_vj _glp_ios_set_vj
202.505 +void ios_set_vj(IOSVEC *v, int j, double val);
202.506 +/* set/change component of sparse vector */
202.507 +
202.508 +#define ios_clear_vec _glp_ios_clear_vec
202.509 +void ios_clear_vec(IOSVEC *v);
202.510 +/* set all components of sparse vector to zero */
202.511 +
202.512 +#define ios_clean_vec _glp_ios_clean_vec
202.513 +void ios_clean_vec(IOSVEC *v, double eps);
202.514 +/* remove zero or small components from sparse vector */
202.515 +
202.516 +#define ios_copy_vec _glp_ios_copy_vec
202.517 +void ios_copy_vec(IOSVEC *x, IOSVEC *y);
202.518 +/* copy sparse vector (x := y) */
202.519 +
202.520 +#define ios_linear_comb _glp_ios_linear_comb
202.521 +void ios_linear_comb(IOSVEC *x, double a, IOSVEC *y);
202.522 +/* compute linear combination (x := x + a * y) */
202.523 +
202.524 +#define ios_delete_vec _glp_ios_delete_vec
202.525 +void ios_delete_vec(IOSVEC *v);
202.526 +/* delete sparse vector */
202.527 +
202.528 +/**********************************************************************/
202.529 +
202.530 +#define ios_gmi_gen _glp_ios_gmi_gen
202.531 +void ios_gmi_gen(glp_tree *tree);
202.532 +/* generate Gomory's mixed integer cuts */
202.533 +
202.534 +#define ios_mir_init _glp_ios_mir_init
202.535 +void *ios_mir_init(glp_tree *tree);
202.536 +/* initialize MIR cut generator */
202.537 +
202.538 +#define ios_mir_gen _glp_ios_mir_gen
202.539 +void ios_mir_gen(glp_tree *tree, void *gen);
202.540 +/* generate MIR cuts */
202.541 +
202.542 +#define ios_mir_term _glp_ios_mir_term
202.543 +void ios_mir_term(void *gen);
202.544 +/* terminate MIR cut generator */
202.545 +
202.546 +#define ios_cov_gen _glp_ios_cov_gen
202.547 +void ios_cov_gen(glp_tree *tree);
202.548 +/* generate mixed cover cuts */
202.549 +
202.550 +#define ios_clq_init _glp_ios_clq_init
202.551 +void *ios_clq_init(glp_tree *tree);
202.552 +/* initialize clique cut generator */
202.553 +
202.554 +#define ios_clq_gen _glp_ios_clq_gen
202.555 +void ios_clq_gen(glp_tree *tree, void *gen);
202.556 +/* generate clique cuts */
202.557 +
202.558 +#define ios_clq_term _glp_ios_clq_term
202.559 +void ios_clq_term(void *gen);
202.560 +/* terminate clique cut generator */
202.561 +
202.562 +#define ios_pcost_init _glp_ios_pcost_init
202.563 +void *ios_pcost_init(glp_tree *tree);
202.564 +/* initialize working data used on pseudocost branching */
202.565 +
202.566 +#define ios_pcost_branch _glp_ios_pcost_branch
202.567 +int ios_pcost_branch(glp_tree *T, int *next);
202.568 +/* choose branching variable with pseudocost branching */
202.569 +
202.570 +#define ios_pcost_update _glp_ios_pcost_update
202.571 +void ios_pcost_update(glp_tree *tree);
202.572 +/* update history information for pseudocost branching */
202.573 +
202.574 +#define ios_pcost_free _glp_ios_pcost_free
202.575 +void ios_pcost_free(glp_tree *tree);
202.576 +/* free working area used on pseudocost branching */
202.577 +
202.578 +#define ios_feas_pump _glp_ios_feas_pump
202.579 +void ios_feas_pump(glp_tree *T);
202.580 +/* feasibility pump heuristic */
202.581 +
202.582 +#define ios_process_cuts _glp_ios_process_cuts
202.583 +void ios_process_cuts(glp_tree *T);
202.584 +/* process cuts stored in the local cut pool */
202.585 +
202.586 +#define ios_choose_node _glp_ios_choose_node
202.587 +int ios_choose_node(glp_tree *T);
202.588 +/* select subproblem to continue the search */
202.589 +
202.590 +#define ios_choose_var _glp_ios_choose_var
202.591 +int ios_choose_var(glp_tree *T, int *next);
202.592 +/* select variable to branch on */
202.593 +
202.594 +#endif
202.595 +
202.596 +/* eof */
203.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
203.2 +++ b/src/glpios01.c Mon Dec 06 13:09:21 2010 +0100
203.3 @@ -0,0 +1,1611 @@
203.4 +/* glpios01.c */
203.5 +
203.6 +/***********************************************************************
203.7 +* This code is part of GLPK (GNU Linear Programming Kit).
203.8 +*
203.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
203.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
203.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
203.12 +* E-mail: <mao@gnu.org>.
203.13 +*
203.14 +* GLPK is free software: you can redistribute it and/or modify it
203.15 +* under the terms of the GNU General Public License as published by
203.16 +* the Free Software Foundation, either version 3 of the License, or
203.17 +* (at your option) any later version.
203.18 +*
203.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
203.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
203.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
203.22 +* License for more details.
203.23 +*
203.24 +* You should have received a copy of the GNU General Public License
203.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
203.26 +***********************************************************************/
203.27 +
203.28 +#include "glpios.h"
203.29 +
203.30 +/***********************************************************************
203.31 +* NAME
203.32 +*
203.33 +* ios_create_tree - create branch-and-bound tree
203.34 +*
203.35 +* SYNOPSIS
203.36 +*
203.37 +* #include "glpios.h"
203.38 +* glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm);
203.39 +*
203.40 +* DESCRIPTION
203.41 +*
203.42 +* The routine ios_create_tree creates the branch-and-bound tree.
203.43 +*
203.44 +* Being created the tree consists of the only root subproblem whose
203.45 +* reference number is 1. Note that initially the root subproblem is in
203.46 +* frozen state and therefore needs to be revived.
203.47 +*
203.48 +* RETURNS
203.49 +*
203.50 +* The routine returns a pointer to the tree created. */
203.51 +
203.52 +static IOSNPD *new_node(glp_tree *tree, IOSNPD *parent);
203.53 +
203.54 +glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm)
203.55 +{ int m = mip->m;
203.56 + int n = mip->n;
203.57 + glp_tree *tree;
203.58 + int i, j;
203.59 + xassert(mip->tree == NULL);
203.60 + mip->tree = tree = xmalloc(sizeof(glp_tree));
203.61 + tree->pool = dmp_create_pool();
203.62 + tree->n = n;
203.63 + /* save original problem components */
203.64 + tree->orig_m = m;
203.65 + tree->orig_type = xcalloc(1+m+n, sizeof(char));
203.66 + tree->orig_lb = xcalloc(1+m+n, sizeof(double));
203.67 + tree->orig_ub = xcalloc(1+m+n, sizeof(double));
203.68 + tree->orig_stat = xcalloc(1+m+n, sizeof(char));
203.69 + tree->orig_prim = xcalloc(1+m+n, sizeof(double));
203.70 + tree->orig_dual = xcalloc(1+m+n, sizeof(double));
203.71 + for (i = 1; i <= m; i++)
203.72 + { GLPROW *row = mip->row[i];
203.73 + tree->orig_type[i] = (char)row->type;
203.74 + tree->orig_lb[i] = row->lb;
203.75 + tree->orig_ub[i] = row->ub;
203.76 + tree->orig_stat[i] = (char)row->stat;
203.77 + tree->orig_prim[i] = row->prim;
203.78 + tree->orig_dual[i] = row->dual;
203.79 + }
203.80 + for (j = 1; j <= n; j++)
203.81 + { GLPCOL *col = mip->col[j];
203.82 + tree->orig_type[m+j] = (char)col->type;
203.83 + tree->orig_lb[m+j] = col->lb;
203.84 + tree->orig_ub[m+j] = col->ub;
203.85 + tree->orig_stat[m+j] = (char)col->stat;
203.86 + tree->orig_prim[m+j] = col->prim;
203.87 + tree->orig_dual[m+j] = col->dual;
203.88 + }
203.89 + tree->orig_obj = mip->obj_val;
203.90 + /* initialize the branch-and-bound tree */
203.91 + tree->nslots = 0;
203.92 + tree->avail = 0;
203.93 + tree->slot = NULL;
203.94 + tree->head = tree->tail = NULL;
203.95 + tree->a_cnt = tree->n_cnt = tree->t_cnt = 0;
203.96 + /* the root subproblem is not solved yet, so its final components
203.97 + are unknown so far */
203.98 + tree->root_m = 0;
203.99 + tree->root_type = NULL;
203.100 + tree->root_lb = tree->root_ub = NULL;
203.101 + tree->root_stat = NULL;
203.102 + /* the current subproblem does not exist yet */
203.103 + tree->curr = NULL;
203.104 + tree->mip = mip;
203.105 + /*tree->solved = 0;*/
203.106 + tree->non_int = xcalloc(1+n, sizeof(char));
203.107 + memset(&tree->non_int[1], 0, n);
203.108 + /* arrays to save parent subproblem components will be allocated
203.109 + later */
203.110 + tree->pred_m = tree->pred_max = 0;
203.111 + tree->pred_type = NULL;
203.112 + tree->pred_lb = tree->pred_ub = NULL;
203.113 + tree->pred_stat = NULL;
203.114 + /* cut generator */
203.115 + tree->local = ios_create_pool(tree);
203.116 + /*tree->first_attempt = 1;*/
203.117 + /*tree->max_added_cuts = 0;*/
203.118 + /*tree->min_eff = 0.0;*/
203.119 + /*tree->miss = 0;*/
203.120 + /*tree->just_selected = 0;*/
203.121 + tree->mir_gen = NULL;
203.122 + tree->clq_gen = NULL;
203.123 + /*tree->round = 0;*/
203.124 +#if 0
203.125 + /* create the conflict graph */
203.126 + tree->n_ref = xcalloc(1+n, sizeof(int));
203.127 + memset(&tree->n_ref[1], 0, n * sizeof(int));
203.128 + tree->c_ref = xcalloc(1+n, sizeof(int));
203.129 + memset(&tree->c_ref[1], 0, n * sizeof(int));
203.130 + tree->g = scg_create_graph(0);
203.131 + tree->j_ref = xcalloc(1+tree->g->n_max, sizeof(int));
203.132 +#endif
203.133 + /* pseudocost branching */
203.134 + tree->pcost = NULL;
203.135 + tree->iwrk = xcalloc(1+n, sizeof(int));
203.136 + tree->dwrk = xcalloc(1+n, sizeof(double));
203.137 + /* initialize control parameters */
203.138 + tree->parm = parm;
203.139 + tree->tm_beg = xtime();
203.140 + tree->tm_lag = xlset(0);
203.141 + tree->sol_cnt = 0;
203.142 + /* initialize advanced solver interface */
203.143 + tree->reason = 0;
203.144 + tree->reopt = 0;
203.145 + tree->reinv = 0;
203.146 + tree->br_var = 0;
203.147 + tree->br_sel = 0;
203.148 + tree->child = 0;
203.149 + tree->next_p = 0;
203.150 + /*tree->btrack = NULL;*/
203.151 + tree->stop = 0;
203.152 + /* create the root subproblem, which initially is identical to
203.153 + the original MIP */
203.154 + new_node(tree, NULL);
203.155 + return tree;
203.156 +}
203.157 +
203.158 +/***********************************************************************
203.159 +* NAME
203.160 +*
203.161 +* ios_revive_node - revive specified subproblem
203.162 +*
203.163 +* SYNOPSIS
203.164 +*
203.165 +* #include "glpios.h"
203.166 +* void ios_revive_node(glp_tree *tree, int p);
203.167 +*
203.168 +* DESCRIPTION
203.169 +*
203.170 +* The routine ios_revive_node revives the specified subproblem, whose
203.171 +* reference number is p, and thereby makes it the current subproblem.
203.172 +* Note that the specified subproblem must be active. Besides, if the
203.173 +* current subproblem already exists, it must be frozen before reviving
203.174 +* another subproblem. */
203.175 +
203.176 +void ios_revive_node(glp_tree *tree, int p)
203.177 +{ glp_prob *mip = tree->mip;
203.178 + IOSNPD *node, *root;
203.179 + /* obtain pointer to the specified subproblem */
203.180 + xassert(1 <= p && p <= tree->nslots);
203.181 + node = tree->slot[p].node;
203.182 + xassert(node != NULL);
203.183 + /* the specified subproblem must be active */
203.184 + xassert(node->count == 0);
203.185 + /* the current subproblem must not exist */
203.186 + xassert(tree->curr == NULL);
203.187 + /* the specified subproblem becomes current */
203.188 + tree->curr = node;
203.189 + /*tree->solved = 0;*/
203.190 + /* obtain pointer to the root subproblem */
203.191 + root = tree->slot[1].node;
203.192 + xassert(root != NULL);
203.193 + /* at this point problem object components correspond to the root
203.194 + subproblem, so if the root subproblem should be revived, there
203.195 + is nothing more to do */
203.196 + if (node == root) goto done;
203.197 + xassert(mip->m == tree->root_m);
203.198 + /* build path from the root to the current node */
203.199 + node->temp = NULL;
203.200 + for (node = node; node != NULL; node = node->up)
203.201 + { if (node->up == NULL)
203.202 + xassert(node == root);
203.203 + else
203.204 + node->up->temp = node;
203.205 + }
203.206 + /* go down from the root to the current node and make necessary
203.207 + changes to restore components of the current subproblem */
203.208 + for (node = root; node != NULL; node = node->temp)
203.209 + { int m = mip->m;
203.210 + int n = mip->n;
203.211 + /* if the current node is reached, the problem object at this
203.212 + point corresponds to its parent, so save attributes of rows
203.213 + and columns for the parent subproblem */
203.214 + if (node->temp == NULL)
203.215 + { int i, j;
203.216 + tree->pred_m = m;
203.217 + /* allocate/reallocate arrays, if necessary */
203.218 + if (tree->pred_max < m + n)
203.219 + { int new_size = m + n + 100;
203.220 + if (tree->pred_type != NULL) xfree(tree->pred_type);
203.221 + if (tree->pred_lb != NULL) xfree(tree->pred_lb);
203.222 + if (tree->pred_ub != NULL) xfree(tree->pred_ub);
203.223 + if (tree->pred_stat != NULL) xfree(tree->pred_stat);
203.224 + tree->pred_max = new_size;
203.225 + tree->pred_type = xcalloc(1+new_size, sizeof(char));
203.226 + tree->pred_lb = xcalloc(1+new_size, sizeof(double));
203.227 + tree->pred_ub = xcalloc(1+new_size, sizeof(double));
203.228 + tree->pred_stat = xcalloc(1+new_size, sizeof(char));
203.229 + }
203.230 + /* save row attributes */
203.231 + for (i = 1; i <= m; i++)
203.232 + { GLPROW *row = mip->row[i];
203.233 + tree->pred_type[i] = (char)row->type;
203.234 + tree->pred_lb[i] = row->lb;
203.235 + tree->pred_ub[i] = row->ub;
203.236 + tree->pred_stat[i] = (char)row->stat;
203.237 + }
203.238 + /* save column attributes */
203.239 + for (j = 1; j <= n; j++)
203.240 + { GLPCOL *col = mip->col[j];
203.241 + tree->pred_type[mip->m+j] = (char)col->type;
203.242 + tree->pred_lb[mip->m+j] = col->lb;
203.243 + tree->pred_ub[mip->m+j] = col->ub;
203.244 + tree->pred_stat[mip->m+j] = (char)col->stat;
203.245 + }
203.246 + }
203.247 + /* change bounds of rows and columns */
203.248 + { IOSBND *b;
203.249 + for (b = node->b_ptr; b != NULL; b = b->next)
203.250 + { if (b->k <= m)
203.251 + glp_set_row_bnds(mip, b->k, b->type, b->lb, b->ub);
203.252 + else
203.253 + glp_set_col_bnds(mip, b->k-m, b->type, b->lb, b->ub);
203.254 + }
203.255 + }
203.256 + /* change statuses of rows and columns */
203.257 + { IOSTAT *s;
203.258 + for (s = node->s_ptr; s != NULL; s = s->next)
203.259 + { if (s->k <= m)
203.260 + glp_set_row_stat(mip, s->k, s->stat);
203.261 + else
203.262 + glp_set_col_stat(mip, s->k-m, s->stat);
203.263 + }
203.264 + }
203.265 + /* add new rows */
203.266 + if (node->r_ptr != NULL)
203.267 + { IOSROW *r;
203.268 + IOSAIJ *a;
203.269 + int i, len, *ind;
203.270 + double *val;
203.271 + ind = xcalloc(1+n, sizeof(int));
203.272 + val = xcalloc(1+n, sizeof(double));
203.273 + for (r = node->r_ptr; r != NULL; r = r->next)
203.274 + { i = glp_add_rows(mip, 1);
203.275 + glp_set_row_name(mip, i, r->name);
203.276 +#if 1 /* 20/IX-2008 */
203.277 + xassert(mip->row[i]->level == 0);
203.278 + mip->row[i]->level = node->level;
203.279 + mip->row[i]->origin = r->origin;
203.280 + mip->row[i]->klass = r->klass;
203.281 +#endif
203.282 + glp_set_row_bnds(mip, i, r->type, r->lb, r->ub);
203.283 + len = 0;
203.284 + for (a = r->ptr; a != NULL; a = a->next)
203.285 + len++, ind[len] = a->j, val[len] = a->val;
203.286 + glp_set_mat_row(mip, i, len, ind, val);
203.287 + glp_set_rii(mip, i, r->rii);
203.288 + glp_set_row_stat(mip, i, r->stat);
203.289 + }
203.290 + xfree(ind);
203.291 + xfree(val);
203.292 + }
203.293 +#if 0
203.294 + /* add new edges to the conflict graph */
203.295 + /* add new cliques to the conflict graph */
203.296 + /* (not implemented yet) */
203.297 + xassert(node->own_nn == 0);
203.298 + xassert(node->own_nc == 0);
203.299 + xassert(node->e_ptr == NULL);
203.300 +#endif
203.301 + }
203.302 + /* the specified subproblem has been revived */
203.303 + node = tree->curr;
203.304 + /* delete its bound change list */
203.305 + while (node->b_ptr != NULL)
203.306 + { IOSBND *b;
203.307 + b = node->b_ptr;
203.308 + node->b_ptr = b->next;
203.309 + dmp_free_atom(tree->pool, b, sizeof(IOSBND));
203.310 + }
203.311 + /* delete its status change list */
203.312 + while (node->s_ptr != NULL)
203.313 + { IOSTAT *s;
203.314 + s = node->s_ptr;
203.315 + node->s_ptr = s->next;
203.316 + dmp_free_atom(tree->pool, s, sizeof(IOSTAT));
203.317 + }
203.318 +#if 1 /* 20/XI-2009 */
203.319 + /* delete its row addition list (additional rows may appear, for
203.320 + example, due to branching on GUB constraints */
203.321 + while (node->r_ptr != NULL)
203.322 + { IOSROW *r;
203.323 + r = node->r_ptr;
203.324 + node->r_ptr = r->next;
203.325 + xassert(r->name == NULL);
203.326 + while (r->ptr != NULL)
203.327 + { IOSAIJ *a;
203.328 + a = r->ptr;
203.329 + r->ptr = a->next;
203.330 + dmp_free_atom(tree->pool, a, sizeof(IOSAIJ));
203.331 + }
203.332 + dmp_free_atom(tree->pool, r, sizeof(IOSROW));
203.333 + }
203.334 +#endif
203.335 +done: return;
203.336 +}
203.337 +
203.338 +/***********************************************************************
203.339 +* NAME
203.340 +*
203.341 +* ios_freeze_node - freeze current subproblem
203.342 +*
203.343 +* SYNOPSIS
203.344 +*
203.345 +* #include "glpios.h"
203.346 +* void ios_freeze_node(glp_tree *tree);
203.347 +*
203.348 +* DESCRIPTION
203.349 +*
203.350 +* The routine ios_freeze_node freezes the current subproblem. */
203.351 +
203.352 +void ios_freeze_node(glp_tree *tree)
203.353 +{ glp_prob *mip = tree->mip;
203.354 + int m = mip->m;
203.355 + int n = mip->n;
203.356 + IOSNPD *node;
203.357 + /* obtain pointer to the current subproblem */
203.358 + node = tree->curr;
203.359 + xassert(node != NULL);
203.360 + if (node->up == NULL)
203.361 + { /* freeze the root subproblem */
203.362 + int k;
203.363 + xassert(node->p == 1);
203.364 + xassert(tree->root_m == 0);
203.365 + xassert(tree->root_type == NULL);
203.366 + xassert(tree->root_lb == NULL);
203.367 + xassert(tree->root_ub == NULL);
203.368 + xassert(tree->root_stat == NULL);
203.369 + tree->root_m = m;
203.370 + tree->root_type = xcalloc(1+m+n, sizeof(char));
203.371 + tree->root_lb = xcalloc(1+m+n, sizeof(double));
203.372 + tree->root_ub = xcalloc(1+m+n, sizeof(double));
203.373 + tree->root_stat = xcalloc(1+m+n, sizeof(char));
203.374 + for (k = 1; k <= m+n; k++)
203.375 + { if (k <= m)
203.376 + { GLPROW *row = mip->row[k];
203.377 + tree->root_type[k] = (char)row->type;
203.378 + tree->root_lb[k] = row->lb;
203.379 + tree->root_ub[k] = row->ub;
203.380 + tree->root_stat[k] = (char)row->stat;
203.381 + }
203.382 + else
203.383 + { GLPCOL *col = mip->col[k-m];
203.384 + tree->root_type[k] = (char)col->type;
203.385 + tree->root_lb[k] = col->lb;
203.386 + tree->root_ub[k] = col->ub;
203.387 + tree->root_stat[k] = (char)col->stat;
203.388 + }
203.389 + }
203.390 + }
203.391 + else
203.392 + { /* freeze non-root subproblem */
203.393 + int root_m = tree->root_m;
203.394 + int pred_m = tree->pred_m;
203.395 + int i, j, k;
203.396 + xassert(pred_m <= m);
203.397 + /* build change lists for rows and columns which exist in the
203.398 + parent subproblem */
203.399 + xassert(node->b_ptr == NULL);
203.400 + xassert(node->s_ptr == NULL);
203.401 + for (k = 1; k <= pred_m + n; k++)
203.402 + { int pred_type, pred_stat, type, stat;
203.403 + double pred_lb, pred_ub, lb, ub;
203.404 + /* determine attributes in the parent subproblem */
203.405 + pred_type = tree->pred_type[k];
203.406 + pred_lb = tree->pred_lb[k];
203.407 + pred_ub = tree->pred_ub[k];
203.408 + pred_stat = tree->pred_stat[k];
203.409 + /* determine attributes in the current subproblem */
203.410 + if (k <= pred_m)
203.411 + { GLPROW *row = mip->row[k];
203.412 + type = row->type;
203.413 + lb = row->lb;
203.414 + ub = row->ub;
203.415 + stat = row->stat;
203.416 + }
203.417 + else
203.418 + { GLPCOL *col = mip->col[k - pred_m];
203.419 + type = col->type;
203.420 + lb = col->lb;
203.421 + ub = col->ub;
203.422 + stat = col->stat;
203.423 + }
203.424 + /* save type and bounds of a row/column, if changed */
203.425 + if (!(pred_type == type && pred_lb == lb && pred_ub == ub))
203.426 + { IOSBND *b;
203.427 + b = dmp_get_atom(tree->pool, sizeof(IOSBND));
203.428 + b->k = k;
203.429 + b->type = (unsigned char)type;
203.430 + b->lb = lb;
203.431 + b->ub = ub;
203.432 + b->next = node->b_ptr;
203.433 + node->b_ptr = b;
203.434 + }
203.435 + /* save status of a row/column, if changed */
203.436 + if (pred_stat != stat)
203.437 + { IOSTAT *s;
203.438 + s = dmp_get_atom(tree->pool, sizeof(IOSTAT));
203.439 + s->k = k;
203.440 + s->stat = (unsigned char)stat;
203.441 + s->next = node->s_ptr;
203.442 + node->s_ptr = s;
203.443 + }
203.444 + }
203.445 + /* save new rows added to the current subproblem */
203.446 + xassert(node->r_ptr == NULL);
203.447 + if (pred_m < m)
203.448 + { int i, len, *ind;
203.449 + double *val;
203.450 + ind = xcalloc(1+n, sizeof(int));
203.451 + val = xcalloc(1+n, sizeof(double));
203.452 + for (i = m; i > pred_m; i--)
203.453 + { GLPROW *row = mip->row[i];
203.454 + IOSROW *r;
203.455 + const char *name;
203.456 + r = dmp_get_atom(tree->pool, sizeof(IOSROW));
203.457 + name = glp_get_row_name(mip, i);
203.458 + if (name == NULL)
203.459 + r->name = NULL;
203.460 + else
203.461 + { r->name = dmp_get_atom(tree->pool, strlen(name)+1);
203.462 + strcpy(r->name, name);
203.463 + }
203.464 +#if 1 /* 20/IX-2008 */
203.465 + r->origin = row->origin;
203.466 + r->klass = row->klass;
203.467 +#endif
203.468 + r->type = (unsigned char)row->type;
203.469 + r->lb = row->lb;
203.470 + r->ub = row->ub;
203.471 + r->ptr = NULL;
203.472 + len = glp_get_mat_row(mip, i, ind, val);
203.473 + for (k = 1; k <= len; k++)
203.474 + { IOSAIJ *a;
203.475 + a = dmp_get_atom(tree->pool, sizeof(IOSAIJ));
203.476 + a->j = ind[k];
203.477 + a->val = val[k];
203.478 + a->next = r->ptr;
203.479 + r->ptr = a;
203.480 + }
203.481 + r->rii = row->rii;
203.482 + r->stat = (unsigned char)row->stat;
203.483 + r->next = node->r_ptr;
203.484 + node->r_ptr = r;
203.485 + }
203.486 + xfree(ind);
203.487 + xfree(val);
203.488 + }
203.489 + /* remove all rows missing in the root subproblem */
203.490 + if (m != root_m)
203.491 + { int nrs, *num;
203.492 + nrs = m - root_m;
203.493 + xassert(nrs > 0);
203.494 + num = xcalloc(1+nrs, sizeof(int));
203.495 + for (i = 1; i <= nrs; i++) num[i] = root_m + i;
203.496 + glp_del_rows(mip, nrs, num);
203.497 + xfree(num);
203.498 + }
203.499 + m = mip->m;
203.500 + /* and restore attributes of all rows and columns for the root
203.501 + subproblem */
203.502 + xassert(m == root_m);
203.503 + for (i = 1; i <= m; i++)
203.504 + { glp_set_row_bnds(mip, i, tree->root_type[i],
203.505 + tree->root_lb[i], tree->root_ub[i]);
203.506 + glp_set_row_stat(mip, i, tree->root_stat[i]);
203.507 + }
203.508 + for (j = 1; j <= n; j++)
203.509 + { glp_set_col_bnds(mip, j, tree->root_type[m+j],
203.510 + tree->root_lb[m+j], tree->root_ub[m+j]);
203.511 + glp_set_col_stat(mip, j, tree->root_stat[m+j]);
203.512 + }
203.513 +#if 1
203.514 + /* remove all edges and cliques missing in the conflict graph
203.515 + for the root subproblem */
203.516 + /* (not implemented yet) */
203.517 +#endif
203.518 + }
203.519 + /* the current subproblem has been frozen */
203.520 + tree->curr = NULL;
203.521 + return;
203.522 +}
203.523 +
203.524 +/***********************************************************************
203.525 +* NAME
203.526 +*
203.527 +* ios_clone_node - clone specified subproblem
203.528 +*
203.529 +* SYNOPSIS
203.530 +*
203.531 +* #include "glpios.h"
203.532 +* void ios_clone_node(glp_tree *tree, int p, int nnn, int ref[]);
203.533 +*
203.534 +* DESCRIPTION
203.535 +*
203.536 +* The routine ios_clone_node clones the specified subproblem, whose
203.537 +* reference number is p, creating its nnn exact copies. Note that the
203.538 +* specified subproblem must be active and must be in the frozen state
203.539 +* (i.e. it must not be the current subproblem).
203.540 +*
203.541 +* Each clone, an exact copy of the specified subproblem, becomes a new
203.542 +* active subproblem added to the end of the active list. After cloning
203.543 +* the specified subproblem becomes inactive.
203.544 +*
203.545 +* The reference numbers of clone subproblems are stored to locations
203.546 +* ref[1], ..., ref[nnn]. */
203.547 +
203.548 +static int get_slot(glp_tree *tree)
203.549 +{ int p;
203.550 + /* if no free slots are available, increase the room */
203.551 + if (tree->avail == 0)
203.552 + { int nslots = tree->nslots;
203.553 + IOSLOT *save = tree->slot;
203.554 + if (nslots == 0)
203.555 + tree->nslots = 20;
203.556 + else
203.557 + { tree->nslots = nslots + nslots;
203.558 + xassert(tree->nslots > nslots);
203.559 + }
203.560 + tree->slot = xcalloc(1+tree->nslots, sizeof(IOSLOT));
203.561 + if (save != NULL)
203.562 + { memcpy(&tree->slot[1], &save[1], nslots * sizeof(IOSLOT));
203.563 + xfree(save);
203.564 + }
203.565 + /* push more free slots into the stack */
203.566 + for (p = tree->nslots; p > nslots; p--)
203.567 + { tree->slot[p].node = NULL;
203.568 + tree->slot[p].next = tree->avail;
203.569 + tree->avail = p;
203.570 + }
203.571 + }
203.572 + /* pull a free slot from the stack */
203.573 + p = tree->avail;
203.574 + tree->avail = tree->slot[p].next;
203.575 + xassert(tree->slot[p].node == NULL);
203.576 + tree->slot[p].next = 0;
203.577 + return p;
203.578 +}
203.579 +
203.580 +static IOSNPD *new_node(glp_tree *tree, IOSNPD *parent)
203.581 +{ IOSNPD *node;
203.582 + int p;
203.583 + /* pull a free slot for the new node */
203.584 + p = get_slot(tree);
203.585 + /* create descriptor of the new subproblem */
203.586 + node = dmp_get_atom(tree->pool, sizeof(IOSNPD));
203.587 + tree->slot[p].node = node;
203.588 + node->p = p;
203.589 + node->up = parent;
203.590 + node->level = (parent == NULL ? 0 : parent->level + 1);
203.591 + node->count = 0;
203.592 + node->b_ptr = NULL;
203.593 + node->s_ptr = NULL;
203.594 + node->r_ptr = NULL;
203.595 + node->solved = 0;
203.596 +#if 0
203.597 + node->own_nn = node->own_nc = 0;
203.598 + node->e_ptr = NULL;
203.599 +#endif
203.600 +#if 1 /* 04/X-2008 */
203.601 + node->lp_obj = (parent == NULL ? (tree->mip->dir == GLP_MIN ?
203.602 + -DBL_MAX : +DBL_MAX) : parent->lp_obj);
203.603 +#endif
203.604 + node->bound = (parent == NULL ? (tree->mip->dir == GLP_MIN ?
203.605 + -DBL_MAX : +DBL_MAX) : parent->bound);
203.606 + node->br_var = 0;
203.607 + node->br_val = 0.0;
203.608 + node->ii_cnt = 0;
203.609 + node->ii_sum = 0.0;
203.610 +#if 1 /* 30/XI-2009 */
203.611 + node->changed = 0;
203.612 +#endif
203.613 + if (tree->parm->cb_size == 0)
203.614 + node->data = NULL;
203.615 + else
203.616 + { node->data = dmp_get_atom(tree->pool, tree->parm->cb_size);
203.617 + memset(node->data, 0, tree->parm->cb_size);
203.618 + }
203.619 + node->temp = NULL;
203.620 + node->prev = tree->tail;
203.621 + node->next = NULL;
203.622 + /* add the new subproblem to the end of the active list */
203.623 + if (tree->head == NULL)
203.624 + tree->head = node;
203.625 + else
203.626 + tree->tail->next = node;
203.627 + tree->tail = node;
203.628 + tree->a_cnt++;
203.629 + tree->n_cnt++;
203.630 + tree->t_cnt++;
203.631 + /* increase the number of child subproblems */
203.632 + if (parent == NULL)
203.633 + xassert(p == 1);
203.634 + else
203.635 + parent->count++;
203.636 + return node;
203.637 +}
203.638 +
203.639 +void ios_clone_node(glp_tree *tree, int p, int nnn, int ref[])
203.640 +{ IOSNPD *node;
203.641 + int k;
203.642 + /* obtain pointer to the subproblem to be cloned */
203.643 + xassert(1 <= p && p <= tree->nslots);
203.644 + node = tree->slot[p].node;
203.645 + xassert(node != NULL);
203.646 + /* the specified subproblem must be active */
203.647 + xassert(node->count == 0);
203.648 + /* and must be in the frozen state */
203.649 + xassert(tree->curr != node);
203.650 + /* remove the specified subproblem from the active list, because
203.651 + it becomes inactive */
203.652 + if (node->prev == NULL)
203.653 + tree->head = node->next;
203.654 + else
203.655 + node->prev->next = node->next;
203.656 + if (node->next == NULL)
203.657 + tree->tail = node->prev;
203.658 + else
203.659 + node->next->prev = node->prev;
203.660 + node->prev = node->next = NULL;
203.661 + tree->a_cnt--;
203.662 + /* create clone subproblems */
203.663 + xassert(nnn > 0);
203.664 + for (k = 1; k <= nnn; k++)
203.665 + ref[k] = new_node(tree, node)->p;
203.666 + return;
203.667 +}
203.668 +
203.669 +/***********************************************************************
203.670 +* NAME
203.671 +*
203.672 +* ios_delete_node - delete specified subproblem
203.673 +*
203.674 +* SYNOPSIS
203.675 +*
203.676 +* #include "glpios.h"
203.677 +* void ios_delete_node(glp_tree *tree, int p);
203.678 +*
203.679 +* DESCRIPTION
203.680 +*
203.681 +* The routine ios_delete_node deletes the specified subproblem, whose
203.682 +* reference number is p. The subproblem must be active and must be in
203.683 +* the frozen state (i.e. it must not be the current subproblem).
203.684 +*
203.685 +* Note that deletion is performed recursively, i.e. if a subproblem to
203.686 +* be deleted is the only child of its parent, the parent subproblem is
203.687 +* also deleted, etc. */
203.688 +
203.689 +void ios_delete_node(glp_tree *tree, int p)
203.690 +{ IOSNPD *node, *temp;
203.691 + /* obtain pointer to the subproblem to be deleted */
203.692 + xassert(1 <= p && p <= tree->nslots);
203.693 + node = tree->slot[p].node;
203.694 + xassert(node != NULL);
203.695 + /* the specified subproblem must be active */
203.696 + xassert(node->count == 0);
203.697 + /* and must be in the frozen state */
203.698 + xassert(tree->curr != node);
203.699 + /* remove the specified subproblem from the active list, because
203.700 + it is gone from the tree */
203.701 + if (node->prev == NULL)
203.702 + tree->head = node->next;
203.703 + else
203.704 + node->prev->next = node->next;
203.705 + if (node->next == NULL)
203.706 + tree->tail = node->prev;
203.707 + else
203.708 + node->next->prev = node->prev;
203.709 + node->prev = node->next = NULL;
203.710 + tree->a_cnt--;
203.711 +loop: /* recursive deletion starts here */
203.712 + /* delete the bound change list */
203.713 + { IOSBND *b;
203.714 + while (node->b_ptr != NULL)
203.715 + { b = node->b_ptr;
203.716 + node->b_ptr = b->next;
203.717 + dmp_free_atom(tree->pool, b, sizeof(IOSBND));
203.718 + }
203.719 + }
203.720 + /* delete the status change list */
203.721 + { IOSTAT *s;
203.722 + while (node->s_ptr != NULL)
203.723 + { s = node->s_ptr;
203.724 + node->s_ptr = s->next;
203.725 + dmp_free_atom(tree->pool, s, sizeof(IOSTAT));
203.726 + }
203.727 + }
203.728 + /* delete the row addition list */
203.729 + while (node->r_ptr != NULL)
203.730 + { IOSROW *r;
203.731 + r = node->r_ptr;
203.732 + if (r->name != NULL)
203.733 + dmp_free_atom(tree->pool, r->name, strlen(r->name)+1);
203.734 + while (r->ptr != NULL)
203.735 + { IOSAIJ *a;
203.736 + a = r->ptr;
203.737 + r->ptr = a->next;
203.738 + dmp_free_atom(tree->pool, a, sizeof(IOSAIJ));
203.739 + }
203.740 + node->r_ptr = r->next;
203.741 + dmp_free_atom(tree->pool, r, sizeof(IOSROW));
203.742 + }
203.743 +#if 0
203.744 + /* delete the edge addition list */
203.745 + /* delete the clique addition list */
203.746 + /* (not implemented yet) */
203.747 + xassert(node->own_nn == 0);
203.748 + xassert(node->own_nc == 0);
203.749 + xassert(node->e_ptr == NULL);
203.750 +#endif
203.751 + /* free application-specific data */
203.752 + if (tree->parm->cb_size == 0)
203.753 + xassert(node->data == NULL);
203.754 + else
203.755 + dmp_free_atom(tree->pool, node->data, tree->parm->cb_size);
203.756 + /* free the corresponding node slot */
203.757 + p = node->p;
203.758 + xassert(tree->slot[p].node == node);
203.759 + tree->slot[p].node = NULL;
203.760 + tree->slot[p].next = tree->avail;
203.761 + tree->avail = p;
203.762 + /* save pointer to the parent subproblem */
203.763 + temp = node->up;
203.764 + /* delete the subproblem descriptor */
203.765 + dmp_free_atom(tree->pool, node, sizeof(IOSNPD));
203.766 + tree->n_cnt--;
203.767 + /* take pointer to the parent subproblem */
203.768 + node = temp;
203.769 + if (node != NULL)
203.770 + { /* the parent subproblem exists; decrease the number of its
203.771 + child subproblems */
203.772 + xassert(node->count > 0);
203.773 + node->count--;
203.774 + /* if now the parent subproblem has no childs, it also must be
203.775 + deleted */
203.776 + if (node->count == 0) goto loop;
203.777 + }
203.778 + return;
203.779 +}
203.780 +
203.781 +/***********************************************************************
203.782 +* NAME
203.783 +*
203.784 +* ios_delete_tree - delete branch-and-bound tree
203.785 +*
203.786 +* SYNOPSIS
203.787 +*
203.788 +* #include "glpios.h"
203.789 +* void ios_delete_tree(glp_tree *tree);
203.790 +*
203.791 +* DESCRIPTION
203.792 +*
203.793 +* The routine ios_delete_tree deletes the branch-and-bound tree, which
203.794 +* the parameter tree points to, and frees all the memory allocated to
203.795 +* this program object.
203.796 +*
203.797 +* On exit components of the problem object are restored to correspond
203.798 +* to the original MIP passed to the routine ios_create_tree. */
203.799 +
203.800 +void ios_delete_tree(glp_tree *tree)
203.801 +{ glp_prob *mip = tree->mip;
203.802 + int i, j;
203.803 + int m = mip->m;
203.804 + int n = mip->n;
203.805 + xassert(mip->tree == tree);
203.806 + /* remove all additional rows */
203.807 + if (m != tree->orig_m)
203.808 + { int nrs, *num;
203.809 + nrs = m - tree->orig_m;
203.810 + xassert(nrs > 0);
203.811 + num = xcalloc(1+nrs, sizeof(int));
203.812 + for (i = 1; i <= nrs; i++) num[i] = tree->orig_m + i;
203.813 + glp_del_rows(mip, nrs, num);
203.814 + xfree(num);
203.815 + }
203.816 + m = tree->orig_m;
203.817 + /* restore original attributes of rows and columns */
203.818 + xassert(m == tree->orig_m);
203.819 + xassert(n == tree->n);
203.820 + for (i = 1; i <= m; i++)
203.821 + { glp_set_row_bnds(mip, i, tree->orig_type[i],
203.822 + tree->orig_lb[i], tree->orig_ub[i]);
203.823 + glp_set_row_stat(mip, i, tree->orig_stat[i]);
203.824 + mip->row[i]->prim = tree->orig_prim[i];
203.825 + mip->row[i]->dual = tree->orig_dual[i];
203.826 + }
203.827 + for (j = 1; j <= n; j++)
203.828 + { glp_set_col_bnds(mip, j, tree->orig_type[m+j],
203.829 + tree->orig_lb[m+j], tree->orig_ub[m+j]);
203.830 + glp_set_col_stat(mip, j, tree->orig_stat[m+j]);
203.831 + mip->col[j]->prim = tree->orig_prim[m+j];
203.832 + mip->col[j]->dual = tree->orig_dual[m+j];
203.833 + }
203.834 + mip->pbs_stat = mip->dbs_stat = GLP_FEAS;
203.835 + mip->obj_val = tree->orig_obj;
203.836 + /* delete the branch-and-bound tree */
203.837 + xassert(tree->local != NULL);
203.838 + ios_delete_pool(tree, tree->local);
203.839 + dmp_delete_pool(tree->pool);
203.840 + xfree(tree->orig_type);
203.841 + xfree(tree->orig_lb);
203.842 + xfree(tree->orig_ub);
203.843 + xfree(tree->orig_stat);
203.844 + xfree(tree->orig_prim);
203.845 + xfree(tree->orig_dual);
203.846 + xfree(tree->slot);
203.847 + if (tree->root_type != NULL) xfree(tree->root_type);
203.848 + if (tree->root_lb != NULL) xfree(tree->root_lb);
203.849 + if (tree->root_ub != NULL) xfree(tree->root_ub);
203.850 + if (tree->root_stat != NULL) xfree(tree->root_stat);
203.851 + xfree(tree->non_int);
203.852 +#if 0
203.853 + xfree(tree->n_ref);
203.854 + xfree(tree->c_ref);
203.855 + xfree(tree->j_ref);
203.856 +#endif
203.857 + if (tree->pcost != NULL) ios_pcost_free(tree);
203.858 + xfree(tree->iwrk);
203.859 + xfree(tree->dwrk);
203.860 +#if 0
203.861 + scg_delete_graph(tree->g);
203.862 +#endif
203.863 + if (tree->pred_type != NULL) xfree(tree->pred_type);
203.864 + if (tree->pred_lb != NULL) xfree(tree->pred_lb);
203.865 + if (tree->pred_ub != NULL) xfree(tree->pred_ub);
203.866 + if (tree->pred_stat != NULL) xfree(tree->pred_stat);
203.867 +#if 0
203.868 + xassert(tree->cut_gen == NULL);
203.869 +#endif
203.870 + xassert(tree->mir_gen == NULL);
203.871 + xassert(tree->clq_gen == NULL);
203.872 + xfree(tree);
203.873 + mip->tree = NULL;
203.874 + return;
203.875 +}
203.876 +
203.877 +/***********************************************************************
203.878 +* NAME
203.879 +*
203.880 +* ios_eval_degrad - estimate obj. degrad. for down- and up-branches
203.881 +*
203.882 +* SYNOPSIS
203.883 +*
203.884 +* #include "glpios.h"
203.885 +* void ios_eval_degrad(glp_tree *tree, int j, double *dn, double *up);
203.886 +*
203.887 +* DESCRIPTION
203.888 +*
203.889 +* Given optimal basis to LP relaxation of the current subproblem the
203.890 +* routine ios_eval_degrad performs the dual ratio test to compute the
203.891 +* objective values in the adjacent basis for down- and up-branches,
203.892 +* which are stored in locations *dn and *up, assuming that x[j] is a
203.893 +* variable chosen to branch upon. */
203.894 +
203.895 +void ios_eval_degrad(glp_tree *tree, int j, double *dn, double *up)
203.896 +{ glp_prob *mip = tree->mip;
203.897 + int m = mip->m, n = mip->n;
203.898 + int len, kase, k, t, stat;
203.899 + double alfa, beta, gamma, delta, dz;
203.900 + int *ind = tree->iwrk;
203.901 + double *val = tree->dwrk;
203.902 + /* current basis must be optimal */
203.903 + xassert(glp_get_status(mip) == GLP_OPT);
203.904 + /* basis factorization must exist */
203.905 + xassert(glp_bf_exists(mip));
203.906 + /* obtain (fractional) value of x[j] in optimal basic solution
203.907 + to LP relaxation of the current subproblem */
203.908 + xassert(1 <= j && j <= n);
203.909 + beta = mip->col[j]->prim;
203.910 + /* since the value of x[j] is fractional, it is basic; compute
203.911 + corresponding row of the simplex table */
203.912 + len = lpx_eval_tab_row(mip, m+j, ind, val);
203.913 + /* kase < 0 means down-branch; kase > 0 means up-branch */
203.914 + for (kase = -1; kase <= +1; kase += 2)
203.915 + { /* for down-branch we introduce new upper bound floor(beta)
203.916 + for x[j]; similarly, for up-branch we introduce new lower
203.917 + bound ceil(beta) for x[j]; in the current basis this new
203.918 + upper/lower bound is violated, so in the adjacent basis
203.919 + x[j] will leave the basis and go to its new upper/lower
203.920 + bound; we need to know which non-basic variable x[k] should
203.921 + enter the basis to keep dual feasibility */
203.922 +#if 0 /* 23/XI-2009 */
203.923 + k = lpx_dual_ratio_test(mip, len, ind, val, kase, 1e-7);
203.924 +#else
203.925 + k = lpx_dual_ratio_test(mip, len, ind, val, kase, 1e-9);
203.926 +#endif
203.927 + /* if no variable has been chosen, current basis being primal
203.928 + infeasible due to the new upper/lower bound of x[j] is dual
203.929 + unbounded, therefore, LP relaxation to corresponding branch
203.930 + has no primal feasible solution */
203.931 + if (k == 0)
203.932 + { if (mip->dir == GLP_MIN)
203.933 + { if (kase < 0)
203.934 + *dn = +DBL_MAX;
203.935 + else
203.936 + *up = +DBL_MAX;
203.937 + }
203.938 + else if (mip->dir == GLP_MAX)
203.939 + { if (kase < 0)
203.940 + *dn = -DBL_MAX;
203.941 + else
203.942 + *up = -DBL_MAX;
203.943 + }
203.944 + else
203.945 + xassert(mip != mip);
203.946 + continue;
203.947 + }
203.948 + xassert(1 <= k && k <= m+n);
203.949 + /* row of the simplex table corresponding to specified basic
203.950 + variable x[j] is the following:
203.951 + x[j] = ... + alfa * x[k] + ... ;
203.952 + we need to know influence coefficient, alfa, at non-basic
203.953 + variable x[k] chosen with the dual ratio test */
203.954 + for (t = 1; t <= len; t++)
203.955 + if (ind[t] == k) break;
203.956 + xassert(1 <= t && t <= len);
203.957 + alfa = val[t];
203.958 + /* determine status and reduced cost of variable x[k] */
203.959 + if (k <= m)
203.960 + { stat = mip->row[k]->stat;
203.961 + gamma = mip->row[k]->dual;
203.962 + }
203.963 + else
203.964 + { stat = mip->col[k-m]->stat;
203.965 + gamma = mip->col[k-m]->dual;
203.966 + }
203.967 + /* x[k] cannot be basic or fixed non-basic */
203.968 + xassert(stat == GLP_NL || stat == GLP_NU || stat == GLP_NF);
203.969 + /* if the current basis is dual degenerative, some reduced
203.970 + costs, which are close to zero, may have wrong sign due to
203.971 + round-off errors, so correct the sign of gamma */
203.972 + if (mip->dir == GLP_MIN)
203.973 + { if (stat == GLP_NL && gamma < 0.0 ||
203.974 + stat == GLP_NU && gamma > 0.0 ||
203.975 + stat == GLP_NF) gamma = 0.0;
203.976 + }
203.977 + else if (mip->dir == GLP_MAX)
203.978 + { if (stat == GLP_NL && gamma > 0.0 ||
203.979 + stat == GLP_NU && gamma < 0.0 ||
203.980 + stat == GLP_NF) gamma = 0.0;
203.981 + }
203.982 + else
203.983 + xassert(mip != mip);
203.984 + /* determine the change of x[j] in the adjacent basis:
203.985 + delta x[j] = new x[j] - old x[j] */
203.986 + delta = (kase < 0 ? floor(beta) : ceil(beta)) - beta;
203.987 + /* compute the change of x[k] in the adjacent basis:
203.988 + delta x[k] = new x[k] - old x[k] = delta x[j] / alfa */
203.989 + delta /= alfa;
203.990 + /* compute the change of the objective in the adjacent basis:
203.991 + delta z = new z - old z = gamma * delta x[k] */
203.992 + dz = gamma * delta;
203.993 + if (mip->dir == GLP_MIN)
203.994 + xassert(dz >= 0.0);
203.995 + else if (mip->dir == GLP_MAX)
203.996 + xassert(dz <= 0.0);
203.997 + else
203.998 + xassert(mip != mip);
203.999 + /* compute the new objective value in the adjacent basis:
203.1000 + new z = old z + delta z */
203.1001 + if (kase < 0)
203.1002 + *dn = mip->obj_val + dz;
203.1003 + else
203.1004 + *up = mip->obj_val + dz;
203.1005 + }
203.1006 + /*xprintf("obj = %g; dn = %g; up = %g\n",
203.1007 + mip->obj_val, *dn, *up);*/
203.1008 + return;
203.1009 +}
203.1010 +
203.1011 +/***********************************************************************
203.1012 +* NAME
203.1013 +*
203.1014 +* ios_round_bound - improve local bound by rounding
203.1015 +*
203.1016 +* SYNOPSIS
203.1017 +*
203.1018 +* #include "glpios.h"
203.1019 +* double ios_round_bound(glp_tree *tree, double bound);
203.1020 +*
203.1021 +* RETURNS
203.1022 +*
203.1023 +* For the given local bound for any integer feasible solution to the
203.1024 +* current subproblem the routine ios_round_bound returns an improved
203.1025 +* local bound for the same integer feasible solution.
203.1026 +*
203.1027 +* BACKGROUND
203.1028 +*
203.1029 +* Let the current subproblem has the following objective function:
203.1030 +*
203.1031 +* z = sum c[j] * x[j] + s >= b, (1)
203.1032 +* j in J
203.1033 +*
203.1034 +* where J = {j: c[j] is non-zero and integer, x[j] is integer}, s is
203.1035 +* the sum of terms corresponding to fixed variables, b is an initial
203.1036 +* local bound (minimization).
203.1037 +*
203.1038 +* From (1) it follows that:
203.1039 +*
203.1040 +* d * sum (c[j] / d) * x[j] + s >= b, (2)
203.1041 +* j in J
203.1042 +*
203.1043 +* or, equivalently,
203.1044 +*
203.1045 +* sum (c[j] / d) * x[j] >= (b - s) / d = h, (3)
203.1046 +* j in J
203.1047 +*
203.1048 +* where d = gcd(c[j]). Since the left-hand side of (3) is integer,
203.1049 +* h = (b - s) / d can be rounded up to the nearest integer:
203.1050 +*
203.1051 +* h' = ceil(h) = (b' - s) / d, (4)
203.1052 +*
203.1053 +* that gives an rounded, improved local bound:
203.1054 +*
203.1055 +* b' = d * h' + s. (5)
203.1056 +*
203.1057 +* In case of maximization '>=' in (1) should be replaced by '<=' that
203.1058 +* leads to the following formula:
203.1059 +*
203.1060 +* h' = floor(h) = (b' - s) / d, (6)
203.1061 +*
203.1062 +* which should used in the same way as (4).
203.1063 +*
203.1064 +* NOTE: If b is a valid local bound for a child of the current
203.1065 +* subproblem, b' is also valid for that child subproblem. */
203.1066 +
203.1067 +double ios_round_bound(glp_tree *tree, double bound)
203.1068 +{ glp_prob *mip = tree->mip;
203.1069 + int n = mip->n;
203.1070 + int d, j, nn, *c = tree->iwrk;
203.1071 + double s, h;
203.1072 + /* determine c[j] and compute s */
203.1073 + nn = 0, s = mip->c0, d = 0;
203.1074 + for (j = 1; j <= n; j++)
203.1075 + { GLPCOL *col = mip->col[j];
203.1076 + if (col->coef == 0.0) continue;
203.1077 + if (col->type == GLP_FX)
203.1078 + { /* fixed variable */
203.1079 + s += col->coef * col->prim;
203.1080 + }
203.1081 + else
203.1082 + { /* non-fixed variable */
203.1083 + if (col->kind != GLP_IV) goto skip;
203.1084 + if (col->coef != floor(col->coef)) goto skip;
203.1085 + if (fabs(col->coef) <= (double)INT_MAX)
203.1086 + c[++nn] = (int)fabs(col->coef);
203.1087 + else
203.1088 + d = 1;
203.1089 + }
203.1090 + }
203.1091 + /* compute d = gcd(c[1],...c[nn]) */
203.1092 + if (d == 0)
203.1093 + { if (nn == 0) goto skip;
203.1094 + d = gcdn(nn, c);
203.1095 + }
203.1096 + xassert(d > 0);
203.1097 + /* compute new local bound */
203.1098 + if (mip->dir == GLP_MIN)
203.1099 + { if (bound != +DBL_MAX)
203.1100 + { h = (bound - s) / (double)d;
203.1101 + if (h >= floor(h) + 0.001)
203.1102 + { /* round up */
203.1103 + h = ceil(h);
203.1104 + /*xprintf("d = %d; old = %g; ", d, bound);*/
203.1105 + bound = (double)d * h + s;
203.1106 + /*xprintf("new = %g\n", bound);*/
203.1107 + }
203.1108 + }
203.1109 + }
203.1110 + else if (mip->dir == GLP_MAX)
203.1111 + { if (bound != -DBL_MAX)
203.1112 + { h = (bound - s) / (double)d;
203.1113 + if (h <= ceil(h) - 0.001)
203.1114 + { /* round down */
203.1115 + h = floor(h);
203.1116 + bound = (double)d * h + s;
203.1117 + }
203.1118 + }
203.1119 + }
203.1120 + else
203.1121 + xassert(mip != mip);
203.1122 +skip: return bound;
203.1123 +}
203.1124 +
203.1125 +/***********************************************************************
203.1126 +* NAME
203.1127 +*
203.1128 +* ios_is_hopeful - check if subproblem is hopeful
203.1129 +*
203.1130 +* SYNOPSIS
203.1131 +*
203.1132 +* #include "glpios.h"
203.1133 +* int ios_is_hopeful(glp_tree *tree, double bound);
203.1134 +*
203.1135 +* DESCRIPTION
203.1136 +*
203.1137 +* Given the local bound of a subproblem the routine ios_is_hopeful
203.1138 +* checks if the subproblem can have an integer optimal solution which
203.1139 +* is better than the best one currently known.
203.1140 +*
203.1141 +* RETURNS
203.1142 +*
203.1143 +* If the subproblem can have a better integer optimal solution, the
203.1144 +* routine returns non-zero; otherwise, if the corresponding branch can
203.1145 +* be pruned, the routine returns zero. */
203.1146 +
203.1147 +int ios_is_hopeful(glp_tree *tree, double bound)
203.1148 +{ glp_prob *mip = tree->mip;
203.1149 + int ret = 1;
203.1150 + double eps;
203.1151 + if (mip->mip_stat == GLP_FEAS)
203.1152 + { eps = tree->parm->tol_obj * (1.0 + fabs(mip->mip_obj));
203.1153 + switch (mip->dir)
203.1154 + { case GLP_MIN:
203.1155 + if (bound >= mip->mip_obj - eps) ret = 0;
203.1156 + break;
203.1157 + case GLP_MAX:
203.1158 + if (bound <= mip->mip_obj + eps) ret = 0;
203.1159 + break;
203.1160 + default:
203.1161 + xassert(mip != mip);
203.1162 + }
203.1163 + }
203.1164 + else
203.1165 + { switch (mip->dir)
203.1166 + { case GLP_MIN:
203.1167 + if (bound == +DBL_MAX) ret = 0;
203.1168 + break;
203.1169 + case GLP_MAX:
203.1170 + if (bound == -DBL_MAX) ret = 0;
203.1171 + break;
203.1172 + default:
203.1173 + xassert(mip != mip);
203.1174 + }
203.1175 + }
203.1176 + return ret;
203.1177 +}
203.1178 +
203.1179 +/***********************************************************************
203.1180 +* NAME
203.1181 +*
203.1182 +* ios_best_node - find active node with best local bound
203.1183 +*
203.1184 +* SYNOPSIS
203.1185 +*
203.1186 +* #include "glpios.h"
203.1187 +* int ios_best_node(glp_tree *tree);
203.1188 +*
203.1189 +* DESCRIPTION
203.1190 +*
203.1191 +* The routine ios_best_node finds an active node whose local bound is
203.1192 +* best among other active nodes.
203.1193 +*
203.1194 +* It is understood that the integer optimal solution of the original
203.1195 +* mip problem cannot be better than the best bound, so the best bound
203.1196 +* is an lower (minimization) or upper (maximization) global bound for
203.1197 +* the original problem.
203.1198 +*
203.1199 +* RETURNS
203.1200 +*
203.1201 +* The routine ios_best_node returns the subproblem reference number
203.1202 +* for the best node. However, if the tree is empty, it returns zero. */
203.1203 +
203.1204 +int ios_best_node(glp_tree *tree)
203.1205 +{ IOSNPD *node, *best = NULL;
203.1206 + switch (tree->mip->dir)
203.1207 + { case GLP_MIN:
203.1208 + /* minimization */
203.1209 + for (node = tree->head; node != NULL; node = node->next)
203.1210 + if (best == NULL || best->bound > node->bound)
203.1211 + best = node;
203.1212 + break;
203.1213 + case GLP_MAX:
203.1214 + /* maximization */
203.1215 + for (node = tree->head; node != NULL; node = node->next)
203.1216 + if (best == NULL || best->bound < node->bound)
203.1217 + best = node;
203.1218 + break;
203.1219 + default:
203.1220 + xassert(tree != tree);
203.1221 + }
203.1222 + return best == NULL ? 0 : best->p;
203.1223 +}
203.1224 +
203.1225 +/***********************************************************************
203.1226 +* NAME
203.1227 +*
203.1228 +* ios_relative_gap - compute relative mip gap
203.1229 +*
203.1230 +* SYNOPSIS
203.1231 +*
203.1232 +* #include "glpios.h"
203.1233 +* double ios_relative_gap(glp_tree *tree);
203.1234 +*
203.1235 +* DESCRIPTION
203.1236 +*
203.1237 +* The routine ios_relative_gap computes the relative mip gap using the
203.1238 +* formula:
203.1239 +*
203.1240 +* gap = |best_mip - best_bnd| / (|best_mip| + DBL_EPSILON),
203.1241 +*
203.1242 +* where best_mip is the best integer feasible solution found so far,
203.1243 +* best_bnd is the best (global) bound. If no integer feasible solution
203.1244 +* has been found yet, rel_gap is set to DBL_MAX.
203.1245 +*
203.1246 +* RETURNS
203.1247 +*
203.1248 +* The routine ios_relative_gap returns the relative mip gap. */
203.1249 +
203.1250 +double ios_relative_gap(glp_tree *tree)
203.1251 +{ glp_prob *mip = tree->mip;
203.1252 + int p;
203.1253 + double best_mip, best_bnd, gap;
203.1254 + if (mip->mip_stat == GLP_FEAS)
203.1255 + { best_mip = mip->mip_obj;
203.1256 + p = ios_best_node(tree);
203.1257 + if (p == 0)
203.1258 + { /* the tree is empty */
203.1259 + gap = 0.0;
203.1260 + }
203.1261 + else
203.1262 + { best_bnd = tree->slot[p].node->bound;
203.1263 + gap = fabs(best_mip - best_bnd) / (fabs(best_mip) +
203.1264 + DBL_EPSILON);
203.1265 + }
203.1266 + }
203.1267 + else
203.1268 + { /* no integer feasible solution has been found yet */
203.1269 + gap = DBL_MAX;
203.1270 + }
203.1271 + return gap;
203.1272 +}
203.1273 +
203.1274 +/***********************************************************************
203.1275 +* NAME
203.1276 +*
203.1277 +* ios_solve_node - solve LP relaxation of current subproblem
203.1278 +*
203.1279 +* SYNOPSIS
203.1280 +*
203.1281 +* #include "glpios.h"
203.1282 +* int ios_solve_node(glp_tree *tree);
203.1283 +*
203.1284 +* DESCRIPTION
203.1285 +*
203.1286 +* The routine ios_solve_node re-optimizes LP relaxation of the current
203.1287 +* subproblem using the dual simplex method.
203.1288 +*
203.1289 +* RETURNS
203.1290 +*
203.1291 +* The routine returns the code which is reported by glp_simplex. */
203.1292 +
203.1293 +int ios_solve_node(glp_tree *tree)
203.1294 +{ glp_prob *mip = tree->mip;
203.1295 + glp_smcp parm;
203.1296 + int ret;
203.1297 + /* the current subproblem must exist */
203.1298 + xassert(tree->curr != NULL);
203.1299 + /* set some control parameters */
203.1300 + glp_init_smcp(&parm);
203.1301 + switch (tree->parm->msg_lev)
203.1302 + { case GLP_MSG_OFF:
203.1303 + parm.msg_lev = GLP_MSG_OFF; break;
203.1304 + case GLP_MSG_ERR:
203.1305 + parm.msg_lev = GLP_MSG_ERR; break;
203.1306 + case GLP_MSG_ON:
203.1307 + case GLP_MSG_ALL:
203.1308 + parm.msg_lev = GLP_MSG_ON; break;
203.1309 + case GLP_MSG_DBG:
203.1310 + parm.msg_lev = GLP_MSG_ALL; break;
203.1311 + default:
203.1312 + xassert(tree != tree);
203.1313 + }
203.1314 + parm.meth = GLP_DUALP;
203.1315 + if (tree->parm->msg_lev < GLP_MSG_DBG)
203.1316 + parm.out_dly = tree->parm->out_dly;
203.1317 + else
203.1318 + parm.out_dly = 0;
203.1319 + /* if the incumbent objective value is already known, use it to
203.1320 + prematurely terminate the dual simplex search */
203.1321 + if (mip->mip_stat == GLP_FEAS)
203.1322 + { switch (tree->mip->dir)
203.1323 + { case GLP_MIN:
203.1324 + parm.obj_ul = mip->mip_obj;
203.1325 + break;
203.1326 + case GLP_MAX:
203.1327 + parm.obj_ll = mip->mip_obj;
203.1328 + break;
203.1329 + default:
203.1330 + xassert(mip != mip);
203.1331 + }
203.1332 + }
203.1333 + /* try to solve/re-optimize the LP relaxation */
203.1334 + ret = glp_simplex(mip, &parm);
203.1335 + tree->curr->solved++;
203.1336 +#if 0
203.1337 + xprintf("ret = %d; status = %d; pbs = %d; dbs = %d; some = %d\n",
203.1338 + ret, glp_get_status(mip), mip->pbs_stat, mip->dbs_stat,
203.1339 + mip->some);
203.1340 + lpx_print_sol(mip, "sol");
203.1341 +#endif
203.1342 + return ret;
203.1343 +}
203.1344 +
203.1345 +/**********************************************************************/
203.1346 +
203.1347 +IOSPOOL *ios_create_pool(glp_tree *tree)
203.1348 +{ /* create cut pool */
203.1349 + IOSPOOL *pool;
203.1350 +#if 0
203.1351 + pool = dmp_get_atom(tree->pool, sizeof(IOSPOOL));
203.1352 +#else
203.1353 + xassert(tree == tree);
203.1354 + pool = xmalloc(sizeof(IOSPOOL));
203.1355 +#endif
203.1356 + pool->size = 0;
203.1357 + pool->head = pool->tail = NULL;
203.1358 + pool->ord = 0, pool->curr = NULL;
203.1359 + return pool;
203.1360 +}
203.1361 +
203.1362 +int ios_add_row(glp_tree *tree, IOSPOOL *pool,
203.1363 + const char *name, int klass, int flags, int len, const int ind[],
203.1364 + const double val[], int type, double rhs)
203.1365 +{ /* add row (constraint) to the cut pool */
203.1366 + IOSCUT *cut;
203.1367 + IOSAIJ *aij;
203.1368 + int k;
203.1369 + xassert(pool != NULL);
203.1370 + cut = dmp_get_atom(tree->pool, sizeof(IOSCUT));
203.1371 + if (name == NULL || name[0] == '\0')
203.1372 + cut->name = NULL;
203.1373 + else
203.1374 + { for (k = 0; name[k] != '\0'; k++)
203.1375 + { if (k == 256)
203.1376 + xerror("glp_ios_add_row: cut name too long\n");
203.1377 + if (iscntrl((unsigned char)name[k]))
203.1378 + xerror("glp_ios_add_row: cut name contains invalid chara"
203.1379 + "cter(s)\n");
203.1380 + }
203.1381 + cut->name = dmp_get_atom(tree->pool, strlen(name)+1);
203.1382 + strcpy(cut->name, name);
203.1383 + }
203.1384 + if (!(0 <= klass && klass <= 255))
203.1385 + xerror("glp_ios_add_row: klass = %d; invalid cut class\n",
203.1386 + klass);
203.1387 + cut->klass = (unsigned char)klass;
203.1388 + if (flags != 0)
203.1389 + xerror("glp_ios_add_row: flags = %d; invalid cut flags\n",
203.1390 + flags);
203.1391 + cut->ptr = NULL;
203.1392 + if (!(0 <= len && len <= tree->n))
203.1393 + xerror("glp_ios_add_row: len = %d; invalid cut length\n",
203.1394 + len);
203.1395 + for (k = 1; k <= len; k++)
203.1396 + { aij = dmp_get_atom(tree->pool, sizeof(IOSAIJ));
203.1397 + if (!(1 <= ind[k] && ind[k] <= tree->n))
203.1398 + xerror("glp_ios_add_row: ind[%d] = %d; column index out of "
203.1399 + "range\n", k, ind[k]);
203.1400 + aij->j = ind[k];
203.1401 + aij->val = val[k];
203.1402 + aij->next = cut->ptr;
203.1403 + cut->ptr = aij;
203.1404 + }
203.1405 + if (!(type == GLP_LO || type == GLP_UP || type == GLP_FX))
203.1406 + xerror("glp_ios_add_row: type = %d; invalid cut type\n",
203.1407 + type);
203.1408 + cut->type = (unsigned char)type;
203.1409 + cut->rhs = rhs;
203.1410 + cut->prev = pool->tail;
203.1411 + cut->next = NULL;
203.1412 + if (cut->prev == NULL)
203.1413 + pool->head = cut;
203.1414 + else
203.1415 + cut->prev->next = cut;
203.1416 + pool->tail = cut;
203.1417 + pool->size++;
203.1418 + return pool->size;
203.1419 +}
203.1420 +
203.1421 +IOSCUT *ios_find_row(IOSPOOL *pool, int i)
203.1422 +{ /* find row (constraint) in the cut pool */
203.1423 + /* (smart linear search) */
203.1424 + xassert(pool != NULL);
203.1425 + xassert(1 <= i && i <= pool->size);
203.1426 + if (pool->ord == 0)
203.1427 + { xassert(pool->curr == NULL);
203.1428 + pool->ord = 1;
203.1429 + pool->curr = pool->head;
203.1430 + }
203.1431 + xassert(pool->curr != NULL);
203.1432 + if (i < pool->ord)
203.1433 + { if (i < pool->ord - i)
203.1434 + { pool->ord = 1;
203.1435 + pool->curr = pool->head;
203.1436 + while (pool->ord != i)
203.1437 + { pool->ord++;
203.1438 + xassert(pool->curr != NULL);
203.1439 + pool->curr = pool->curr->next;
203.1440 + }
203.1441 + }
203.1442 + else
203.1443 + { while (pool->ord != i)
203.1444 + { pool->ord--;
203.1445 + xassert(pool->curr != NULL);
203.1446 + pool->curr = pool->curr->prev;
203.1447 + }
203.1448 + }
203.1449 + }
203.1450 + else if (i > pool->ord)
203.1451 + { if (i - pool->ord < pool->size - i)
203.1452 + { while (pool->ord != i)
203.1453 + { pool->ord++;
203.1454 + xassert(pool->curr != NULL);
203.1455 + pool->curr = pool->curr->next;
203.1456 + }
203.1457 + }
203.1458 + else
203.1459 + { pool->ord = pool->size;
203.1460 + pool->curr = pool->tail;
203.1461 + while (pool->ord != i)
203.1462 + { pool->ord--;
203.1463 + xassert(pool->curr != NULL);
203.1464 + pool->curr = pool->curr->prev;
203.1465 + }
203.1466 + }
203.1467 + }
203.1468 + xassert(pool->ord == i);
203.1469 + xassert(pool->curr != NULL);
203.1470 + return pool->curr;
203.1471 +}
203.1472 +
203.1473 +void ios_del_row(glp_tree *tree, IOSPOOL *pool, int i)
203.1474 +{ /* remove row (constraint) from the cut pool */
203.1475 + IOSCUT *cut;
203.1476 + IOSAIJ *aij;
203.1477 + xassert(pool != NULL);
203.1478 + if (!(1 <= i && i <= pool->size))
203.1479 + xerror("glp_ios_del_row: i = %d; cut number out of range\n",
203.1480 + i);
203.1481 + cut = ios_find_row(pool, i);
203.1482 + xassert(pool->curr == cut);
203.1483 + if (cut->next != NULL)
203.1484 + pool->curr = cut->next;
203.1485 + else if (cut->prev != NULL)
203.1486 + pool->ord--, pool->curr = cut->prev;
203.1487 + else
203.1488 + pool->ord = 0, pool->curr = NULL;
203.1489 + if (cut->name != NULL)
203.1490 + dmp_free_atom(tree->pool, cut->name, strlen(cut->name)+1);
203.1491 + if (cut->prev == NULL)
203.1492 + { xassert(pool->head == cut);
203.1493 + pool->head = cut->next;
203.1494 + }
203.1495 + else
203.1496 + { xassert(cut->prev->next == cut);
203.1497 + cut->prev->next = cut->next;
203.1498 + }
203.1499 + if (cut->next == NULL)
203.1500 + { xassert(pool->tail == cut);
203.1501 + pool->tail = cut->prev;
203.1502 + }
203.1503 + else
203.1504 + { xassert(cut->next->prev == cut);
203.1505 + cut->next->prev = cut->prev;
203.1506 + }
203.1507 + while (cut->ptr != NULL)
203.1508 + { aij = cut->ptr;
203.1509 + cut->ptr = aij->next;
203.1510 + dmp_free_atom(tree->pool, aij, sizeof(IOSAIJ));
203.1511 + }
203.1512 + dmp_free_atom(tree->pool, cut, sizeof(IOSCUT));
203.1513 + pool->size--;
203.1514 + return;
203.1515 +}
203.1516 +
203.1517 +void ios_clear_pool(glp_tree *tree, IOSPOOL *pool)
203.1518 +{ /* remove all rows (constraints) from the cut pool */
203.1519 + xassert(pool != NULL);
203.1520 + while (pool->head != NULL)
203.1521 + { IOSCUT *cut = pool->head;
203.1522 + pool->head = cut->next;
203.1523 + if (cut->name != NULL)
203.1524 + dmp_free_atom(tree->pool, cut->name, strlen(cut->name)+1);
203.1525 + while (cut->ptr != NULL)
203.1526 + { IOSAIJ *aij = cut->ptr;
203.1527 + cut->ptr = aij->next;
203.1528 + dmp_free_atom(tree->pool, aij, sizeof(IOSAIJ));
203.1529 + }
203.1530 + dmp_free_atom(tree->pool, cut, sizeof(IOSCUT));
203.1531 + }
203.1532 + pool->size = 0;
203.1533 + pool->head = pool->tail = NULL;
203.1534 + pool->ord = 0, pool->curr = NULL;
203.1535 + return;
203.1536 +}
203.1537 +
203.1538 +void ios_delete_pool(glp_tree *tree, IOSPOOL *pool)
203.1539 +{ /* delete cut pool */
203.1540 + xassert(pool != NULL);
203.1541 + ios_clear_pool(tree, pool);
203.1542 + xfree(pool);
203.1543 + return;
203.1544 +}
203.1545 +
203.1546 +/**********************************************************************/
203.1547 +
203.1548 +#if 0
203.1549 +static int refer_to_node(glp_tree *tree, int j)
203.1550 +{ /* determine node number corresponding to binary variable x[j] or
203.1551 + its complement */
203.1552 + glp_prob *mip = tree->mip;
203.1553 + int n = mip->n;
203.1554 + int *ref;
203.1555 + if (j > 0)
203.1556 + ref = tree->n_ref;
203.1557 + else
203.1558 + ref = tree->c_ref, j = - j;
203.1559 + xassert(1 <= j && j <= n);
203.1560 + if (ref[j] == 0)
203.1561 + { /* new node is needed */
203.1562 + SCG *g = tree->g;
203.1563 + int n_max = g->n_max;
203.1564 + ref[j] = scg_add_nodes(g, 1);
203.1565 + if (g->n_max > n_max)
203.1566 + { int *save = tree->j_ref;
203.1567 + tree->j_ref = xcalloc(1+g->n_max, sizeof(int));
203.1568 + memcpy(&tree->j_ref[1], &save[1], g->n * sizeof(int));
203.1569 + xfree(save);
203.1570 + }
203.1571 + xassert(ref[j] == g->n);
203.1572 + tree->j_ref[ref[j]] = j;
203.1573 + xassert(tree->curr != NULL);
203.1574 + if (tree->curr->level > 0) tree->curr->own_nn++;
203.1575 + }
203.1576 + return ref[j];
203.1577 +}
203.1578 +#endif
203.1579 +
203.1580 +#if 0
203.1581 +void ios_add_edge(glp_tree *tree, int j1, int j2)
203.1582 +{ /* add new edge to the conflict graph */
203.1583 + glp_prob *mip = tree->mip;
203.1584 + int n = mip->n;
203.1585 + SCGRIB *e;
203.1586 + int first, i1, i2;
203.1587 + xassert(-n <= j1 && j1 <= +n && j1 != 0);
203.1588 + xassert(-n <= j2 && j2 <= +n && j2 != 0);
203.1589 + xassert(j1 != j2);
203.1590 + /* determine number of the first node, which was added for the
203.1591 + current subproblem */
203.1592 + xassert(tree->curr != NULL);
203.1593 + first = tree->g->n - tree->curr->own_nn + 1;
203.1594 + /* determine node numbers for both endpoints */
203.1595 + i1 = refer_to_node(tree, j1);
203.1596 + i2 = refer_to_node(tree, j2);
203.1597 + /* add edge (i1,i2) to the conflict graph */
203.1598 + e = scg_add_edge(tree->g, i1, i2);
203.1599 + /* if the current subproblem is not the root and both endpoints
203.1600 + were created on some previous levels, save the edge */
203.1601 + if (tree->curr->level > 0 && i1 < first && i2 < first)
203.1602 + { IOSRIB *rib;
203.1603 + rib = dmp_get_atom(tree->pool, sizeof(IOSRIB));
203.1604 + rib->j1 = j1;
203.1605 + rib->j2 = j2;
203.1606 + rib->e = e;
203.1607 + rib->next = tree->curr->e_ptr;
203.1608 + tree->curr->e_ptr = rib;
203.1609 + }
203.1610 + return;
203.1611 +}
203.1612 +#endif
203.1613 +
203.1614 +/* eof */
204.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
204.2 +++ b/src/glpios02.c Mon Dec 06 13:09:21 2010 +0100
204.3 @@ -0,0 +1,825 @@
204.4 +/* glpios02.c (preprocess current subproblem) */
204.5 +
204.6 +/***********************************************************************
204.7 +* This code is part of GLPK (GNU Linear Programming Kit).
204.8 +*
204.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
204.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
204.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
204.12 +* E-mail: <mao@gnu.org>.
204.13 +*
204.14 +* GLPK is free software: you can redistribute it and/or modify it
204.15 +* under the terms of the GNU General Public License as published by
204.16 +* the Free Software Foundation, either version 3 of the License, or
204.17 +* (at your option) any later version.
204.18 +*
204.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
204.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
204.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
204.22 +* License for more details.
204.23 +*
204.24 +* You should have received a copy of the GNU General Public License
204.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
204.26 +***********************************************************************/
204.27 +
204.28 +#include "glpios.h"
204.29 +
204.30 +/***********************************************************************
204.31 +* prepare_row_info - prepare row info to determine implied bounds
204.32 +*
204.33 +* Given a row (linear form)
204.34 +*
204.35 +* n
204.36 +* sum a[j] * x[j] (1)
204.37 +* j=1
204.38 +*
204.39 +* and bounds of columns (variables)
204.40 +*
204.41 +* l[j] <= x[j] <= u[j] (2)
204.42 +*
204.43 +* this routine computes f_min, j_min, f_max, j_max needed to determine
204.44 +* implied bounds.
204.45 +*
204.46 +* ALGORITHM
204.47 +*
204.48 +* Let J+ = {j : a[j] > 0} and J- = {j : a[j] < 0}.
204.49 +*
204.50 +* Parameters f_min and j_min are computed as follows:
204.51 +*
204.52 +* 1) if there is no x[k] such that k in J+ and l[k] = -inf or k in J-
204.53 +* and u[k] = +inf, then
204.54 +*
204.55 +* f_min := sum a[j] * l[j] + sum a[j] * u[j]
204.56 +* j in J+ j in J-
204.57 +* (3)
204.58 +* j_min := 0
204.59 +*
204.60 +* 2) if there is exactly one x[k] such that k in J+ and l[k] = -inf
204.61 +* or k in J- and u[k] = +inf, then
204.62 +*
204.63 +* f_min := sum a[j] * l[j] + sum a[j] * u[j]
204.64 +* j in J+\{k} j in J-\{k}
204.65 +* (4)
204.66 +* j_min := k
204.67 +*
204.68 +* 3) if there are two or more x[k] such that k in J+ and l[k] = -inf
204.69 +* or k in J- and u[k] = +inf, then
204.70 +*
204.71 +* f_min := -inf
204.72 +* (5)
204.73 +* j_min := 0
204.74 +*
204.75 +* Parameters f_max and j_max are computed in a similar way as follows:
204.76 +*
204.77 +* 1) if there is no x[k] such that k in J+ and u[k] = +inf or k in J-
204.78 +* and l[k] = -inf, then
204.79 +*
204.80 +* f_max := sum a[j] * u[j] + sum a[j] * l[j]
204.81 +* j in J+ j in J-
204.82 +* (6)
204.83 +* j_max := 0
204.84 +*
204.85 +* 2) if there is exactly one x[k] such that k in J+ and u[k] = +inf
204.86 +* or k in J- and l[k] = -inf, then
204.87 +*
204.88 +* f_max := sum a[j] * u[j] + sum a[j] * l[j]
204.89 +* j in J+\{k} j in J-\{k}
204.90 +* (7)
204.91 +* j_max := k
204.92 +*
204.93 +* 3) if there are two or more x[k] such that k in J+ and u[k] = +inf
204.94 +* or k in J- and l[k] = -inf, then
204.95 +*
204.96 +* f_max := +inf
204.97 +* (8)
204.98 +* j_max := 0 */
204.99 +
204.100 +struct f_info
204.101 +{ int j_min, j_max;
204.102 + double f_min, f_max;
204.103 +};
204.104 +
204.105 +static void prepare_row_info(int n, const double a[], const double l[],
204.106 + const double u[], struct f_info *f)
204.107 +{ int j, j_min, j_max;
204.108 + double f_min, f_max;
204.109 + xassert(n >= 0);
204.110 + /* determine f_min and j_min */
204.111 + f_min = 0.0, j_min = 0;
204.112 + for (j = 1; j <= n; j++)
204.113 + { if (a[j] > 0.0)
204.114 + { if (l[j] == -DBL_MAX)
204.115 + { if (j_min == 0)
204.116 + j_min = j;
204.117 + else
204.118 + { f_min = -DBL_MAX, j_min = 0;
204.119 + break;
204.120 + }
204.121 + }
204.122 + else
204.123 + f_min += a[j] * l[j];
204.124 + }
204.125 + else if (a[j] < 0.0)
204.126 + { if (u[j] == +DBL_MAX)
204.127 + { if (j_min == 0)
204.128 + j_min = j;
204.129 + else
204.130 + { f_min = -DBL_MAX, j_min = 0;
204.131 + break;
204.132 + }
204.133 + }
204.134 + else
204.135 + f_min += a[j] * u[j];
204.136 + }
204.137 + else
204.138 + xassert(a != a);
204.139 + }
204.140 + f->f_min = f_min, f->j_min = j_min;
204.141 + /* determine f_max and j_max */
204.142 + f_max = 0.0, j_max = 0;
204.143 + for (j = 1; j <= n; j++)
204.144 + { if (a[j] > 0.0)
204.145 + { if (u[j] == +DBL_MAX)
204.146 + { if (j_max == 0)
204.147 + j_max = j;
204.148 + else
204.149 + { f_max = +DBL_MAX, j_max = 0;
204.150 + break;
204.151 + }
204.152 + }
204.153 + else
204.154 + f_max += a[j] * u[j];
204.155 + }
204.156 + else if (a[j] < 0.0)
204.157 + { if (l[j] == -DBL_MAX)
204.158 + { if (j_max == 0)
204.159 + j_max = j;
204.160 + else
204.161 + { f_max = +DBL_MAX, j_max = 0;
204.162 + break;
204.163 + }
204.164 + }
204.165 + else
204.166 + f_max += a[j] * l[j];
204.167 + }
204.168 + else
204.169 + xassert(a != a);
204.170 + }
204.171 + f->f_max = f_max, f->j_max = j_max;
204.172 + return;
204.173 +}
204.174 +
204.175 +/***********************************************************************
204.176 +* row_implied_bounds - determine row implied bounds
204.177 +*
204.178 +* Given a row (linear form)
204.179 +*
204.180 +* n
204.181 +* sum a[j] * x[j]
204.182 +* j=1
204.183 +*
204.184 +* and bounds of columns (variables)
204.185 +*
204.186 +* l[j] <= x[j] <= u[j]
204.187 +*
204.188 +* this routine determines implied bounds of the row.
204.189 +*
204.190 +* ALGORITHM
204.191 +*
204.192 +* Let J+ = {j : a[j] > 0} and J- = {j : a[j] < 0}.
204.193 +*
204.194 +* The implied lower bound of the row is computed as follows:
204.195 +*
204.196 +* L' := sum a[j] * l[j] + sum a[j] * u[j] (9)
204.197 +* j in J+ j in J-
204.198 +*
204.199 +* and as it follows from (3), (4), and (5):
204.200 +*
204.201 +* L' := if j_min = 0 then f_min else -inf (10)
204.202 +*
204.203 +* The implied upper bound of the row is computed as follows:
204.204 +*
204.205 +* U' := sum a[j] * u[j] + sum a[j] * l[j] (11)
204.206 +* j in J+ j in J-
204.207 +*
204.208 +* and as it follows from (6), (7), and (8):
204.209 +*
204.210 +* U' := if j_max = 0 then f_max else +inf (12)
204.211 +*
204.212 +* The implied bounds are stored in locations LL and UU. */
204.213 +
204.214 +static void row_implied_bounds(const struct f_info *f, double *LL,
204.215 + double *UU)
204.216 +{ *LL = (f->j_min == 0 ? f->f_min : -DBL_MAX);
204.217 + *UU = (f->j_max == 0 ? f->f_max : +DBL_MAX);
204.218 + return;
204.219 +}
204.220 +
204.221 +/***********************************************************************
204.222 +* col_implied_bounds - determine column implied bounds
204.223 +*
204.224 +* Given a row (constraint)
204.225 +*
204.226 +* n
204.227 +* L <= sum a[j] * x[j] <= U (13)
204.228 +* j=1
204.229 +*
204.230 +* and bounds of columns (variables)
204.231 +*
204.232 +* l[j] <= x[j] <= u[j]
204.233 +*
204.234 +* this routine determines implied bounds of variable x[k].
204.235 +*
204.236 +* It is assumed that if L != -inf, the lower bound of the row can be
204.237 +* active, and if U != +inf, the upper bound of the row can be active.
204.238 +*
204.239 +* ALGORITHM
204.240 +*
204.241 +* From (13) it follows that
204.242 +*
204.243 +* L <= sum a[j] * x[j] + a[k] * x[k] <= U
204.244 +* j!=k
204.245 +* or
204.246 +*
204.247 +* L - sum a[j] * x[j] <= a[k] * x[k] <= U - sum a[j] * x[j]
204.248 +* j!=k j!=k
204.249 +*
204.250 +* Thus, if the row lower bound L can be active, implied lower bound of
204.251 +* term a[k] * x[k] can be determined as follows:
204.252 +*
204.253 +* ilb(a[k] * x[k]) = min(L - sum a[j] * x[j]) =
204.254 +* j!=k
204.255 +* (14)
204.256 +* = L - max sum a[j] * x[j]
204.257 +* j!=k
204.258 +*
204.259 +* where, as it follows from (6), (7), and (8)
204.260 +*
204.261 +* / f_max - a[k] * u[k], j_max = 0, a[k] > 0
204.262 +* |
204.263 +* | f_max - a[k] * l[k], j_max = 0, a[k] < 0
204.264 +* max sum a[j] * x[j] = {
204.265 +* j!=k | f_max, j_max = k
204.266 +* |
204.267 +* \ +inf, j_max != 0
204.268 +*
204.269 +* and if the upper bound U can be active, implied upper bound of term
204.270 +* a[k] * x[k] can be determined as follows:
204.271 +*
204.272 +* iub(a[k] * x[k]) = max(U - sum a[j] * x[j]) =
204.273 +* j!=k
204.274 +* (15)
204.275 +* = U - min sum a[j] * x[j]
204.276 +* j!=k
204.277 +*
204.278 +* where, as it follows from (3), (4), and (5)
204.279 +*
204.280 +* / f_min - a[k] * l[k], j_min = 0, a[k] > 0
204.281 +* |
204.282 +* | f_min - a[k] * u[k], j_min = 0, a[k] < 0
204.283 +* min sum a[j] * x[j] = {
204.284 +* j!=k | f_min, j_min = k
204.285 +* |
204.286 +* \ -inf, j_min != 0
204.287 +*
204.288 +* Since
204.289 +*
204.290 +* ilb(a[k] * x[k]) <= a[k] * x[k] <= iub(a[k] * x[k])
204.291 +*
204.292 +* implied lower and upper bounds of x[k] are determined as follows:
204.293 +*
204.294 +* l'[k] := if a[k] > 0 then ilb / a[k] else ulb / a[k] (16)
204.295 +*
204.296 +* u'[k] := if a[k] > 0 then ulb / a[k] else ilb / a[k] (17)
204.297 +*
204.298 +* The implied bounds are stored in locations ll and uu. */
204.299 +
204.300 +static void col_implied_bounds(const struct f_info *f, int n,
204.301 + const double a[], double L, double U, const double l[],
204.302 + const double u[], int k, double *ll, double *uu)
204.303 +{ double ilb, iub;
204.304 + xassert(n >= 0);
204.305 + xassert(1 <= k && k <= n);
204.306 + /* determine implied lower bound of term a[k] * x[k] (14) */
204.307 + if (L == -DBL_MAX || f->f_max == +DBL_MAX)
204.308 + ilb = -DBL_MAX;
204.309 + else if (f->j_max == 0)
204.310 + { if (a[k] > 0.0)
204.311 + { xassert(u[k] != +DBL_MAX);
204.312 + ilb = L - (f->f_max - a[k] * u[k]);
204.313 + }
204.314 + else if (a[k] < 0.0)
204.315 + { xassert(l[k] != -DBL_MAX);
204.316 + ilb = L - (f->f_max - a[k] * l[k]);
204.317 + }
204.318 + else
204.319 + xassert(a != a);
204.320 + }
204.321 + else if (f->j_max == k)
204.322 + ilb = L - f->f_max;
204.323 + else
204.324 + ilb = -DBL_MAX;
204.325 + /* determine implied upper bound of term a[k] * x[k] (15) */
204.326 + if (U == +DBL_MAX || f->f_min == -DBL_MAX)
204.327 + iub = +DBL_MAX;
204.328 + else if (f->j_min == 0)
204.329 + { if (a[k] > 0.0)
204.330 + { xassert(l[k] != -DBL_MAX);
204.331 + iub = U - (f->f_min - a[k] * l[k]);
204.332 + }
204.333 + else if (a[k] < 0.0)
204.334 + { xassert(u[k] != +DBL_MAX);
204.335 + iub = U - (f->f_min - a[k] * u[k]);
204.336 + }
204.337 + else
204.338 + xassert(a != a);
204.339 + }
204.340 + else if (f->j_min == k)
204.341 + iub = U - f->f_min;
204.342 + else
204.343 + iub = +DBL_MAX;
204.344 + /* determine implied bounds of x[k] (16) and (17) */
204.345 +#if 1
204.346 + /* do not use a[k] if it has small magnitude to prevent wrong
204.347 + implied bounds; for example, 1e-15 * x1 >= x2 + x3, where
204.348 + x1 >= -10, x2, x3 >= 0, would lead to wrong conclusion that
204.349 + x1 >= 0 */
204.350 + if (fabs(a[k]) < 1e-6)
204.351 + *ll = -DBL_MAX, *uu = +DBL_MAX; else
204.352 +#endif
204.353 + if (a[k] > 0.0)
204.354 + { *ll = (ilb == -DBL_MAX ? -DBL_MAX : ilb / a[k]);
204.355 + *uu = (iub == +DBL_MAX ? +DBL_MAX : iub / a[k]);
204.356 + }
204.357 + else if (a[k] < 0.0)
204.358 + { *ll = (iub == +DBL_MAX ? -DBL_MAX : iub / a[k]);
204.359 + *uu = (ilb == -DBL_MAX ? +DBL_MAX : ilb / a[k]);
204.360 + }
204.361 + else
204.362 + xassert(a != a);
204.363 + return;
204.364 +}
204.365 +
204.366 +/***********************************************************************
204.367 +* check_row_bounds - check and relax original row bounds
204.368 +*
204.369 +* Given a row (constraint)
204.370 +*
204.371 +* n
204.372 +* L <= sum a[j] * x[j] <= U
204.373 +* j=1
204.374 +*
204.375 +* and bounds of columns (variables)
204.376 +*
204.377 +* l[j] <= x[j] <= u[j]
204.378 +*
204.379 +* this routine checks the original row bounds L and U for feasibility
204.380 +* and redundancy. If the original lower bound L or/and upper bound U
204.381 +* cannot be active due to bounds of variables, the routine remove them
204.382 +* replacing by -inf or/and +inf, respectively.
204.383 +*
204.384 +* If no primal infeasibility is detected, the routine returns zero,
204.385 +* otherwise non-zero. */
204.386 +
204.387 +static int check_row_bounds(const struct f_info *f, double *L_,
204.388 + double *U_)
204.389 +{ int ret = 0;
204.390 + double L = *L_, U = *U_, LL, UU;
204.391 + /* determine implied bounds of the row */
204.392 + row_implied_bounds(f, &LL, &UU);
204.393 + /* check if the original lower bound is infeasible */
204.394 + if (L != -DBL_MAX)
204.395 + { double eps = 1e-3 * (1.0 + fabs(L));
204.396 + if (UU < L - eps)
204.397 + { ret = 1;
204.398 + goto done;
204.399 + }
204.400 + }
204.401 + /* check if the original upper bound is infeasible */
204.402 + if (U != +DBL_MAX)
204.403 + { double eps = 1e-3 * (1.0 + fabs(U));
204.404 + if (LL > U + eps)
204.405 + { ret = 1;
204.406 + goto done;
204.407 + }
204.408 + }
204.409 + /* check if the original lower bound is redundant */
204.410 + if (L != -DBL_MAX)
204.411 + { double eps = 1e-12 * (1.0 + fabs(L));
204.412 + if (LL > L - eps)
204.413 + { /* it cannot be active, so remove it */
204.414 + *L_ = -DBL_MAX;
204.415 + }
204.416 + }
204.417 + /* check if the original upper bound is redundant */
204.418 + if (U != +DBL_MAX)
204.419 + { double eps = 1e-12 * (1.0 + fabs(U));
204.420 + if (UU < U + eps)
204.421 + { /* it cannot be active, so remove it */
204.422 + *U_ = +DBL_MAX;
204.423 + }
204.424 + }
204.425 +done: return ret;
204.426 +}
204.427 +
204.428 +/***********************************************************************
204.429 +* check_col_bounds - check and tighten original column bounds
204.430 +*
204.431 +* Given a row (constraint)
204.432 +*
204.433 +* n
204.434 +* L <= sum a[j] * x[j] <= U
204.435 +* j=1
204.436 +*
204.437 +* and bounds of columns (variables)
204.438 +*
204.439 +* l[j] <= x[j] <= u[j]
204.440 +*
204.441 +* for column (variable) x[j] this routine checks the original column
204.442 +* bounds l[j] and u[j] for feasibility and redundancy. If the original
204.443 +* lower bound l[j] or/and upper bound u[j] cannot be active due to
204.444 +* bounds of the constraint and other variables, the routine tighten
204.445 +* them replacing by corresponding implied bounds, if possible.
204.446 +*
204.447 +* NOTE: It is assumed that if L != -inf, the row lower bound can be
204.448 +* active, and if U != +inf, the row upper bound can be active.
204.449 +*
204.450 +* The flag means that variable x[j] is required to be integer.
204.451 +*
204.452 +* New actual bounds for x[j] are stored in locations lj and uj.
204.453 +*
204.454 +* If no primal infeasibility is detected, the routine returns zero,
204.455 +* otherwise non-zero. */
204.456 +
204.457 +static int check_col_bounds(const struct f_info *f, int n,
204.458 + const double a[], double L, double U, const double l[],
204.459 + const double u[], int flag, int j, double *_lj, double *_uj)
204.460 +{ int ret = 0;
204.461 + double lj, uj, ll, uu;
204.462 + xassert(n >= 0);
204.463 + xassert(1 <= j && j <= n);
204.464 + lj = l[j], uj = u[j];
204.465 + /* determine implied bounds of the column */
204.466 + col_implied_bounds(f, n, a, L, U, l, u, j, &ll, &uu);
204.467 + /* if x[j] is integral, round its implied bounds */
204.468 + if (flag)
204.469 + { if (ll != -DBL_MAX)
204.470 + ll = (ll - floor(ll) < 1e-3 ? floor(ll) : ceil(ll));
204.471 + if (uu != +DBL_MAX)
204.472 + uu = (ceil(uu) - uu < 1e-3 ? ceil(uu) : floor(uu));
204.473 + }
204.474 + /* check if the original lower bound is infeasible */
204.475 + if (lj != -DBL_MAX)
204.476 + { double eps = 1e-3 * (1.0 + fabs(lj));
204.477 + if (uu < lj - eps)
204.478 + { ret = 1;
204.479 + goto done;
204.480 + }
204.481 + }
204.482 + /* check if the original upper bound is infeasible */
204.483 + if (uj != +DBL_MAX)
204.484 + { double eps = 1e-3 * (1.0 + fabs(uj));
204.485 + if (ll > uj + eps)
204.486 + { ret = 1;
204.487 + goto done;
204.488 + }
204.489 + }
204.490 + /* check if the original lower bound is redundant */
204.491 + if (ll != -DBL_MAX)
204.492 + { double eps = 1e-3 * (1.0 + fabs(ll));
204.493 + if (lj < ll - eps)
204.494 + { /* it cannot be active, so tighten it */
204.495 + lj = ll;
204.496 + }
204.497 + }
204.498 + /* check if the original upper bound is redundant */
204.499 + if (uu != +DBL_MAX)
204.500 + { double eps = 1e-3 * (1.0 + fabs(uu));
204.501 + if (uj > uu + eps)
204.502 + { /* it cannot be active, so tighten it */
204.503 + uj = uu;
204.504 + }
204.505 + }
204.506 + /* due to round-off errors it may happen that lj > uj (although
204.507 + lj < uj + eps, since no primal infeasibility is detected), so
204.508 + adjuct the new actual bounds to provide lj <= uj */
204.509 + if (!(lj == -DBL_MAX || uj == +DBL_MAX))
204.510 + { double t1 = fabs(lj), t2 = fabs(uj);
204.511 + double eps = 1e-10 * (1.0 + (t1 <= t2 ? t1 : t2));
204.512 + if (lj > uj - eps)
204.513 + { if (lj == l[j])
204.514 + uj = lj;
204.515 + else if (uj == u[j])
204.516 + lj = uj;
204.517 + else if (t1 <= t2)
204.518 + uj = lj;
204.519 + else
204.520 + lj = uj;
204.521 + }
204.522 + }
204.523 + *_lj = lj, *_uj = uj;
204.524 +done: return ret;
204.525 +}
204.526 +
204.527 +/***********************************************************************
204.528 +* check_efficiency - check if change in column bounds is efficient
204.529 +*
204.530 +* Given the original bounds of a column l and u and its new actual
204.531 +* bounds l' and u' (possibly tighten by the routine check_col_bounds)
204.532 +* this routine checks if the change in the column bounds is efficient
204.533 +* enough. If so, the routine returns non-zero, otherwise zero.
204.534 +*
204.535 +* The flag means that the variable is required to be integer. */
204.536 +
204.537 +static int check_efficiency(int flag, double l, double u, double ll,
204.538 + double uu)
204.539 +{ int eff = 0;
204.540 + /* check efficiency for lower bound */
204.541 + if (l < ll)
204.542 + { if (flag || l == -DBL_MAX)
204.543 + eff++;
204.544 + else
204.545 + { double r;
204.546 + if (u == +DBL_MAX)
204.547 + r = 1.0 + fabs(l);
204.548 + else
204.549 + r = 1.0 + (u - l);
204.550 + if (ll - l >= 0.25 * r)
204.551 + eff++;
204.552 + }
204.553 + }
204.554 + /* check efficiency for upper bound */
204.555 + if (u > uu)
204.556 + { if (flag || u == +DBL_MAX)
204.557 + eff++;
204.558 + else
204.559 + { double r;
204.560 + if (l == -DBL_MAX)
204.561 + r = 1.0 + fabs(u);
204.562 + else
204.563 + r = 1.0 + (u - l);
204.564 + if (u - uu >= 0.25 * r)
204.565 + eff++;
204.566 + }
204.567 + }
204.568 + return eff;
204.569 +}
204.570 +
204.571 +/***********************************************************************
204.572 +* basic_preprocessing - perform basic preprocessing
204.573 +*
204.574 +* This routine performs basic preprocessing of the specified MIP that
204.575 +* includes relaxing some row bounds and tightening some column bounds.
204.576 +*
204.577 +* On entry the arrays L and U contains original row bounds, and the
204.578 +* arrays l and u contains original column bounds:
204.579 +*
204.580 +* L[0] is the lower bound of the objective row;
204.581 +* L[i], i = 1,...,m, is the lower bound of i-th row;
204.582 +* U[0] is the upper bound of the objective row;
204.583 +* U[i], i = 1,...,m, is the upper bound of i-th row;
204.584 +* l[0] is not used;
204.585 +* l[j], j = 1,...,n, is the lower bound of j-th column;
204.586 +* u[0] is not used;
204.587 +* u[j], j = 1,...,n, is the upper bound of j-th column.
204.588 +*
204.589 +* On exit the arrays L, U, l, and u contain new actual bounds of rows
204.590 +* and column in the same locations.
204.591 +*
204.592 +* The parameters nrs and num specify an initial list of rows to be
204.593 +* processed:
204.594 +*
204.595 +* nrs is the number of rows in the initial list, 0 <= nrs <= m+1;
204.596 +* num[0] is not used;
204.597 +* num[1,...,nrs] are row numbers (0 means the objective row).
204.598 +*
204.599 +* The parameter max_pass specifies the maximal number of times that
204.600 +* each row can be processed, max_pass > 0.
204.601 +*
204.602 +* If no primal infeasibility is detected, the routine returns zero,
204.603 +* otherwise non-zero. */
204.604 +
204.605 +static int basic_preprocessing(glp_prob *mip, double L[], double U[],
204.606 + double l[], double u[], int nrs, const int num[], int max_pass)
204.607 +{ int m = mip->m;
204.608 + int n = mip->n;
204.609 + struct f_info f;
204.610 + int i, j, k, len, size, ret = 0;
204.611 + int *ind, *list, *mark, *pass;
204.612 + double *val, *lb, *ub;
204.613 + xassert(0 <= nrs && nrs <= m+1);
204.614 + xassert(max_pass > 0);
204.615 + /* allocate working arrays */
204.616 + ind = xcalloc(1+n, sizeof(int));
204.617 + list = xcalloc(1+m+1, sizeof(int));
204.618 + mark = xcalloc(1+m+1, sizeof(int));
204.619 + memset(&mark[0], 0, (m+1) * sizeof(int));
204.620 + pass = xcalloc(1+m+1, sizeof(int));
204.621 + memset(&pass[0], 0, (m+1) * sizeof(int));
204.622 + val = xcalloc(1+n, sizeof(double));
204.623 + lb = xcalloc(1+n, sizeof(double));
204.624 + ub = xcalloc(1+n, sizeof(double));
204.625 + /* initialize the list of rows to be processed */
204.626 + size = 0;
204.627 + for (k = 1; k <= nrs; k++)
204.628 + { i = num[k];
204.629 + xassert(0 <= i && i <= m);
204.630 + /* duplicate row numbers are not allowed */
204.631 + xassert(!mark[i]);
204.632 + list[++size] = i, mark[i] = 1;
204.633 + }
204.634 + xassert(size == nrs);
204.635 + /* process rows in the list until it becomes empty */
204.636 + while (size > 0)
204.637 + { /* get a next row from the list */
204.638 + i = list[size--], mark[i] = 0;
204.639 + /* increase the row processing count */
204.640 + pass[i]++;
204.641 + /* if the row is free, skip it */
204.642 + if (L[i] == -DBL_MAX && U[i] == +DBL_MAX) continue;
204.643 + /* obtain coefficients of the row */
204.644 + len = 0;
204.645 + if (i == 0)
204.646 + { for (j = 1; j <= n; j++)
204.647 + { GLPCOL *col = mip->col[j];
204.648 + if (col->coef != 0.0)
204.649 + len++, ind[len] = j, val[len] = col->coef;
204.650 + }
204.651 + }
204.652 + else
204.653 + { GLPROW *row = mip->row[i];
204.654 + GLPAIJ *aij;
204.655 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
204.656 + len++, ind[len] = aij->col->j, val[len] = aij->val;
204.657 + }
204.658 + /* determine lower and upper bounds of columns corresponding
204.659 + to non-zero row coefficients */
204.660 + for (k = 1; k <= len; k++)
204.661 + j = ind[k], lb[k] = l[j], ub[k] = u[j];
204.662 + /* prepare the row info to determine implied bounds */
204.663 + prepare_row_info(len, val, lb, ub, &f);
204.664 + /* check and relax bounds of the row */
204.665 + if (check_row_bounds(&f, &L[i], &U[i]))
204.666 + { /* the feasible region is empty */
204.667 + ret = 1;
204.668 + goto done;
204.669 + }
204.670 + /* if the row became free, drop it */
204.671 + if (L[i] == -DBL_MAX && U[i] == +DBL_MAX) continue;
204.672 + /* process columns having non-zero coefficients in the row */
204.673 + for (k = 1; k <= len; k++)
204.674 + { GLPCOL *col;
204.675 + int flag, eff;
204.676 + double ll, uu;
204.677 + /* take a next column in the row */
204.678 + j = ind[k], col = mip->col[j];
204.679 + flag = col->kind != GLP_CV;
204.680 + /* check and tighten bounds of the column */
204.681 + if (check_col_bounds(&f, len, val, L[i], U[i], lb, ub,
204.682 + flag, k, &ll, &uu))
204.683 + { /* the feasible region is empty */
204.684 + ret = 1;
204.685 + goto done;
204.686 + }
204.687 + /* check if change in the column bounds is efficient */
204.688 + eff = check_efficiency(flag, l[j], u[j], ll, uu);
204.689 + /* set new actual bounds of the column */
204.690 + l[j] = ll, u[j] = uu;
204.691 + /* if the change is efficient, add all rows affected by the
204.692 + corresponding column, to the list */
204.693 + if (eff > 0)
204.694 + { GLPAIJ *aij;
204.695 + for (aij = col->ptr; aij != NULL; aij = aij->c_next)
204.696 + { int ii = aij->row->i;
204.697 + /* if the row was processed maximal number of times,
204.698 + skip it */
204.699 + if (pass[ii] >= max_pass) continue;
204.700 + /* if the row is free, skip it */
204.701 + if (L[ii] == -DBL_MAX && U[ii] == +DBL_MAX) continue;
204.702 + /* put the row into the list */
204.703 + if (mark[ii] == 0)
204.704 + { xassert(size <= m);
204.705 + list[++size] = ii, mark[ii] = 1;
204.706 + }
204.707 + }
204.708 + }
204.709 + }
204.710 + }
204.711 +done: /* free working arrays */
204.712 + xfree(ind);
204.713 + xfree(list);
204.714 + xfree(mark);
204.715 + xfree(pass);
204.716 + xfree(val);
204.717 + xfree(lb);
204.718 + xfree(ub);
204.719 + return ret;
204.720 +}
204.721 +
204.722 +/***********************************************************************
204.723 +* NAME
204.724 +*
204.725 +* ios_preprocess_node - preprocess current subproblem
204.726 +*
204.727 +* SYNOPSIS
204.728 +*
204.729 +* #include "glpios.h"
204.730 +* int ios_preprocess_node(glp_tree *tree, int max_pass);
204.731 +*
204.732 +* DESCRIPTION
204.733 +*
204.734 +* The routine ios_preprocess_node performs basic preprocessing of the
204.735 +* current subproblem.
204.736 +*
204.737 +* RETURNS
204.738 +*
204.739 +* If no primal infeasibility is detected, the routine returns zero,
204.740 +* otherwise non-zero. */
204.741 +
204.742 +int ios_preprocess_node(glp_tree *tree, int max_pass)
204.743 +{ glp_prob *mip = tree->mip;
204.744 + int m = mip->m;
204.745 + int n = mip->n;
204.746 + int i, j, nrs, *num, ret = 0;
204.747 + double *L, *U, *l, *u;
204.748 + /* the current subproblem must exist */
204.749 + xassert(tree->curr != NULL);
204.750 + /* determine original row bounds */
204.751 + L = xcalloc(1+m, sizeof(double));
204.752 + U = xcalloc(1+m, sizeof(double));
204.753 + switch (mip->mip_stat)
204.754 + { case GLP_UNDEF:
204.755 + L[0] = -DBL_MAX, U[0] = +DBL_MAX;
204.756 + break;
204.757 + case GLP_FEAS:
204.758 + switch (mip->dir)
204.759 + { case GLP_MIN:
204.760 + L[0] = -DBL_MAX, U[0] = mip->mip_obj - mip->c0;
204.761 + break;
204.762 + case GLP_MAX:
204.763 + L[0] = mip->mip_obj - mip->c0, U[0] = +DBL_MAX;
204.764 + break;
204.765 + default:
204.766 + xassert(mip != mip);
204.767 + }
204.768 + break;
204.769 + default:
204.770 + xassert(mip != mip);
204.771 + }
204.772 + for (i = 1; i <= m; i++)
204.773 + { L[i] = glp_get_row_lb(mip, i);
204.774 + U[i] = glp_get_row_ub(mip, i);
204.775 + }
204.776 + /* determine original column bounds */
204.777 + l = xcalloc(1+n, sizeof(double));
204.778 + u = xcalloc(1+n, sizeof(double));
204.779 + for (j = 1; j <= n; j++)
204.780 + { l[j] = glp_get_col_lb(mip, j);
204.781 + u[j] = glp_get_col_ub(mip, j);
204.782 + }
204.783 + /* build the initial list of rows to be analyzed */
204.784 + nrs = m + 1;
204.785 + num = xcalloc(1+nrs, sizeof(int));
204.786 + for (i = 1; i <= nrs; i++) num[i] = i - 1;
204.787 + /* perform basic preprocessing */
204.788 + if (basic_preprocessing(mip , L, U, l, u, nrs, num, max_pass))
204.789 + { ret = 1;
204.790 + goto done;
204.791 + }
204.792 + /* set new actual (relaxed) row bounds */
204.793 + for (i = 1; i <= m; i++)
204.794 + { /* consider only non-active rows to keep dual feasibility */
204.795 + if (glp_get_row_stat(mip, i) == GLP_BS)
204.796 + { if (L[i] == -DBL_MAX && U[i] == +DBL_MAX)
204.797 + glp_set_row_bnds(mip, i, GLP_FR, 0.0, 0.0);
204.798 + else if (U[i] == +DBL_MAX)
204.799 + glp_set_row_bnds(mip, i, GLP_LO, L[i], 0.0);
204.800 + else if (L[i] == -DBL_MAX)
204.801 + glp_set_row_bnds(mip, i, GLP_UP, 0.0, U[i]);
204.802 + }
204.803 + }
204.804 + /* set new actual (tightened) column bounds */
204.805 + for (j = 1; j <= n; j++)
204.806 + { int type;
204.807 + if (l[j] == -DBL_MAX && u[j] == +DBL_MAX)
204.808 + type = GLP_FR;
204.809 + else if (u[j] == +DBL_MAX)
204.810 + type = GLP_LO;
204.811 + else if (l[j] == -DBL_MAX)
204.812 + type = GLP_UP;
204.813 + else if (l[j] != u[j])
204.814 + type = GLP_DB;
204.815 + else
204.816 + type = GLP_FX;
204.817 + glp_set_col_bnds(mip, j, type, l[j], u[j]);
204.818 + }
204.819 +done: /* free working arrays and return */
204.820 + xfree(L);
204.821 + xfree(U);
204.822 + xfree(l);
204.823 + xfree(u);
204.824 + xfree(num);
204.825 + return ret;
204.826 +}
204.827 +
204.828 +/* eof */
205.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
205.2 +++ b/src/glpios03.c Mon Dec 06 13:09:21 2010 +0100
205.3 @@ -0,0 +1,1155 @@
205.4 +/* glpios03.c (branch-and-cut driver) */
205.5 +
205.6 +/***********************************************************************
205.7 +* This code is part of GLPK (GNU Linear Programming Kit).
205.8 +*
205.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
205.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
205.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
205.12 +* E-mail: <mao@gnu.org>.
205.13 +*
205.14 +* GLPK is free software: you can redistribute it and/or modify it
205.15 +* under the terms of the GNU General Public License as published by
205.16 +* the Free Software Foundation, either version 3 of the License, or
205.17 +* (at your option) any later version.
205.18 +*
205.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
205.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
205.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
205.22 +* License for more details.
205.23 +*
205.24 +* You should have received a copy of the GNU General Public License
205.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
205.26 +***********************************************************************/
205.27 +
205.28 +#include "glpios.h"
205.29 +
205.30 +/***********************************************************************
205.31 +* show_progress - display current progress of the search
205.32 +*
205.33 +* This routine displays some information about current progress of the
205.34 +* search.
205.35 +*
205.36 +* The information includes:
205.37 +*
205.38 +* the current number of iterations performed by the simplex solver;
205.39 +*
205.40 +* the objective value for the best known integer feasible solution,
205.41 +* which is upper (minimization) or lower (maximization) global bound
205.42 +* for optimal solution of the original mip problem;
205.43 +*
205.44 +* the best local bound for active nodes, which is lower (minimization)
205.45 +* or upper (maximization) global bound for optimal solution of the
205.46 +* original mip problem;
205.47 +*
205.48 +* the relative mip gap, in percents;
205.49 +*
205.50 +* the number of open (active) subproblems;
205.51 +*
205.52 +* the number of completely explored subproblems, i.e. whose nodes have
205.53 +* been removed from the tree. */
205.54 +
205.55 +static void show_progress(glp_tree *T, int bingo)
205.56 +{ int p;
205.57 + double temp;
205.58 + char best_mip[50], best_bound[50], *rho, rel_gap[50];
205.59 + /* format the best known integer feasible solution */
205.60 + if (T->mip->mip_stat == GLP_FEAS)
205.61 + sprintf(best_mip, "%17.9e", T->mip->mip_obj);
205.62 + else
205.63 + sprintf(best_mip, "%17s", "not found yet");
205.64 + /* determine reference number of an active subproblem whose local
205.65 + bound is best */
205.66 + p = ios_best_node(T);
205.67 + /* format the best bound */
205.68 + if (p == 0)
205.69 + sprintf(best_bound, "%17s", "tree is empty");
205.70 + else
205.71 + { temp = T->slot[p].node->bound;
205.72 + if (temp == -DBL_MAX)
205.73 + sprintf(best_bound, "%17s", "-inf");
205.74 + else if (temp == +DBL_MAX)
205.75 + sprintf(best_bound, "%17s", "+inf");
205.76 + else
205.77 + sprintf(best_bound, "%17.9e", temp);
205.78 + }
205.79 + /* choose the relation sign between global bounds */
205.80 + if (T->mip->dir == GLP_MIN)
205.81 + rho = ">=";
205.82 + else if (T->mip->dir == GLP_MAX)
205.83 + rho = "<=";
205.84 + else
205.85 + xassert(T != T);
205.86 + /* format the relative mip gap */
205.87 + temp = ios_relative_gap(T);
205.88 + if (temp == 0.0)
205.89 + sprintf(rel_gap, " 0.0%%");
205.90 + else if (temp < 0.001)
205.91 + sprintf(rel_gap, "< 0.1%%");
205.92 + else if (temp <= 9.999)
205.93 + sprintf(rel_gap, "%5.1f%%", 100.0 * temp);
205.94 + else
205.95 + sprintf(rel_gap, "%6s", "");
205.96 + /* display progress of the search */
205.97 + xprintf("+%6d: %s %s %s %s %s (%d; %d)\n",
205.98 + T->mip->it_cnt, bingo ? ">>>>>" : "mip =", best_mip, rho,
205.99 + best_bound, rel_gap, T->a_cnt, T->t_cnt - T->n_cnt);
205.100 + T->tm_lag = xtime();
205.101 + return;
205.102 +}
205.103 +
205.104 +/***********************************************************************
205.105 +* is_branch_hopeful - check if specified branch is hopeful
205.106 +*
205.107 +* This routine checks if the specified subproblem can have an integer
205.108 +* optimal solution which is better than the best known one.
205.109 +*
205.110 +* The check is based on comparison of the local objective bound stored
205.111 +* in the subproblem descriptor and the incumbent objective value which
205.112 +* is the global objective bound.
205.113 +*
205.114 +* If there is a chance that the specified subproblem can have a better
205.115 +* integer optimal solution, the routine returns non-zero. Otherwise, if
205.116 +* the corresponding branch can pruned, zero is returned. */
205.117 +
205.118 +static int is_branch_hopeful(glp_tree *T, int p)
205.119 +{ xassert(1 <= p && p <= T->nslots);
205.120 + xassert(T->slot[p].node != NULL);
205.121 + return ios_is_hopeful(T, T->slot[p].node->bound);
205.122 +}
205.123 +
205.124 +/***********************************************************************
205.125 +* check_integrality - check integrality of basic solution
205.126 +*
205.127 +* This routine checks if the basic solution of LP relaxation of the
205.128 +* current subproblem satisfies to integrality conditions, i.e. that all
205.129 +* variables of integer kind have integral primal values. (The solution
205.130 +* is assumed to be optimal.)
205.131 +*
205.132 +* For each variable of integer kind the routine computes the following
205.133 +* quantity:
205.134 +*
205.135 +* ii(x[j]) = min(x[j] - floor(x[j]), ceil(x[j]) - x[j]), (1)
205.136 +*
205.137 +* which is a measure of the integer infeasibility (non-integrality) of
205.138 +* x[j] (for example, ii(2.1) = 0.1, ii(3.7) = 0.3, ii(5.0) = 0). It is
205.139 +* understood that 0 <= ii(x[j]) <= 0.5, and variable x[j] is integer
205.140 +* feasible if ii(x[j]) = 0. However, due to floating-point arithmetic
205.141 +* the routine checks less restrictive condition:
205.142 +*
205.143 +* ii(x[j]) <= tol_int, (2)
205.144 +*
205.145 +* where tol_int is a given tolerance (small positive number) and marks
205.146 +* each variable which does not satisfy to (2) as integer infeasible by
205.147 +* setting its fractionality flag.
205.148 +*
205.149 +* In order to characterize integer infeasibility of the basic solution
205.150 +* in the whole the routine computes two parameters: ii_cnt, which is
205.151 +* the number of variables with the fractionality flag set, and ii_sum,
205.152 +* which is the sum of integer infeasibilities (1). */
205.153 +
205.154 +static void check_integrality(glp_tree *T)
205.155 +{ glp_prob *mip = T->mip;
205.156 + int j, type, ii_cnt = 0;
205.157 + double lb, ub, x, temp1, temp2, ii_sum = 0.0;
205.158 + /* walk through the set of columns (structural variables) */
205.159 + for (j = 1; j <= mip->n; j++)
205.160 + { GLPCOL *col = mip->col[j];
205.161 + T->non_int[j] = 0;
205.162 + /* if the column is not integer, skip it */
205.163 + if (col->kind != GLP_IV) continue;
205.164 + /* if the column is non-basic, it is integer feasible */
205.165 + if (col->stat != GLP_BS) continue;
205.166 + /* obtain the type and bounds of the column */
205.167 + type = col->type, lb = col->lb, ub = col->ub;
205.168 + /* obtain value of the column in optimal basic solution */
205.169 + x = col->prim;
205.170 + /* if the column's primal value is close to the lower bound,
205.171 + the column is integer feasible within given tolerance */
205.172 + if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
205.173 + { temp1 = lb - T->parm->tol_int;
205.174 + temp2 = lb + T->parm->tol_int;
205.175 + if (temp1 <= x && x <= temp2) continue;
205.176 +#if 0
205.177 + /* the lower bound must not be violated */
205.178 + xassert(x >= lb);
205.179 +#else
205.180 + if (x < lb) continue;
205.181 +#endif
205.182 + }
205.183 + /* if the column's primal value is close to the upper bound,
205.184 + the column is integer feasible within given tolerance */
205.185 + if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
205.186 + { temp1 = ub - T->parm->tol_int;
205.187 + temp2 = ub + T->parm->tol_int;
205.188 + if (temp1 <= x && x <= temp2) continue;
205.189 +#if 0
205.190 + /* the upper bound must not be violated */
205.191 + xassert(x <= ub);
205.192 +#else
205.193 + if (x > ub) continue;
205.194 +#endif
205.195 + }
205.196 + /* if the column's primal value is close to nearest integer,
205.197 + the column is integer feasible within given tolerance */
205.198 + temp1 = floor(x + 0.5) - T->parm->tol_int;
205.199 + temp2 = floor(x + 0.5) + T->parm->tol_int;
205.200 + if (temp1 <= x && x <= temp2) continue;
205.201 + /* otherwise the column is integer infeasible */
205.202 + T->non_int[j] = 1;
205.203 + /* increase the number of fractional-valued columns */
205.204 + ii_cnt++;
205.205 + /* compute the sum of integer infeasibilities */
205.206 + temp1 = x - floor(x);
205.207 + temp2 = ceil(x) - x;
205.208 + xassert(temp1 > 0.0 && temp2 > 0.0);
205.209 + ii_sum += (temp1 <= temp2 ? temp1 : temp2);
205.210 + }
205.211 + /* store ii_cnt and ii_sum to the current problem descriptor */
205.212 + xassert(T->curr != NULL);
205.213 + T->curr->ii_cnt = ii_cnt;
205.214 + T->curr->ii_sum = ii_sum;
205.215 + /* and also display these parameters */
205.216 + if (T->parm->msg_lev >= GLP_MSG_DBG)
205.217 + { if (ii_cnt == 0)
205.218 + xprintf("There are no fractional columns\n");
205.219 + else if (ii_cnt == 1)
205.220 + xprintf("There is one fractional column, integer infeasibil"
205.221 + "ity is %.3e\n", ii_sum);
205.222 + else
205.223 + xprintf("There are %d fractional columns, integer infeasibi"
205.224 + "lity is %.3e\n", ii_cnt, ii_sum);
205.225 + }
205.226 + return;
205.227 +}
205.228 +
205.229 +/***********************************************************************
205.230 +* record_solution - record better integer feasible solution
205.231 +*
205.232 +* This routine records optimal basic solution of LP relaxation of the
205.233 +* current subproblem, which being integer feasible is better than the
205.234 +* best known integer feasible solution. */
205.235 +
205.236 +static void record_solution(glp_tree *T)
205.237 +{ glp_prob *mip = T->mip;
205.238 + int i, j;
205.239 + mip->mip_stat = GLP_FEAS;
205.240 + mip->mip_obj = mip->obj_val;
205.241 + for (i = 1; i <= mip->m; i++)
205.242 + { GLPROW *row = mip->row[i];
205.243 + row->mipx = row->prim;
205.244 + }
205.245 + for (j = 1; j <= mip->n; j++)
205.246 + { GLPCOL *col = mip->col[j];
205.247 + if (col->kind == GLP_CV)
205.248 + col->mipx = col->prim;
205.249 + else if (col->kind == GLP_IV)
205.250 + { /* value of the integer column must be integral */
205.251 + col->mipx = floor(col->prim + 0.5);
205.252 + }
205.253 + else
205.254 + xassert(col != col);
205.255 + }
205.256 + T->sol_cnt++;
205.257 + return;
205.258 +}
205.259 +
205.260 +/***********************************************************************
205.261 +* fix_by_red_cost - fix non-basic integer columns by reduced costs
205.262 +*
205.263 +* This routine fixes some non-basic integer columns if their reduced
205.264 +* costs indicate that increasing (decreasing) the column at least by
205.265 +* one involves the objective value becoming worse than the incumbent
205.266 +* objective value. */
205.267 +
205.268 +static void fix_by_red_cost(glp_tree *T)
205.269 +{ glp_prob *mip = T->mip;
205.270 + int j, stat, fixed = 0;
205.271 + double obj, lb, ub, dj;
205.272 + /* the global bound must exist */
205.273 + xassert(T->mip->mip_stat == GLP_FEAS);
205.274 + /* basic solution of LP relaxation must be optimal */
205.275 + xassert(mip->pbs_stat == GLP_FEAS && mip->dbs_stat == GLP_FEAS);
205.276 + /* determine the objective function value */
205.277 + obj = mip->obj_val;
205.278 + /* walk through the column list */
205.279 + for (j = 1; j <= mip->n; j++)
205.280 + { GLPCOL *col = mip->col[j];
205.281 + /* if the column is not integer, skip it */
205.282 + if (col->kind != GLP_IV) continue;
205.283 + /* obtain bounds of j-th column */
205.284 + lb = col->lb, ub = col->ub;
205.285 + /* and determine its status and reduced cost */
205.286 + stat = col->stat, dj = col->dual;
205.287 + /* analyze the reduced cost */
205.288 + switch (mip->dir)
205.289 + { case GLP_MIN:
205.290 + /* minimization */
205.291 + if (stat == GLP_NL)
205.292 + { /* j-th column is non-basic on its lower bound */
205.293 + if (dj < 0.0) dj = 0.0;
205.294 + if (obj + dj >= mip->mip_obj)
205.295 + glp_set_col_bnds(mip, j, GLP_FX, lb, lb), fixed++;
205.296 + }
205.297 + else if (stat == GLP_NU)
205.298 + { /* j-th column is non-basic on its upper bound */
205.299 + if (dj > 0.0) dj = 0.0;
205.300 + if (obj - dj >= mip->mip_obj)
205.301 + glp_set_col_bnds(mip, j, GLP_FX, ub, ub), fixed++;
205.302 + }
205.303 + break;
205.304 + case GLP_MAX:
205.305 + /* maximization */
205.306 + if (stat == GLP_NL)
205.307 + { /* j-th column is non-basic on its lower bound */
205.308 + if (dj > 0.0) dj = 0.0;
205.309 + if (obj + dj <= mip->mip_obj)
205.310 + glp_set_col_bnds(mip, j, GLP_FX, lb, lb), fixed++;
205.311 + }
205.312 + else if (stat == GLP_NU)
205.313 + { /* j-th column is non-basic on its upper bound */
205.314 + if (dj < 0.0) dj = 0.0;
205.315 + if (obj - dj <= mip->mip_obj)
205.316 + glp_set_col_bnds(mip, j, GLP_FX, ub, ub), fixed++;
205.317 + }
205.318 + break;
205.319 + default:
205.320 + xassert(T != T);
205.321 + }
205.322 + }
205.323 + if (T->parm->msg_lev >= GLP_MSG_DBG)
205.324 + { if (fixed == 0)
205.325 + /* nothing to say */;
205.326 + else if (fixed == 1)
205.327 + xprintf("One column has been fixed by reduced cost\n");
205.328 + else
205.329 + xprintf("%d columns have been fixed by reduced costs\n",
205.330 + fixed);
205.331 + }
205.332 + /* fixing non-basic columns on their current bounds does not
205.333 + change the basic solution */
205.334 + xassert(mip->pbs_stat == GLP_FEAS && mip->dbs_stat == GLP_FEAS);
205.335 + return;
205.336 +}
205.337 +
205.338 +/***********************************************************************
205.339 +* branch_on - perform branching on specified variable
205.340 +*
205.341 +* This routine performs branching on j-th column (structural variable)
205.342 +* of the current subproblem. The specified column must be of integer
205.343 +* kind and must have a fractional value in optimal basic solution of
205.344 +* LP relaxation of the current subproblem (i.e. only columns for which
205.345 +* the flag non_int[j] is set are valid candidates to branch on).
205.346 +*
205.347 +* Let x be j-th structural variable, and beta be its primal fractional
205.348 +* value in the current basic solution. Branching on j-th variable is
205.349 +* dividing the current subproblem into two new subproblems, which are
205.350 +* identical to the current subproblem with the following exception: in
205.351 +* the first subproblem that begins the down-branch x has a new upper
205.352 +* bound x <= floor(beta), and in the second subproblem that begins the
205.353 +* up-branch x has a new lower bound x >= ceil(beta).
205.354 +*
205.355 +* Depending on estimation of local bounds for down- and up-branches
205.356 +* this routine returns the following:
205.357 +*
205.358 +* 0 - both branches have been created;
205.359 +* 1 - one branch is hopeless and has been pruned, so now the current
205.360 +* subproblem is other branch;
205.361 +* 2 - both branches are hopeless and have been pruned; new subproblem
205.362 +* selection is needed to continue the search. */
205.363 +
205.364 +static int branch_on(glp_tree *T, int j, int next)
205.365 +{ glp_prob *mip = T->mip;
205.366 + IOSNPD *node;
205.367 + int m = mip->m;
205.368 + int n = mip->n;
205.369 + int type, dn_type, up_type, dn_bad, up_bad, p, ret, clone[1+2];
205.370 + double lb, ub, beta, new_ub, new_lb, dn_lp, up_lp, dn_bnd, up_bnd;
205.371 + /* determine bounds and value of x[j] in optimal solution to LP
205.372 + relaxation of the current subproblem */
205.373 + xassert(1 <= j && j <= n);
205.374 + type = mip->col[j]->type;
205.375 + lb = mip->col[j]->lb;
205.376 + ub = mip->col[j]->ub;
205.377 + beta = mip->col[j]->prim;
205.378 + /* determine new bounds of x[j] for down- and up-branches */
205.379 + new_ub = floor(beta);
205.380 + new_lb = ceil(beta);
205.381 + switch (type)
205.382 + { case GLP_FR:
205.383 + dn_type = GLP_UP;
205.384 + up_type = GLP_LO;
205.385 + break;
205.386 + case GLP_LO:
205.387 + xassert(lb <= new_ub);
205.388 + dn_type = (lb == new_ub ? GLP_FX : GLP_DB);
205.389 + xassert(lb + 1.0 <= new_lb);
205.390 + up_type = GLP_LO;
205.391 + break;
205.392 + case GLP_UP:
205.393 + xassert(new_ub <= ub - 1.0);
205.394 + dn_type = GLP_UP;
205.395 + xassert(new_lb <= ub);
205.396 + up_type = (new_lb == ub ? GLP_FX : GLP_DB);
205.397 + break;
205.398 + case GLP_DB:
205.399 + xassert(lb <= new_ub && new_ub <= ub - 1.0);
205.400 + dn_type = (lb == new_ub ? GLP_FX : GLP_DB);
205.401 + xassert(lb + 1.0 <= new_lb && new_lb <= ub);
205.402 + up_type = (new_lb == ub ? GLP_FX : GLP_DB);
205.403 + break;
205.404 + default:
205.405 + xassert(type != type);
205.406 + }
205.407 + /* compute local bounds to LP relaxation for both branches */
205.408 + ios_eval_degrad(T, j, &dn_lp, &up_lp);
205.409 + /* and improve them by rounding */
205.410 + dn_bnd = ios_round_bound(T, dn_lp);
205.411 + up_bnd = ios_round_bound(T, up_lp);
205.412 + /* check local bounds for down- and up-branches */
205.413 + dn_bad = !ios_is_hopeful(T, dn_bnd);
205.414 + up_bad = !ios_is_hopeful(T, up_bnd);
205.415 + if (dn_bad && up_bad)
205.416 + { if (T->parm->msg_lev >= GLP_MSG_DBG)
205.417 + xprintf("Both down- and up-branches are hopeless\n");
205.418 + ret = 2;
205.419 + goto done;
205.420 + }
205.421 + else if (up_bad)
205.422 + { if (T->parm->msg_lev >= GLP_MSG_DBG)
205.423 + xprintf("Up-branch is hopeless\n");
205.424 + glp_set_col_bnds(mip, j, dn_type, lb, new_ub);
205.425 + T->curr->lp_obj = dn_lp;
205.426 + if (mip->dir == GLP_MIN)
205.427 + { if (T->curr->bound < dn_bnd)
205.428 + T->curr->bound = dn_bnd;
205.429 + }
205.430 + else if (mip->dir == GLP_MAX)
205.431 + { if (T->curr->bound > dn_bnd)
205.432 + T->curr->bound = dn_bnd;
205.433 + }
205.434 + else
205.435 + xassert(mip != mip);
205.436 + ret = 1;
205.437 + goto done;
205.438 + }
205.439 + else if (dn_bad)
205.440 + { if (T->parm->msg_lev >= GLP_MSG_DBG)
205.441 + xprintf("Down-branch is hopeless\n");
205.442 + glp_set_col_bnds(mip, j, up_type, new_lb, ub);
205.443 + T->curr->lp_obj = up_lp;
205.444 + if (mip->dir == GLP_MIN)
205.445 + { if (T->curr->bound < up_bnd)
205.446 + T->curr->bound = up_bnd;
205.447 + }
205.448 + else if (mip->dir == GLP_MAX)
205.449 + { if (T->curr->bound > up_bnd)
205.450 + T->curr->bound = up_bnd;
205.451 + }
205.452 + else
205.453 + xassert(mip != mip);
205.454 + ret = 1;
205.455 + goto done;
205.456 + }
205.457 + /* both down- and up-branches seem to be hopeful */
205.458 + if (T->parm->msg_lev >= GLP_MSG_DBG)
205.459 + xprintf("Branching on column %d, primal value is %.9e\n",
205.460 + j, beta);
205.461 + /* determine the reference number of the current subproblem */
205.462 + xassert(T->curr != NULL);
205.463 + p = T->curr->p;
205.464 + T->curr->br_var = j;
205.465 + T->curr->br_val = beta;
205.466 + /* freeze the current subproblem */
205.467 + ios_freeze_node(T);
205.468 + /* create two clones of the current subproblem; the first clone
205.469 + begins the down-branch, the second one begins the up-branch */
205.470 + ios_clone_node(T, p, 2, clone);
205.471 + if (T->parm->msg_lev >= GLP_MSG_DBG)
205.472 + xprintf("Node %d begins down branch, node %d begins up branch "
205.473 + "\n", clone[1], clone[2]);
205.474 + /* set new upper bound of j-th column in the down-branch */
205.475 + node = T->slot[clone[1]].node;
205.476 + xassert(node != NULL);
205.477 + xassert(node->up != NULL);
205.478 + xassert(node->b_ptr == NULL);
205.479 + node->b_ptr = dmp_get_atom(T->pool, sizeof(IOSBND));
205.480 + node->b_ptr->k = m + j;
205.481 + node->b_ptr->type = (unsigned char)dn_type;
205.482 + node->b_ptr->lb = lb;
205.483 + node->b_ptr->ub = new_ub;
205.484 + node->b_ptr->next = NULL;
205.485 + node->lp_obj = dn_lp;
205.486 + if (mip->dir == GLP_MIN)
205.487 + { if (node->bound < dn_bnd)
205.488 + node->bound = dn_bnd;
205.489 + }
205.490 + else if (mip->dir == GLP_MAX)
205.491 + { if (node->bound > dn_bnd)
205.492 + node->bound = dn_bnd;
205.493 + }
205.494 + else
205.495 + xassert(mip != mip);
205.496 + /* set new lower bound of j-th column in the up-branch */
205.497 + node = T->slot[clone[2]].node;
205.498 + xassert(node != NULL);
205.499 + xassert(node->up != NULL);
205.500 + xassert(node->b_ptr == NULL);
205.501 + node->b_ptr = dmp_get_atom(T->pool, sizeof(IOSBND));
205.502 + node->b_ptr->k = m + j;
205.503 + node->b_ptr->type = (unsigned char)up_type;
205.504 + node->b_ptr->lb = new_lb;
205.505 + node->b_ptr->ub = ub;
205.506 + node->b_ptr->next = NULL;
205.507 + node->lp_obj = up_lp;
205.508 + if (mip->dir == GLP_MIN)
205.509 + { if (node->bound < up_bnd)
205.510 + node->bound = up_bnd;
205.511 + }
205.512 + else if (mip->dir == GLP_MAX)
205.513 + { if (node->bound > up_bnd)
205.514 + node->bound = up_bnd;
205.515 + }
205.516 + else
205.517 + xassert(mip != mip);
205.518 + /* suggest the subproblem to be solved next */
205.519 + xassert(T->child == 0);
205.520 + if (next == GLP_NO_BRNCH)
205.521 + T->child = 0;
205.522 + else if (next == GLP_DN_BRNCH)
205.523 + T->child = clone[1];
205.524 + else if (next == GLP_UP_BRNCH)
205.525 + T->child = clone[2];
205.526 + else
205.527 + xassert(next != next);
205.528 + ret = 0;
205.529 +done: return ret;
205.530 +}
205.531 +
205.532 +/***********************************************************************
205.533 +* cleanup_the_tree - prune hopeless branches from the tree
205.534 +*
205.535 +* This routine walks through the active list and checks the local
205.536 +* bound for every active subproblem. If the local bound indicates that
205.537 +* the subproblem cannot have integer optimal solution better than the
205.538 +* incumbent objective value, the routine deletes such subproblem that,
205.539 +* in turn, involves pruning the corresponding branch of the tree. */
205.540 +
205.541 +static void cleanup_the_tree(glp_tree *T)
205.542 +{ IOSNPD *node, *next_node;
205.543 + int count = 0;
205.544 + /* the global bound must exist */
205.545 + xassert(T->mip->mip_stat == GLP_FEAS);
205.546 + /* walk through the list of active subproblems */
205.547 + for (node = T->head; node != NULL; node = next_node)
205.548 + { /* deleting some active problem node may involve deleting its
205.549 + parents recursively; however, all its parents being created
205.550 + *before* it are always *precede* it in the node list, so
205.551 + the next problem node is never affected by such deletion */
205.552 + next_node = node->next;
205.553 + /* if the branch is hopeless, prune it */
205.554 + if (!is_branch_hopeful(T, node->p))
205.555 + ios_delete_node(T, node->p), count++;
205.556 + }
205.557 + if (T->parm->msg_lev >= GLP_MSG_DBG)
205.558 + { if (count == 1)
205.559 + xprintf("One hopeless branch has been pruned\n");
205.560 + else if (count > 1)
205.561 + xprintf("%d hopeless branches have been pruned\n", count);
205.562 + }
205.563 + return;
205.564 +}
205.565 +
205.566 +/**********************************************************************/
205.567 +
205.568 +static void generate_cuts(glp_tree *T)
205.569 +{ /* generate generic cuts with built-in generators */
205.570 + if (!(T->parm->mir_cuts == GLP_ON ||
205.571 + T->parm->gmi_cuts == GLP_ON ||
205.572 + T->parm->cov_cuts == GLP_ON ||
205.573 + T->parm->clq_cuts == GLP_ON)) goto done;
205.574 +#if 1 /* 20/IX-2008 */
205.575 + { int i, max_cuts, added_cuts;
205.576 + max_cuts = T->n;
205.577 + if (max_cuts < 1000) max_cuts = 1000;
205.578 + added_cuts = 0;
205.579 + for (i = T->orig_m+1; i <= T->mip->m; i++)
205.580 + { if (T->mip->row[i]->origin == GLP_RF_CUT)
205.581 + added_cuts++;
205.582 + }
205.583 + /* xprintf("added_cuts = %d\n", added_cuts); */
205.584 + if (added_cuts >= max_cuts) goto done;
205.585 + }
205.586 +#endif
205.587 + /* generate and add to POOL all cuts violated by x* */
205.588 + if (T->parm->gmi_cuts == GLP_ON)
205.589 + { if (T->curr->changed < 5)
205.590 + ios_gmi_gen(T);
205.591 + }
205.592 + if (T->parm->mir_cuts == GLP_ON)
205.593 + { xassert(T->mir_gen != NULL);
205.594 + ios_mir_gen(T, T->mir_gen);
205.595 + }
205.596 + if (T->parm->cov_cuts == GLP_ON)
205.597 + { /* cover cuts works well along with mir cuts */
205.598 + /*if (T->round <= 5)*/
205.599 + ios_cov_gen(T);
205.600 + }
205.601 + if (T->parm->clq_cuts == GLP_ON)
205.602 + { if (T->clq_gen != NULL)
205.603 + { if (T->curr->level == 0 && T->curr->changed < 50 ||
205.604 + T->curr->level > 0 && T->curr->changed < 5)
205.605 + ios_clq_gen(T, T->clq_gen);
205.606 + }
205.607 + }
205.608 +done: return;
205.609 +}
205.610 +
205.611 +/**********************************************************************/
205.612 +
205.613 +static void remove_cuts(glp_tree *T)
205.614 +{ /* remove inactive cuts (some valueable globally valid cut might
205.615 + be saved in the global cut pool) */
205.616 + int i, cnt = 0, *num = NULL;
205.617 + xassert(T->curr != NULL);
205.618 + for (i = T->orig_m+1; i <= T->mip->m; i++)
205.619 + { if (T->mip->row[i]->origin == GLP_RF_CUT &&
205.620 + T->mip->row[i]->level == T->curr->level &&
205.621 + T->mip->row[i]->stat == GLP_BS)
205.622 + { if (num == NULL)
205.623 + num = xcalloc(1+T->mip->m, sizeof(int));
205.624 + num[++cnt] = i;
205.625 + }
205.626 + }
205.627 + if (cnt > 0)
205.628 + { glp_del_rows(T->mip, cnt, num);
205.629 +#if 0
205.630 + xprintf("%d inactive cut(s) removed\n", cnt);
205.631 +#endif
205.632 + xfree(num);
205.633 + xassert(glp_factorize(T->mip) == 0);
205.634 + }
205.635 + return;
205.636 +}
205.637 +
205.638 +/**********************************************************************/
205.639 +
205.640 +static void display_cut_info(glp_tree *T)
205.641 +{ glp_prob *mip = T->mip;
205.642 + int i, gmi = 0, mir = 0, cov = 0, clq = 0, app = 0;
205.643 + for (i = mip->m; i > 0; i--)
205.644 + { GLPROW *row;
205.645 + row = mip->row[i];
205.646 + /* if (row->level < T->curr->level) break; */
205.647 + if (row->origin == GLP_RF_CUT)
205.648 + { if (row->klass == GLP_RF_GMI)
205.649 + gmi++;
205.650 + else if (row->klass == GLP_RF_MIR)
205.651 + mir++;
205.652 + else if (row->klass == GLP_RF_COV)
205.653 + cov++;
205.654 + else if (row->klass == GLP_RF_CLQ)
205.655 + clq++;
205.656 + else
205.657 + app++;
205.658 + }
205.659 + }
205.660 + xassert(T->curr != NULL);
205.661 + if (gmi + mir + cov + clq + app > 0)
205.662 + { xprintf("Cuts on level %d:", T->curr->level);
205.663 + if (gmi > 0) xprintf(" gmi = %d;", gmi);
205.664 + if (mir > 0) xprintf(" mir = %d;", mir);
205.665 + if (cov > 0) xprintf(" cov = %d;", cov);
205.666 + if (clq > 0) xprintf(" clq = %d;", clq);
205.667 + if (app > 0) xprintf(" app = %d;", app);
205.668 + xprintf("\n");
205.669 + }
205.670 + return;
205.671 +}
205.672 +
205.673 +/***********************************************************************
205.674 +* NAME
205.675 +*
205.676 +* ios_driver - branch-and-cut driver
205.677 +*
205.678 +* SYNOPSIS
205.679 +*
205.680 +* #include "glpios.h"
205.681 +* int ios_driver(glp_tree *T);
205.682 +*
205.683 +* DESCRIPTION
205.684 +*
205.685 +* The routine ios_driver is a branch-and-cut driver. It controls the
205.686 +* MIP solution process.
205.687 +*
205.688 +* RETURNS
205.689 +*
205.690 +* 0 The MIP problem instance has been successfully solved. This code
205.691 +* does not necessarily mean that the solver has found optimal
205.692 +* solution. It only means that the solution process was successful.
205.693 +*
205.694 +* GLP_EFAIL
205.695 +* The search was prematurely terminated due to the solver failure.
205.696 +*
205.697 +* GLP_EMIPGAP
205.698 +* The search was prematurely terminated, because the relative mip
205.699 +* gap tolerance has been reached.
205.700 +*
205.701 +* GLP_ETMLIM
205.702 +* The search was prematurely terminated, because the time limit has
205.703 +* been exceeded.
205.704 +*
205.705 +* GLP_ESTOP
205.706 +* The search was prematurely terminated by application. */
205.707 +
205.708 +int ios_driver(glp_tree *T)
205.709 +{ int p, curr_p, p_stat, d_stat, ret;
205.710 +#if 1 /* carry out to glp_tree */
205.711 + int pred_p = 0;
205.712 + /* if the current subproblem has been just created due to
205.713 + branching, pred_p is the reference number of its parent
205.714 + subproblem, otherwise pred_p is zero */
205.715 +#endif
205.716 + glp_long ttt = T->tm_beg;
205.717 +#if 0
205.718 + ((glp_iocp *)T->parm)->msg_lev = GLP_MSG_DBG;
205.719 +#endif
205.720 + /* on entry to the B&B driver it is assumed that the active list
205.721 + contains the only active (i.e. root) subproblem, which is the
205.722 + original MIP problem to be solved */
205.723 +loop: /* main loop starts here */
205.724 + /* at this point the current subproblem does not exist */
205.725 + xassert(T->curr == NULL);
205.726 + /* if the active list is empty, the search is finished */
205.727 + if (T->head == NULL)
205.728 + { if (T->parm->msg_lev >= GLP_MSG_DBG)
205.729 + xprintf("Active list is empty!\n");
205.730 + xassert(dmp_in_use(T->pool).lo == 0);
205.731 + ret = 0;
205.732 + goto done;
205.733 + }
205.734 + /* select some active subproblem to continue the search */
205.735 + xassert(T->next_p == 0);
205.736 + /* let the application program select subproblem */
205.737 + if (T->parm->cb_func != NULL)
205.738 + { xassert(T->reason == 0);
205.739 + T->reason = GLP_ISELECT;
205.740 + T->parm->cb_func(T, T->parm->cb_info);
205.741 + T->reason = 0;
205.742 + if (T->stop)
205.743 + { ret = GLP_ESTOP;
205.744 + goto done;
205.745 + }
205.746 + }
205.747 + if (T->next_p != 0)
205.748 + { /* the application program has selected something */
205.749 + ;
205.750 + }
205.751 + else if (T->a_cnt == 1)
205.752 + { /* the only active subproblem exists, so select it */
205.753 + xassert(T->head->next == NULL);
205.754 + T->next_p = T->head->p;
205.755 + }
205.756 + else if (T->child != 0)
205.757 + { /* select one of branching childs suggested by the branching
205.758 + heuristic */
205.759 + T->next_p = T->child;
205.760 + }
205.761 + else
205.762 + { /* select active subproblem as specified by the backtracking
205.763 + technique option */
205.764 + T->next_p = ios_choose_node(T);
205.765 + }
205.766 + /* the active subproblem just selected becomes current */
205.767 + ios_revive_node(T, T->next_p);
205.768 + T->next_p = T->child = 0;
205.769 + /* invalidate pred_p, if it is not the reference number of the
205.770 + parent of the current subproblem */
205.771 + if (T->curr->up != NULL && T->curr->up->p != pred_p) pred_p = 0;
205.772 + /* determine the reference number of the current subproblem */
205.773 + p = T->curr->p;
205.774 + if (T->parm->msg_lev >= GLP_MSG_DBG)
205.775 + { xprintf("-----------------------------------------------------"
205.776 + "-------------------\n");
205.777 + xprintf("Processing node %d at level %d\n", p, T->curr->level);
205.778 + }
205.779 + /* if it is the root subproblem, initialize cut generators */
205.780 + if (p == 1)
205.781 + { if (T->parm->gmi_cuts == GLP_ON)
205.782 + { if (T->parm->msg_lev >= GLP_MSG_ALL)
205.783 + xprintf("Gomory's cuts enabled\n");
205.784 + }
205.785 + if (T->parm->mir_cuts == GLP_ON)
205.786 + { if (T->parm->msg_lev >= GLP_MSG_ALL)
205.787 + xprintf("MIR cuts enabled\n");
205.788 + xassert(T->mir_gen == NULL);
205.789 + T->mir_gen = ios_mir_init(T);
205.790 + }
205.791 + if (T->parm->cov_cuts == GLP_ON)
205.792 + { if (T->parm->msg_lev >= GLP_MSG_ALL)
205.793 + xprintf("Cover cuts enabled\n");
205.794 + }
205.795 + if (T->parm->clq_cuts == GLP_ON)
205.796 + { xassert(T->clq_gen == NULL);
205.797 + if (T->parm->msg_lev >= GLP_MSG_ALL)
205.798 + xprintf("Clique cuts enabled\n");
205.799 + T->clq_gen = ios_clq_init(T);
205.800 + }
205.801 + }
205.802 +more: /* minor loop starts here */
205.803 + /* at this point the current subproblem needs either to be solved
205.804 + for the first time or re-optimized due to reformulation */
205.805 + /* display current progress of the search */
205.806 + if (T->parm->msg_lev >= GLP_MSG_DBG ||
205.807 + T->parm->msg_lev >= GLP_MSG_ON &&
205.808 + (double)(T->parm->out_frq - 1) <=
205.809 + 1000.0 * xdifftime(xtime(), T->tm_lag))
205.810 + show_progress(T, 0);
205.811 + if (T->parm->msg_lev >= GLP_MSG_ALL &&
205.812 + xdifftime(xtime(), ttt) >= 60.0)
205.813 + { glp_long total;
205.814 + glp_mem_usage(NULL, NULL, &total, NULL);
205.815 + xprintf("Time used: %.1f secs. Memory used: %.1f Mb.\n",
205.816 + xdifftime(xtime(), T->tm_beg), xltod(total) / 1048576.0);
205.817 + ttt = xtime();
205.818 + }
205.819 + /* check the mip gap */
205.820 + if (T->parm->mip_gap > 0.0 &&
205.821 + ios_relative_gap(T) <= T->parm->mip_gap)
205.822 + { if (T->parm->msg_lev >= GLP_MSG_DBG)
205.823 + xprintf("Relative gap tolerance reached; search terminated "
205.824 + "\n");
205.825 + ret = GLP_EMIPGAP;
205.826 + goto done;
205.827 + }
205.828 + /* check if the time limit has been exhausted */
205.829 + if (T->parm->tm_lim < INT_MAX &&
205.830 + (double)(T->parm->tm_lim - 1) <=
205.831 + 1000.0 * xdifftime(xtime(), T->tm_beg))
205.832 + { if (T->parm->msg_lev >= GLP_MSG_DBG)
205.833 + xprintf("Time limit exhausted; search terminated\n");
205.834 + ret = GLP_ETMLIM;
205.835 + goto done;
205.836 + }
205.837 + /* let the application program preprocess the subproblem */
205.838 + if (T->parm->cb_func != NULL)
205.839 + { xassert(T->reason == 0);
205.840 + T->reason = GLP_IPREPRO;
205.841 + T->parm->cb_func(T, T->parm->cb_info);
205.842 + T->reason = 0;
205.843 + if (T->stop)
205.844 + { ret = GLP_ESTOP;
205.845 + goto done;
205.846 + }
205.847 + }
205.848 + /* perform basic preprocessing */
205.849 + if (T->parm->pp_tech == GLP_PP_NONE)
205.850 + ;
205.851 + else if (T->parm->pp_tech == GLP_PP_ROOT)
205.852 + { if (T->curr->level == 0)
205.853 + { if (ios_preprocess_node(T, 100))
205.854 + goto fath;
205.855 + }
205.856 + }
205.857 + else if (T->parm->pp_tech == GLP_PP_ALL)
205.858 + { if (ios_preprocess_node(T, T->curr->level == 0 ? 100 : 10))
205.859 + goto fath;
205.860 + }
205.861 + else
205.862 + xassert(T != T);
205.863 + /* preprocessing may improve the global bound */
205.864 + if (!is_branch_hopeful(T, p))
205.865 + { xprintf("*** not tested yet ***\n");
205.866 + goto fath;
205.867 + }
205.868 + /* solve LP relaxation of the current subproblem */
205.869 + if (T->parm->msg_lev >= GLP_MSG_DBG)
205.870 + xprintf("Solving LP relaxation...\n");
205.871 + ret = ios_solve_node(T);
205.872 + if (!(ret == 0 || ret == GLP_EOBJLL || ret == GLP_EOBJUL))
205.873 + { if (T->parm->msg_lev >= GLP_MSG_ERR)
205.874 + xprintf("ios_driver: unable to solve current LP relaxation;"
205.875 + " glp_simplex returned %d\n", ret);
205.876 + ret = GLP_EFAIL;
205.877 + goto done;
205.878 + }
205.879 + /* analyze status of the basic solution to LP relaxation found */
205.880 + p_stat = T->mip->pbs_stat;
205.881 + d_stat = T->mip->dbs_stat;
205.882 + if (p_stat == GLP_FEAS && d_stat == GLP_FEAS)
205.883 + { /* LP relaxation has optimal solution */
205.884 + if (T->parm->msg_lev >= GLP_MSG_DBG)
205.885 + xprintf("Found optimal solution to LP relaxation\n");
205.886 + }
205.887 + else if (d_stat == GLP_NOFEAS)
205.888 + { /* LP relaxation has no dual feasible solution */
205.889 + /* since the current subproblem cannot have a larger feasible
205.890 + region than its parent, there is something wrong */
205.891 + if (T->parm->msg_lev >= GLP_MSG_ERR)
205.892 + xprintf("ios_driver: current LP relaxation has no dual feas"
205.893 + "ible solution\n");
205.894 + ret = GLP_EFAIL;
205.895 + goto done;
205.896 + }
205.897 + else if (p_stat == GLP_INFEAS && d_stat == GLP_FEAS)
205.898 + { /* LP relaxation has no primal solution which is better than
205.899 + the incumbent objective value */
205.900 + xassert(T->mip->mip_stat == GLP_FEAS);
205.901 + if (T->parm->msg_lev >= GLP_MSG_DBG)
205.902 + xprintf("LP relaxation has no solution better than incumben"
205.903 + "t objective value\n");
205.904 + /* prune the branch */
205.905 + goto fath;
205.906 + }
205.907 + else if (p_stat == GLP_NOFEAS)
205.908 + { /* LP relaxation has no primal feasible solution */
205.909 + if (T->parm->msg_lev >= GLP_MSG_DBG)
205.910 + xprintf("LP relaxation has no feasible solution\n");
205.911 + /* prune the branch */
205.912 + goto fath;
205.913 + }
205.914 + else
205.915 + { /* other cases cannot appear */
205.916 + xassert(T->mip != T->mip);
205.917 + }
205.918 + /* at this point basic solution to LP relaxation of the current
205.919 + subproblem is optimal */
205.920 + xassert(p_stat == GLP_FEAS && d_stat == GLP_FEAS);
205.921 + xassert(T->curr != NULL);
205.922 + T->curr->lp_obj = T->mip->obj_val;
205.923 + /* thus, it defines a local bound to integer optimal solution of
205.924 + the current subproblem */
205.925 + { double bound = T->mip->obj_val;
205.926 + /* some local bound to the current subproblem could be already
205.927 + set before, so we should only improve it */
205.928 + bound = ios_round_bound(T, bound);
205.929 + if (T->mip->dir == GLP_MIN)
205.930 + { if (T->curr->bound < bound)
205.931 + T->curr->bound = bound;
205.932 + }
205.933 + else if (T->mip->dir == GLP_MAX)
205.934 + { if (T->curr->bound > bound)
205.935 + T->curr->bound = bound;
205.936 + }
205.937 + else
205.938 + xassert(T->mip != T->mip);
205.939 + if (T->parm->msg_lev >= GLP_MSG_DBG)
205.940 + xprintf("Local bound is %.9e\n", bound);
205.941 + }
205.942 + /* if the local bound indicates that integer optimal solution of
205.943 + the current subproblem cannot be better than the global bound,
205.944 + prune the branch */
205.945 + if (!is_branch_hopeful(T, p))
205.946 + { if (T->parm->msg_lev >= GLP_MSG_DBG)
205.947 + xprintf("Current branch is hopeless and can be pruned\n");
205.948 + goto fath;
205.949 + }
205.950 + /* let the application program generate additional rows ("lazy"
205.951 + constraints) */
205.952 + xassert(T->reopt == 0);
205.953 + xassert(T->reinv == 0);
205.954 + if (T->parm->cb_func != NULL)
205.955 + { xassert(T->reason == 0);
205.956 + T->reason = GLP_IROWGEN;
205.957 + T->parm->cb_func(T, T->parm->cb_info);
205.958 + T->reason = 0;
205.959 + if (T->stop)
205.960 + { ret = GLP_ESTOP;
205.961 + goto done;
205.962 + }
205.963 + if (T->reopt)
205.964 + { /* some rows were added; re-optimization is needed */
205.965 + T->reopt = T->reinv = 0;
205.966 + goto more;
205.967 + }
205.968 + if (T->reinv)
205.969 + { /* no rows were added, however, some inactive rows were
205.970 + removed */
205.971 + T->reinv = 0;
205.972 + xassert(glp_factorize(T->mip) == 0);
205.973 + }
205.974 + }
205.975 + /* check if the basic solution is integer feasible */
205.976 + check_integrality(T);
205.977 + /* if the basic solution satisfies to all integrality conditions,
205.978 + it is a new, better integer feasible solution */
205.979 + if (T->curr->ii_cnt == 0)
205.980 + { if (T->parm->msg_lev >= GLP_MSG_DBG)
205.981 + xprintf("New integer feasible solution found\n");
205.982 + if (T->parm->msg_lev >= GLP_MSG_ALL)
205.983 + display_cut_info(T);
205.984 + record_solution(T);
205.985 + if (T->parm->msg_lev >= GLP_MSG_ON)
205.986 + show_progress(T, 1);
205.987 + /* make the application program happy */
205.988 + if (T->parm->cb_func != NULL)
205.989 + { xassert(T->reason == 0);
205.990 + T->reason = GLP_IBINGO;
205.991 + T->parm->cb_func(T, T->parm->cb_info);
205.992 + T->reason = 0;
205.993 + if (T->stop)
205.994 + { ret = GLP_ESTOP;
205.995 + goto done;
205.996 + }
205.997 + }
205.998 + /* since the current subproblem has been fathomed, prune its
205.999 + branch */
205.1000 + goto fath;
205.1001 + }
205.1002 + /* at this point basic solution to LP relaxation of the current
205.1003 + subproblem is optimal, but integer infeasible */
205.1004 + /* try to fix some non-basic structural variables of integer kind
205.1005 + on their current bounds due to reduced costs */
205.1006 + if (T->mip->mip_stat == GLP_FEAS)
205.1007 + fix_by_red_cost(T);
205.1008 + /* let the application program try to find some solution to the
205.1009 + original MIP with a primal heuristic */
205.1010 + if (T->parm->cb_func != NULL)
205.1011 + { xassert(T->reason == 0);
205.1012 + T->reason = GLP_IHEUR;
205.1013 + T->parm->cb_func(T, T->parm->cb_info);
205.1014 + T->reason = 0;
205.1015 + if (T->stop)
205.1016 + { ret = GLP_ESTOP;
205.1017 + goto done;
205.1018 + }
205.1019 + /* check if the current branch became hopeless */
205.1020 + if (!is_branch_hopeful(T, p))
205.1021 + { if (T->parm->msg_lev >= GLP_MSG_DBG)
205.1022 + xprintf("Current branch became hopeless and can be prune"
205.1023 + "d\n");
205.1024 + goto fath;
205.1025 + }
205.1026 + }
205.1027 + /* try to find solution with the feasibility pump heuristic */
205.1028 + if (T->parm->fp_heur)
205.1029 + { xassert(T->reason == 0);
205.1030 + T->reason = GLP_IHEUR;
205.1031 + ios_feas_pump(T);
205.1032 + T->reason = 0;
205.1033 + /* check if the current branch became hopeless */
205.1034 + if (!is_branch_hopeful(T, p))
205.1035 + { if (T->parm->msg_lev >= GLP_MSG_DBG)
205.1036 + xprintf("Current branch became hopeless and can be prune"
205.1037 + "d\n");
205.1038 + goto fath;
205.1039 + }
205.1040 + }
205.1041 + /* it's time to generate cutting planes */
205.1042 + xassert(T->local != NULL);
205.1043 + xassert(T->local->size == 0);
205.1044 + /* let the application program generate some cuts; note that it
205.1045 + can add cuts either to the local cut pool or directly to the
205.1046 + current subproblem */
205.1047 + if (T->parm->cb_func != NULL)
205.1048 + { xassert(T->reason == 0);
205.1049 + T->reason = GLP_ICUTGEN;
205.1050 + T->parm->cb_func(T, T->parm->cb_info);
205.1051 + T->reason = 0;
205.1052 + if (T->stop)
205.1053 + { ret = GLP_ESTOP;
205.1054 + goto done;
205.1055 + }
205.1056 + }
205.1057 + /* try to generate generic cuts with built-in generators
205.1058 + (as suggested by Matteo Fischetti et al. the built-in cuts
205.1059 + are not generated at each branching node; an intense attempt
205.1060 + of generating new cuts is only made at the root node, and then
205.1061 + a moderate effort is spent after each backtracking step) */
205.1062 + if (T->curr->level == 0 || pred_p == 0)
205.1063 + { xassert(T->reason == 0);
205.1064 + T->reason = GLP_ICUTGEN;
205.1065 + generate_cuts(T);
205.1066 + T->reason = 0;
205.1067 + }
205.1068 + /* if the local cut pool is not empty, select useful cuts and add
205.1069 + them to the current subproblem */
205.1070 + if (T->local->size > 0)
205.1071 + { xassert(T->reason == 0);
205.1072 + T->reason = GLP_ICUTGEN;
205.1073 + ios_process_cuts(T);
205.1074 + T->reason = 0;
205.1075 + }
205.1076 + /* clear the local cut pool */
205.1077 + ios_clear_pool(T, T->local);
205.1078 + /* perform re-optimization, if necessary */
205.1079 + if (T->reopt)
205.1080 + { T->reopt = 0;
205.1081 + T->curr->changed++;
205.1082 + goto more;
205.1083 + }
205.1084 + /* no cuts were generated; remove inactive cuts */
205.1085 + remove_cuts(T);
205.1086 + if (T->parm->msg_lev >= GLP_MSG_ALL && T->curr->level == 0)
205.1087 + display_cut_info(T);
205.1088 + /* update history information used on pseudocost branching */
205.1089 + if (T->pcost != NULL) ios_pcost_update(T);
205.1090 + /* it's time to perform branching */
205.1091 + xassert(T->br_var == 0);
205.1092 + xassert(T->br_sel == 0);
205.1093 + /* let the application program choose variable to branch on */
205.1094 + if (T->parm->cb_func != NULL)
205.1095 + { xassert(T->reason == 0);
205.1096 + xassert(T->br_var == 0);
205.1097 + xassert(T->br_sel == 0);
205.1098 + T->reason = GLP_IBRANCH;
205.1099 + T->parm->cb_func(T, T->parm->cb_info);
205.1100 + T->reason = 0;
205.1101 + if (T->stop)
205.1102 + { ret = GLP_ESTOP;
205.1103 + goto done;
205.1104 + }
205.1105 + }
205.1106 + /* if nothing has been chosen, choose some variable as specified
205.1107 + by the branching technique option */
205.1108 + if (T->br_var == 0)
205.1109 + T->br_var = ios_choose_var(T, &T->br_sel);
205.1110 + /* perform actual branching */
205.1111 + curr_p = T->curr->p;
205.1112 + ret = branch_on(T, T->br_var, T->br_sel);
205.1113 + T->br_var = T->br_sel = 0;
205.1114 + if (ret == 0)
205.1115 + { /* both branches have been created */
205.1116 + pred_p = curr_p;
205.1117 + goto loop;
205.1118 + }
205.1119 + else if (ret == 1)
205.1120 + { /* one branch is hopeless and has been pruned, so now the
205.1121 + current subproblem is other branch */
205.1122 + /* the current subproblem should be considered as a new one,
205.1123 + since one bound of the branching variable was changed */
205.1124 + T->curr->solved = T->curr->changed = 0;
205.1125 + goto more;
205.1126 + }
205.1127 + else if (ret == 2)
205.1128 + { /* both branches are hopeless and have been pruned; new
205.1129 + subproblem selection is needed to continue the search */
205.1130 + goto fath;
205.1131 + }
205.1132 + else
205.1133 + xassert(ret != ret);
205.1134 +fath: /* the current subproblem has been fathomed */
205.1135 + if (T->parm->msg_lev >= GLP_MSG_DBG)
205.1136 + xprintf("Node %d fathomed\n", p);
205.1137 + /* freeze the current subproblem */
205.1138 + ios_freeze_node(T);
205.1139 + /* and prune the corresponding branch of the tree */
205.1140 + ios_delete_node(T, p);
205.1141 + /* if a new integer feasible solution has just been found, other
205.1142 + branches may become hopeless and therefore must be pruned */
205.1143 + if (T->mip->mip_stat == GLP_FEAS) cleanup_the_tree(T);
205.1144 + /* new subproblem selection is needed due to backtracking */
205.1145 + pred_p = 0;
205.1146 + goto loop;
205.1147 +done: /* display progress of the search on exit from the solver */
205.1148 + if (T->parm->msg_lev >= GLP_MSG_ON)
205.1149 + show_progress(T, 0);
205.1150 + if (T->mir_gen != NULL)
205.1151 + ios_mir_term(T->mir_gen), T->mir_gen = NULL;
205.1152 + if (T->clq_gen != NULL)
205.1153 + ios_clq_term(T->clq_gen), T->clq_gen = NULL;
205.1154 + /* return to the calling program */
205.1155 + return ret;
205.1156 +}
205.1157 +
205.1158 +/* eof */
206.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
206.2 +++ b/src/glpios04.c Mon Dec 06 13:09:21 2010 +0100
206.3 @@ -0,0 +1,303 @@
206.4 +/* glpios04.c (operations on sparse vectors) */
206.5 +
206.6 +/***********************************************************************
206.7 +* This code is part of GLPK (GNU Linear Programming Kit).
206.8 +*
206.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
206.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
206.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
206.12 +* E-mail: <mao@gnu.org>.
206.13 +*
206.14 +* GLPK is free software: you can redistribute it and/or modify it
206.15 +* under the terms of the GNU General Public License as published by
206.16 +* the Free Software Foundation, either version 3 of the License, or
206.17 +* (at your option) any later version.
206.18 +*
206.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
206.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
206.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
206.22 +* License for more details.
206.23 +*
206.24 +* You should have received a copy of the GNU General Public License
206.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
206.26 +***********************************************************************/
206.27 +
206.28 +#include "glpios.h"
206.29 +
206.30 +/***********************************************************************
206.31 +* NAME
206.32 +*
206.33 +* ios_create_vec - create sparse vector
206.34 +*
206.35 +* SYNOPSIS
206.36 +*
206.37 +* #include "glpios.h"
206.38 +* IOSVEC *ios_create_vec(int n);
206.39 +*
206.40 +* DESCRIPTION
206.41 +*
206.42 +* The routine ios_create_vec creates a sparse vector of dimension n,
206.43 +* which initially is a null vector.
206.44 +*
206.45 +* RETURNS
206.46 +*
206.47 +* The routine returns a pointer to the vector created. */
206.48 +
206.49 +IOSVEC *ios_create_vec(int n)
206.50 +{ IOSVEC *v;
206.51 + xassert(n >= 0);
206.52 + v = xmalloc(sizeof(IOSVEC));
206.53 + v->n = n;
206.54 + v->nnz = 0;
206.55 + v->pos = xcalloc(1+n, sizeof(int));
206.56 + memset(&v->pos[1], 0, n * sizeof(int));
206.57 + v->ind = xcalloc(1+n, sizeof(int));
206.58 + v->val = xcalloc(1+n, sizeof(double));
206.59 + return v;
206.60 +}
206.61 +
206.62 +/***********************************************************************
206.63 +* NAME
206.64 +*
206.65 +* ios_check_vec - check that sparse vector has correct representation
206.66 +*
206.67 +* SYNOPSIS
206.68 +*
206.69 +* #include "glpios.h"
206.70 +* void ios_check_vec(IOSVEC *v);
206.71 +*
206.72 +* DESCRIPTION
206.73 +*
206.74 +* The routine ios_check_vec checks that a sparse vector specified by
206.75 +* the parameter v has correct representation.
206.76 +*
206.77 +* NOTE
206.78 +*
206.79 +* Complexity of this operation is O(n). */
206.80 +
206.81 +void ios_check_vec(IOSVEC *v)
206.82 +{ int j, k, nnz;
206.83 + xassert(v->n >= 0);
206.84 + nnz = 0;
206.85 + for (j = v->n; j >= 1; j--)
206.86 + { k = v->pos[j];
206.87 + xassert(0 <= k && k <= v->nnz);
206.88 + if (k != 0)
206.89 + { xassert(v->ind[k] == j);
206.90 + nnz++;
206.91 + }
206.92 + }
206.93 + xassert(v->nnz == nnz);
206.94 + return;
206.95 +}
206.96 +
206.97 +/***********************************************************************
206.98 +* NAME
206.99 +*
206.100 +* ios_get_vj - retrieve component of sparse vector
206.101 +*
206.102 +* SYNOPSIS
206.103 +*
206.104 +* #include "glpios.h"
206.105 +* double ios_get_vj(IOSVEC *v, int j);
206.106 +*
206.107 +* RETURNS
206.108 +*
206.109 +* The routine ios_get_vj returns j-th component of a sparse vector
206.110 +* specified by the parameter v. */
206.111 +
206.112 +double ios_get_vj(IOSVEC *v, int j)
206.113 +{ int k;
206.114 + xassert(1 <= j && j <= v->n);
206.115 + k = v->pos[j];
206.116 + xassert(0 <= k && k <= v->nnz);
206.117 + return (k == 0 ? 0.0 : v->val[k]);
206.118 +}
206.119 +
206.120 +/***********************************************************************
206.121 +* NAME
206.122 +*
206.123 +* ios_set_vj - set/change component of sparse vector
206.124 +*
206.125 +* SYNOPSIS
206.126 +*
206.127 +* #include "glpios.h"
206.128 +* void ios_set_vj(IOSVEC *v, int j, double val);
206.129 +*
206.130 +* DESCRIPTION
206.131 +*
206.132 +* The routine ios_set_vj assigns val to j-th component of a sparse
206.133 +* vector specified by the parameter v. */
206.134 +
206.135 +void ios_set_vj(IOSVEC *v, int j, double val)
206.136 +{ int k;
206.137 + xassert(1 <= j && j <= v->n);
206.138 + k = v->pos[j];
206.139 + if (val == 0.0)
206.140 + { if (k != 0)
206.141 + { /* remove j-th component */
206.142 + v->pos[j] = 0;
206.143 + if (k < v->nnz)
206.144 + { v->pos[v->ind[v->nnz]] = k;
206.145 + v->ind[k] = v->ind[v->nnz];
206.146 + v->val[k] = v->val[v->nnz];
206.147 + }
206.148 + v->nnz--;
206.149 + }
206.150 + }
206.151 + else
206.152 + { if (k == 0)
206.153 + { /* create j-th component */
206.154 + k = ++(v->nnz);
206.155 + v->pos[j] = k;
206.156 + v->ind[k] = j;
206.157 + }
206.158 + v->val[k] = val;
206.159 + }
206.160 + return;
206.161 +}
206.162 +
206.163 +/***********************************************************************
206.164 +* NAME
206.165 +*
206.166 +* ios_clear_vec - set all components of sparse vector to zero
206.167 +*
206.168 +* SYNOPSIS
206.169 +*
206.170 +* #include "glpios.h"
206.171 +* void ios_clear_vec(IOSVEC *v);
206.172 +*
206.173 +* DESCRIPTION
206.174 +*
206.175 +* The routine ios_clear_vec sets all components of a sparse vector
206.176 +* specified by the parameter v to zero. */
206.177 +
206.178 +void ios_clear_vec(IOSVEC *v)
206.179 +{ int k;
206.180 + for (k = 1; k <= v->nnz; k++)
206.181 + v->pos[v->ind[k]] = 0;
206.182 + v->nnz = 0;
206.183 + return;
206.184 +}
206.185 +
206.186 +/***********************************************************************
206.187 +* NAME
206.188 +*
206.189 +* ios_clean_vec - remove zero or small components from sparse vector
206.190 +*
206.191 +* SYNOPSIS
206.192 +*
206.193 +* #include "glpios.h"
206.194 +* void ios_clean_vec(IOSVEC *v, double eps);
206.195 +*
206.196 +* DESCRIPTION
206.197 +*
206.198 +* The routine ios_clean_vec removes zero components and components
206.199 +* whose magnitude is less than eps from a sparse vector specified by
206.200 +* the parameter v. If eps is 0.0, only zero components are removed. */
206.201 +
206.202 +void ios_clean_vec(IOSVEC *v, double eps)
206.203 +{ int k, nnz;
206.204 + nnz = 0;
206.205 + for (k = 1; k <= v->nnz; k++)
206.206 + { if (fabs(v->val[k]) == 0.0 || fabs(v->val[k]) < eps)
206.207 + { /* remove component */
206.208 + v->pos[v->ind[k]] = 0;
206.209 + }
206.210 + else
206.211 + { /* keep component */
206.212 + nnz++;
206.213 + v->pos[v->ind[k]] = nnz;
206.214 + v->ind[nnz] = v->ind[k];
206.215 + v->val[nnz] = v->val[k];
206.216 + }
206.217 + }
206.218 + v->nnz = nnz;
206.219 + return;
206.220 +}
206.221 +
206.222 +/***********************************************************************
206.223 +* NAME
206.224 +*
206.225 +* ios_copy_vec - copy sparse vector (x := y)
206.226 +*
206.227 +* SYNOPSIS
206.228 +*
206.229 +* #include "glpios.h"
206.230 +* void ios_copy_vec(IOSVEC *x, IOSVEC *y);
206.231 +*
206.232 +* DESCRIPTION
206.233 +*
206.234 +* The routine ios_copy_vec copies a sparse vector specified by the
206.235 +* parameter y to a sparse vector specified by the parameter x. */
206.236 +
206.237 +void ios_copy_vec(IOSVEC *x, IOSVEC *y)
206.238 +{ int j;
206.239 + xassert(x != y);
206.240 + xassert(x->n == y->n);
206.241 + ios_clear_vec(x);
206.242 + x->nnz = y->nnz;
206.243 + memcpy(&x->ind[1], &y->ind[1], x->nnz * sizeof(int));
206.244 + memcpy(&x->val[1], &y->val[1], x->nnz * sizeof(double));
206.245 + for (j = 1; j <= x->nnz; j++)
206.246 + x->pos[x->ind[j]] = j;
206.247 + return;
206.248 +}
206.249 +
206.250 +/***********************************************************************
206.251 +* NAME
206.252 +*
206.253 +* ios_linear_comb - compute linear combination (x := x + a * y)
206.254 +*
206.255 +* SYNOPSIS
206.256 +*
206.257 +* #include "glpios.h"
206.258 +* void ios_linear_comb(IOSVEC *x, double a, IOSVEC *y);
206.259 +*
206.260 +* DESCRIPTION
206.261 +*
206.262 +* The routine ios_linear_comb computes the linear combination
206.263 +*
206.264 +* x := x + a * y,
206.265 +*
206.266 +* where x and y are sparse vectors, a is a scalar. */
206.267 +
206.268 +void ios_linear_comb(IOSVEC *x, double a, IOSVEC *y)
206.269 +{ int j, k;
206.270 + double xj, yj;
206.271 + xassert(x != y);
206.272 + xassert(x->n == y->n);
206.273 + for (k = 1; k <= y->nnz; k++)
206.274 + { j = y->ind[k];
206.275 + xj = ios_get_vj(x, j);
206.276 + yj = y->val[k];
206.277 + ios_set_vj(x, j, xj + a * yj);
206.278 + }
206.279 + return;
206.280 +}
206.281 +
206.282 +/***********************************************************************
206.283 +* NAME
206.284 +*
206.285 +* ios_delete_vec - delete sparse vector
206.286 +*
206.287 +* SYNOPSIS
206.288 +*
206.289 +* #include "glpios.h"
206.290 +* void ios_delete_vec(IOSVEC *v);
206.291 +*
206.292 +* DESCRIPTION
206.293 +*
206.294 +* The routine ios_delete_vec deletes a sparse vector specified by the
206.295 +* parameter v freeing all the memory allocated to this object. */
206.296 +
206.297 +void ios_delete_vec(IOSVEC *v)
206.298 +{ /* delete sparse vector */
206.299 + xfree(v->pos);
206.300 + xfree(v->ind);
206.301 + xfree(v->val);
206.302 + xfree(v);
206.303 + return;
206.304 +}
206.305 +
206.306 +/* eof */
207.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
207.2 +++ b/src/glpios05.c Mon Dec 06 13:09:21 2010 +0100
207.3 @@ -0,0 +1,281 @@
207.4 +/* glpios05.c (Gomory's mixed integer cut generator) */
207.5 +
207.6 +/***********************************************************************
207.7 +* This code is part of GLPK (GNU Linear Programming Kit).
207.8 +*
207.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
207.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
207.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
207.12 +* E-mail: <mao@gnu.org>.
207.13 +*
207.14 +* GLPK is free software: you can redistribute it and/or modify it
207.15 +* under the terms of the GNU General Public License as published by
207.16 +* the Free Software Foundation, either version 3 of the License, or
207.17 +* (at your option) any later version.
207.18 +*
207.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
207.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
207.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
207.22 +* License for more details.
207.23 +*
207.24 +* You should have received a copy of the GNU General Public License
207.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
207.26 +***********************************************************************/
207.27 +
207.28 +#include "glpios.h"
207.29 +
207.30 +/***********************************************************************
207.31 +* NAME
207.32 +*
207.33 +* ios_gmi_gen - generate Gomory's mixed integer cuts.
207.34 +*
207.35 +* SYNOPSIS
207.36 +*
207.37 +* #include "glpios.h"
207.38 +* void ios_gmi_gen(glp_tree *tree, IOSPOOL *pool);
207.39 +*
207.40 +* DESCRIPTION
207.41 +*
207.42 +* The routine ios_gmi_gen generates Gomory's mixed integer cuts for
207.43 +* the current point and adds them to the cut pool. */
207.44 +
207.45 +#define MAXCUTS 50
207.46 +/* maximal number of cuts to be generated for one round */
207.47 +
207.48 +struct worka
207.49 +{ /* Gomory's cut generator working area */
207.50 + int *ind; /* int ind[1+n]; */
207.51 + double *val; /* double val[1+n]; */
207.52 + double *phi; /* double phi[1+m+n]; */
207.53 +};
207.54 +
207.55 +#define f(x) ((x) - floor(x))
207.56 +/* compute fractional part of x */
207.57 +
207.58 +static void gen_cut(glp_tree *tree, struct worka *worka, int j)
207.59 +{ /* this routine tries to generate Gomory's mixed integer cut for
207.60 + specified structural variable x[m+j] of integer kind, which is
207.61 + basic and has fractional value in optimal solution to current
207.62 + LP relaxation */
207.63 + glp_prob *mip = tree->mip;
207.64 + int m = mip->m;
207.65 + int n = mip->n;
207.66 + int *ind = worka->ind;
207.67 + double *val = worka->val;
207.68 + double *phi = worka->phi;
207.69 + int i, k, len, kind, stat;
207.70 + double lb, ub, alfa, beta, ksi, phi1, rhs;
207.71 + /* compute row of the simplex tableau, which (row) corresponds
207.72 + to specified basic variable xB[i] = x[m+j]; see (23) */
207.73 + len = glp_eval_tab_row(mip, m+j, ind, val);
207.74 + /* determine beta[i], which a value of xB[i] in optimal solution
207.75 + to current LP relaxation; note that this value is the same as
207.76 + if it would be computed with formula (27); it is assumed that
207.77 + beta[i] is fractional enough */
207.78 + beta = mip->col[j]->prim;
207.79 + /* compute cut coefficients phi and right-hand side rho, which
207.80 + correspond to formula (30); dense format is used, because rows
207.81 + of the simplex tableau is usually dense */
207.82 + for (k = 1; k <= m+n; k++) phi[k] = 0.0;
207.83 + rhs = f(beta); /* initial value of rho; see (28), (32) */
207.84 + for (j = 1; j <= len; j++)
207.85 + { /* determine original number of non-basic variable xN[j] */
207.86 + k = ind[j];
207.87 + xassert(1 <= k && k <= m+n);
207.88 + /* determine the kind, bounds and current status of xN[j] in
207.89 + optimal solution to LP relaxation */
207.90 + if (k <= m)
207.91 + { /* auxiliary variable */
207.92 + GLPROW *row = mip->row[k];
207.93 + kind = GLP_CV;
207.94 + lb = row->lb;
207.95 + ub = row->ub;
207.96 + stat = row->stat;
207.97 + }
207.98 + else
207.99 + { /* structural variable */
207.100 + GLPCOL *col = mip->col[k-m];
207.101 + kind = col->kind;
207.102 + lb = col->lb;
207.103 + ub = col->ub;
207.104 + stat = col->stat;
207.105 + }
207.106 + /* xN[j] cannot be basic */
207.107 + xassert(stat != GLP_BS);
207.108 + /* determine row coefficient ksi[i,j] at xN[j]; see (23) */
207.109 + ksi = val[j];
207.110 + /* if ksi[i,j] is too large in the magnitude, do not generate
207.111 + the cut */
207.112 + if (fabs(ksi) > 1e+05) goto fini;
207.113 + /* if ksi[i,j] is too small in the magnitude, skip it */
207.114 + if (fabs(ksi) < 1e-10) goto skip;
207.115 + /* compute row coefficient alfa[i,j] at y[j]; see (26) */
207.116 + switch (stat)
207.117 + { case GLP_NF:
207.118 + /* xN[j] is free (unbounded) having non-zero ksi[i,j];
207.119 + do not generate the cut */
207.120 + goto fini;
207.121 + case GLP_NL:
207.122 + /* xN[j] has active lower bound */
207.123 + alfa = - ksi;
207.124 + break;
207.125 + case GLP_NU:
207.126 + /* xN[j] has active upper bound */
207.127 + alfa = + ksi;
207.128 + break;
207.129 + case GLP_NS:
207.130 + /* xN[j] is fixed; skip it */
207.131 + goto skip;
207.132 + default:
207.133 + xassert(stat != stat);
207.134 + }
207.135 + /* compute cut coefficient phi'[j] at y[j]; see (21), (28) */
207.136 + switch (kind)
207.137 + { case GLP_IV:
207.138 + /* y[j] is integer */
207.139 + if (fabs(alfa - floor(alfa + 0.5)) < 1e-10)
207.140 + { /* alfa[i,j] is close to nearest integer; skip it */
207.141 + goto skip;
207.142 + }
207.143 + else if (f(alfa) <= f(beta))
207.144 + phi1 = f(alfa);
207.145 + else
207.146 + phi1 = (f(beta) / (1.0 - f(beta))) * (1.0 - f(alfa));
207.147 + break;
207.148 + case GLP_CV:
207.149 + /* y[j] is continuous */
207.150 + if (alfa >= 0.0)
207.151 + phi1 = + alfa;
207.152 + else
207.153 + phi1 = (f(beta) / (1.0 - f(beta))) * (- alfa);
207.154 + break;
207.155 + default:
207.156 + xassert(kind != kind);
207.157 + }
207.158 + /* compute cut coefficient phi[j] at xN[j] and update right-
207.159 + hand side rho; see (31), (32) */
207.160 + switch (stat)
207.161 + { case GLP_NL:
207.162 + /* xN[j] has active lower bound */
207.163 + phi[k] = + phi1;
207.164 + rhs += phi1 * lb;
207.165 + break;
207.166 + case GLP_NU:
207.167 + /* xN[j] has active upper bound */
207.168 + phi[k] = - phi1;
207.169 + rhs -= phi1 * ub;
207.170 + break;
207.171 + default:
207.172 + xassert(stat != stat);
207.173 + }
207.174 +skip: ;
207.175 + }
207.176 + /* now the cut has the form sum_k phi[k] * x[k] >= rho, where cut
207.177 + coefficients are stored in the array phi in dense format;
207.178 + x[1,...,m] are auxiliary variables, x[m+1,...,m+n] are struc-
207.179 + tural variables; see (30) */
207.180 + /* eliminate auxiliary variables in order to express the cut only
207.181 + through structural variables; see (33) */
207.182 + for (i = 1; i <= m; i++)
207.183 + { GLPROW *row;
207.184 + GLPAIJ *aij;
207.185 + if (fabs(phi[i]) < 1e-10) continue;
207.186 + /* auxiliary variable x[i] has non-zero cut coefficient */
207.187 + row = mip->row[i];
207.188 + /* x[i] cannot be fixed */
207.189 + xassert(row->type != GLP_FX);
207.190 + /* substitute x[i] = sum_j a[i,j] * x[m+j] */
207.191 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
207.192 + phi[m+aij->col->j] += phi[i] * aij->val;
207.193 + }
207.194 + /* convert the final cut to sparse format and substitute fixed
207.195 + (structural) variables */
207.196 + len = 0;
207.197 + for (j = 1; j <= n; j++)
207.198 + { GLPCOL *col;
207.199 + if (fabs(phi[m+j]) < 1e-10) continue;
207.200 + /* structural variable x[m+j] has non-zero cut coefficient */
207.201 + col = mip->col[j];
207.202 + if (col->type == GLP_FX)
207.203 + { /* eliminate x[m+j] */
207.204 + rhs -= phi[m+j] * col->lb;
207.205 + }
207.206 + else
207.207 + { len++;
207.208 + ind[len] = j;
207.209 + val[len] = phi[m+j];
207.210 + }
207.211 + }
207.212 + if (fabs(rhs) < 1e-12) rhs = 0.0;
207.213 + /* if the cut inequality seems to be badly scaled, reject it to
207.214 + avoid numeric difficulties */
207.215 + for (k = 1; k <= len; k++)
207.216 + { if (fabs(val[k]) < 1e-03) goto fini;
207.217 + if (fabs(val[k]) > 1e+03) goto fini;
207.218 + }
207.219 + /* add the cut to the cut pool for further consideration */
207.220 +#if 0
207.221 + ios_add_cut_row(tree, pool, GLP_RF_GMI, len, ind, val, GLP_LO,
207.222 + rhs);
207.223 +#else
207.224 + glp_ios_add_row(tree, NULL, GLP_RF_GMI, 0, len, ind, val, GLP_LO,
207.225 + rhs);
207.226 +#endif
207.227 +fini: return;
207.228 +}
207.229 +
207.230 +struct var { int j; double f; };
207.231 +
207.232 +static int fcmp(const void *p1, const void *p2)
207.233 +{ const struct var *v1 = p1, *v2 = p2;
207.234 + if (v1->f > v2->f) return -1;
207.235 + if (v1->f < v2->f) return +1;
207.236 + return 0;
207.237 +}
207.238 +
207.239 +void ios_gmi_gen(glp_tree *tree)
207.240 +{ /* main routine to generate Gomory's cuts */
207.241 + glp_prob *mip = tree->mip;
207.242 + int m = mip->m;
207.243 + int n = mip->n;
207.244 + struct var *var;
207.245 + int k, nv, j, size;
207.246 + struct worka _worka, *worka = &_worka;
207.247 + /* allocate working arrays */
207.248 + var = xcalloc(1+n, sizeof(struct var));
207.249 + worka->ind = xcalloc(1+n, sizeof(int));
207.250 + worka->val = xcalloc(1+n, sizeof(double));
207.251 + worka->phi = xcalloc(1+m+n, sizeof(double));
207.252 + /* build the list of integer structural variables, which are
207.253 + basic and have fractional value in optimal solution to current
207.254 + LP relaxation */
207.255 + nv = 0;
207.256 + for (j = 1; j <= n; j++)
207.257 + { GLPCOL *col = mip->col[j];
207.258 + double frac;
207.259 + if (col->kind != GLP_IV) continue;
207.260 + if (col->type == GLP_FX) continue;
207.261 + if (col->stat != GLP_BS) continue;
207.262 + frac = f(col->prim);
207.263 + if (!(0.05 <= frac && frac <= 0.95)) continue;
207.264 + /* add variable to the list */
207.265 + nv++, var[nv].j = j, var[nv].f = frac;
207.266 + }
207.267 + /* order the list by descending fractionality */
207.268 + qsort(&var[1], nv, sizeof(struct var), fcmp);
207.269 + /* try to generate cuts by one for each variable in the list, but
207.270 + not more than MAXCUTS cuts */
207.271 + size = glp_ios_pool_size(tree);
207.272 + for (k = 1; k <= nv; k++)
207.273 + { if (glp_ios_pool_size(tree) - size >= MAXCUTS) break;
207.274 + gen_cut(tree, worka, var[k].j);
207.275 + }
207.276 + /* free working arrays */
207.277 + xfree(var);
207.278 + xfree(worka->ind);
207.279 + xfree(worka->val);
207.280 + xfree(worka->phi);
207.281 + return;
207.282 +}
207.283 +
207.284 +/* eof */
208.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
208.2 +++ b/src/glpios06.c Mon Dec 06 13:09:21 2010 +0100
208.3 @@ -0,0 +1,1447 @@
208.4 +/* glpios06.c (MIR cut generator) */
208.5 +
208.6 +/***********************************************************************
208.7 +* This code is part of GLPK (GNU Linear Programming Kit).
208.8 +*
208.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
208.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
208.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
208.12 +* E-mail: <mao@gnu.org>.
208.13 +*
208.14 +* GLPK is free software: you can redistribute it and/or modify it
208.15 +* under the terms of the GNU General Public License as published by
208.16 +* the Free Software Foundation, either version 3 of the License, or
208.17 +* (at your option) any later version.
208.18 +*
208.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
208.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
208.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
208.22 +* License for more details.
208.23 +*
208.24 +* You should have received a copy of the GNU General Public License
208.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
208.26 +***********************************************************************/
208.27 +
208.28 +#include "glpios.h"
208.29 +
208.30 +#define _MIR_DEBUG 0
208.31 +
208.32 +#define MAXAGGR 5
208.33 +/* maximal number of rows which can be aggregated */
208.34 +
208.35 +struct MIR
208.36 +{ /* MIR cut generator working area */
208.37 + /*--------------------------------------------------------------*/
208.38 + /* global information valid for the root subproblem */
208.39 + int m;
208.40 + /* number of rows (in the root subproblem) */
208.41 + int n;
208.42 + /* number of columns */
208.43 + char *skip; /* char skip[1+m]; */
208.44 + /* skip[i], 1 <= i <= m, is a flag that means that row i should
208.45 + not be used because (1) it is not suitable, or (2) because it
208.46 + has been used in the aggregated constraint */
208.47 + char *isint; /* char isint[1+m+n]; */
208.48 + /* isint[k], 1 <= k <= m+n, is a flag that means that variable
208.49 + x[k] is integer (otherwise, continuous) */
208.50 + double *lb; /* double lb[1+m+n]; */
208.51 + /* lb[k], 1 <= k <= m+n, is lower bound of x[k]; -DBL_MAX means
208.52 + that x[k] has no lower bound */
208.53 + int *vlb; /* int vlb[1+m+n]; */
208.54 + /* vlb[k] = k', 1 <= k <= m+n, is the number of integer variable,
208.55 + which defines variable lower bound x[k] >= lb[k] * x[k']; zero
208.56 + means that x[k] has simple lower bound */
208.57 + double *ub; /* double ub[1+m+n]; */
208.58 + /* ub[k], 1 <= k <= m+n, is upper bound of x[k]; +DBL_MAX means
208.59 + that x[k] has no upper bound */
208.60 + int *vub; /* int vub[1+m+n]; */
208.61 + /* vub[k] = k', 1 <= k <= m+n, is the number of integer variable,
208.62 + which defines variable upper bound x[k] <= ub[k] * x[k']; zero
208.63 + means that x[k] has simple upper bound */
208.64 + /*--------------------------------------------------------------*/
208.65 + /* current (fractional) point to be separated */
208.66 + double *x; /* double x[1+m+n]; */
208.67 + /* x[k] is current value of auxiliary (1 <= k <= m) or structural
208.68 + (m+1 <= k <= m+n) variable */
208.69 + /*--------------------------------------------------------------*/
208.70 + /* aggregated constraint sum a[k] * x[k] = b, which is a linear
208.71 + combination of original constraints transformed to equalities
208.72 + by introducing auxiliary variables */
208.73 + int agg_cnt;
208.74 + /* number of rows (original constraints) used to build aggregated
208.75 + constraint, 1 <= agg_cnt <= MAXAGGR */
208.76 + int *agg_row; /* int agg_row[1+MAXAGGR]; */
208.77 + /* agg_row[k], 1 <= k <= agg_cnt, is the row number used to build
208.78 + aggregated constraint */
208.79 + IOSVEC *agg_vec; /* IOSVEC agg_vec[1:m+n]; */
208.80 + /* sparse vector of aggregated constraint coefficients, a[k] */
208.81 + double agg_rhs;
208.82 + /* right-hand side of the aggregated constraint, b */
208.83 + /*--------------------------------------------------------------*/
208.84 + /* bound substitution flags for modified constraint */
208.85 + char *subst; /* char subst[1+m+n]; */
208.86 + /* subst[k], 1 <= k <= m+n, is a bound substitution flag used for
208.87 + variable x[k]:
208.88 + '?' - x[k] is missing in modified constraint
208.89 + 'L' - x[k] = (lower bound) + x'[k]
208.90 + 'U' - x[k] = (upper bound) - x'[k] */
208.91 + /*--------------------------------------------------------------*/
208.92 + /* modified constraint sum a'[k] * x'[k] = b', where x'[k] >= 0,
208.93 + derived from aggregated constraint by substituting bounds;
208.94 + note that due to substitution of variable bounds there may be
208.95 + additional terms in the modified constraint */
208.96 + IOSVEC *mod_vec; /* IOSVEC mod_vec[1:m+n]; */
208.97 + /* sparse vector of modified constraint coefficients, a'[k] */
208.98 + double mod_rhs;
208.99 + /* right-hand side of the modified constraint, b' */
208.100 + /*--------------------------------------------------------------*/
208.101 + /* cutting plane sum alpha[k] * x[k] <= beta */
208.102 + IOSVEC *cut_vec; /* IOSVEC cut_vec[1:m+n]; */
208.103 + /* sparse vector of cutting plane coefficients, alpha[k] */
208.104 + double cut_rhs;
208.105 + /* right-hand size of the cutting plane, beta */
208.106 +};
208.107 +
208.108 +/***********************************************************************
208.109 +* NAME
208.110 +*
208.111 +* ios_mir_init - initialize MIR cut generator
208.112 +*
208.113 +* SYNOPSIS
208.114 +*
208.115 +* #include "glpios.h"
208.116 +* void *ios_mir_init(glp_tree *tree);
208.117 +*
208.118 +* DESCRIPTION
208.119 +*
208.120 +* The routine ios_mir_init initializes the MIR cut generator assuming
208.121 +* that the current subproblem is the root subproblem.
208.122 +*
208.123 +* RETURNS
208.124 +*
208.125 +* The routine ios_mir_init returns a pointer to the MIR cut generator
208.126 +* working area. */
208.127 +
208.128 +static void set_row_attrib(glp_tree *tree, struct MIR *mir)
208.129 +{ /* set global row attributes */
208.130 + glp_prob *mip = tree->mip;
208.131 + int m = mir->m;
208.132 + int k;
208.133 + for (k = 1; k <= m; k++)
208.134 + { GLPROW *row = mip->row[k];
208.135 + mir->skip[k] = 0;
208.136 + mir->isint[k] = 0;
208.137 + switch (row->type)
208.138 + { case GLP_FR:
208.139 + mir->lb[k] = -DBL_MAX, mir->ub[k] = +DBL_MAX; break;
208.140 + case GLP_LO:
208.141 + mir->lb[k] = row->lb, mir->ub[k] = +DBL_MAX; break;
208.142 + case GLP_UP:
208.143 + mir->lb[k] = -DBL_MAX, mir->ub[k] = row->ub; break;
208.144 + case GLP_DB:
208.145 + mir->lb[k] = row->lb, mir->ub[k] = row->ub; break;
208.146 + case GLP_FX:
208.147 + mir->lb[k] = mir->ub[k] = row->lb; break;
208.148 + default:
208.149 + xassert(row != row);
208.150 + }
208.151 + mir->vlb[k] = mir->vub[k] = 0;
208.152 + }
208.153 + return;
208.154 +}
208.155 +
208.156 +static void set_col_attrib(glp_tree *tree, struct MIR *mir)
208.157 +{ /* set global column attributes */
208.158 + glp_prob *mip = tree->mip;
208.159 + int m = mir->m;
208.160 + int n = mir->n;
208.161 + int k;
208.162 + for (k = m+1; k <= m+n; k++)
208.163 + { GLPCOL *col = mip->col[k-m];
208.164 + switch (col->kind)
208.165 + { case GLP_CV:
208.166 + mir->isint[k] = 0; break;
208.167 + case GLP_IV:
208.168 + mir->isint[k] = 1; break;
208.169 + default:
208.170 + xassert(col != col);
208.171 + }
208.172 + switch (col->type)
208.173 + { case GLP_FR:
208.174 + mir->lb[k] = -DBL_MAX, mir->ub[k] = +DBL_MAX; break;
208.175 + case GLP_LO:
208.176 + mir->lb[k] = col->lb, mir->ub[k] = +DBL_MAX; break;
208.177 + case GLP_UP:
208.178 + mir->lb[k] = -DBL_MAX, mir->ub[k] = col->ub; break;
208.179 + case GLP_DB:
208.180 + mir->lb[k] = col->lb, mir->ub[k] = col->ub; break;
208.181 + case GLP_FX:
208.182 + mir->lb[k] = mir->ub[k] = col->lb; break;
208.183 + default:
208.184 + xassert(col != col);
208.185 + }
208.186 + mir->vlb[k] = mir->vub[k] = 0;
208.187 + }
208.188 + return;
208.189 +}
208.190 +
208.191 +static void set_var_bounds(glp_tree *tree, struct MIR *mir)
208.192 +{ /* set variable bounds */
208.193 + glp_prob *mip = tree->mip;
208.194 + int m = mir->m;
208.195 + GLPAIJ *aij;
208.196 + int i, k1, k2;
208.197 + double a1, a2;
208.198 + for (i = 1; i <= m; i++)
208.199 + { /* we need the row to be '>= 0' or '<= 0' */
208.200 + if (!(mir->lb[i] == 0.0 && mir->ub[i] == +DBL_MAX ||
208.201 + mir->lb[i] == -DBL_MAX && mir->ub[i] == 0.0)) continue;
208.202 + /* take first term */
208.203 + aij = mip->row[i]->ptr;
208.204 + if (aij == NULL) continue;
208.205 + k1 = m + aij->col->j, a1 = aij->val;
208.206 + /* take second term */
208.207 + aij = aij->r_next;
208.208 + if (aij == NULL) continue;
208.209 + k2 = m + aij->col->j, a2 = aij->val;
208.210 + /* there must be only two terms */
208.211 + if (aij->r_next != NULL) continue;
208.212 + /* interchange terms, if needed */
208.213 + if (!mir->isint[k1] && mir->isint[k2])
208.214 + ;
208.215 + else if (mir->isint[k1] && !mir->isint[k2])
208.216 + { k2 = k1, a2 = a1;
208.217 + k1 = m + aij->col->j, a1 = aij->val;
208.218 + }
208.219 + else
208.220 + { /* both terms are either continuous or integer */
208.221 + continue;
208.222 + }
208.223 + /* x[k2] should be double-bounded */
208.224 + if (mir->lb[k2] == -DBL_MAX || mir->ub[k2] == +DBL_MAX ||
208.225 + mir->lb[k2] == mir->ub[k2]) continue;
208.226 + /* change signs, if necessary */
208.227 + if (mir->ub[i] == 0.0) a1 = - a1, a2 = - a2;
208.228 + /* now the row has the form a1 * x1 + a2 * x2 >= 0, where x1
208.229 + is continuous, x2 is integer */
208.230 + if (a1 > 0.0)
208.231 + { /* x1 >= - (a2 / a1) * x2 */
208.232 + if (mir->vlb[k1] == 0)
208.233 + { /* set variable lower bound for x1 */
208.234 + mir->lb[k1] = - a2 / a1;
208.235 + mir->vlb[k1] = k2;
208.236 + /* the row should not be used */
208.237 + mir->skip[i] = 1;
208.238 + }
208.239 + }
208.240 + else /* a1 < 0.0 */
208.241 + { /* x1 <= - (a2 / a1) * x2 */
208.242 + if (mir->vub[k1] == 0)
208.243 + { /* set variable upper bound for x1 */
208.244 + mir->ub[k1] = - a2 / a1;
208.245 + mir->vub[k1] = k2;
208.246 + /* the row should not be used */
208.247 + mir->skip[i] = 1;
208.248 + }
208.249 + }
208.250 + }
208.251 + return;
208.252 +}
208.253 +
208.254 +static void mark_useless_rows(glp_tree *tree, struct MIR *mir)
208.255 +{ /* mark rows which should not be used */
208.256 + glp_prob *mip = tree->mip;
208.257 + int m = mir->m;
208.258 + GLPAIJ *aij;
208.259 + int i, k, nv;
208.260 + for (i = 1; i <= m; i++)
208.261 + { /* free rows should not be used */
208.262 + if (mir->lb[i] == -DBL_MAX && mir->ub[i] == +DBL_MAX)
208.263 + { mir->skip[i] = 1;
208.264 + continue;
208.265 + }
208.266 + nv = 0;
208.267 + for (aij = mip->row[i]->ptr; aij != NULL; aij = aij->r_next)
208.268 + { k = m + aij->col->j;
208.269 + /* rows with free variables should not be used */
208.270 + if (mir->lb[k] == -DBL_MAX && mir->ub[k] == +DBL_MAX)
208.271 + { mir->skip[i] = 1;
208.272 + break;
208.273 + }
208.274 + /* rows with integer variables having infinite (lower or
208.275 + upper) bound should not be used */
208.276 + if (mir->isint[k] && mir->lb[k] == -DBL_MAX ||
208.277 + mir->isint[k] && mir->ub[k] == +DBL_MAX)
208.278 + { mir->skip[i] = 1;
208.279 + break;
208.280 + }
208.281 + /* count non-fixed variables */
208.282 + if (!(mir->vlb[k] == 0 && mir->vub[k] == 0 &&
208.283 + mir->lb[k] == mir->ub[k])) nv++;
208.284 + }
208.285 + /* rows with all variables fixed should not be used */
208.286 + if (nv == 0)
208.287 + { mir->skip[i] = 1;
208.288 + continue;
208.289 + }
208.290 + }
208.291 + return;
208.292 +}
208.293 +
208.294 +void *ios_mir_init(glp_tree *tree)
208.295 +{ /* initialize MIR cut generator */
208.296 + glp_prob *mip = tree->mip;
208.297 + int m = mip->m;
208.298 + int n = mip->n;
208.299 + struct MIR *mir;
208.300 +#if _MIR_DEBUG
208.301 + xprintf("ios_mir_init: warning: debug mode enabled\n");
208.302 +#endif
208.303 + /* allocate working area */
208.304 + mir = xmalloc(sizeof(struct MIR));
208.305 + mir->m = m;
208.306 + mir->n = n;
208.307 + mir->skip = xcalloc(1+m, sizeof(char));
208.308 + mir->isint = xcalloc(1+m+n, sizeof(char));
208.309 + mir->lb = xcalloc(1+m+n, sizeof(double));
208.310 + mir->vlb = xcalloc(1+m+n, sizeof(int));
208.311 + mir->ub = xcalloc(1+m+n, sizeof(double));
208.312 + mir->vub = xcalloc(1+m+n, sizeof(int));
208.313 + mir->x = xcalloc(1+m+n, sizeof(double));
208.314 + mir->agg_row = xcalloc(1+MAXAGGR, sizeof(int));
208.315 + mir->agg_vec = ios_create_vec(m+n);
208.316 + mir->subst = xcalloc(1+m+n, sizeof(char));
208.317 + mir->mod_vec = ios_create_vec(m+n);
208.318 + mir->cut_vec = ios_create_vec(m+n);
208.319 + /* set global row attributes */
208.320 + set_row_attrib(tree, mir);
208.321 + /* set global column attributes */
208.322 + set_col_attrib(tree, mir);
208.323 + /* set variable bounds */
208.324 + set_var_bounds(tree, mir);
208.325 + /* mark rows which should not be used */
208.326 + mark_useless_rows(tree, mir);
208.327 + return mir;
208.328 +}
208.329 +
208.330 +/***********************************************************************
208.331 +* NAME
208.332 +*
208.333 +* ios_mir_gen - generate MIR cuts
208.334 +*
208.335 +* SYNOPSIS
208.336 +*
208.337 +* #include "glpios.h"
208.338 +* void ios_mir_gen(glp_tree *tree, void *gen, IOSPOOL *pool);
208.339 +*
208.340 +* DESCRIPTION
208.341 +*
208.342 +* The routine ios_mir_gen generates MIR cuts for the current point and
208.343 +* adds them to the cut pool. */
208.344 +
208.345 +static void get_current_point(glp_tree *tree, struct MIR *mir)
208.346 +{ /* obtain current point */
208.347 + glp_prob *mip = tree->mip;
208.348 + int m = mir->m;
208.349 + int n = mir->n;
208.350 + int k;
208.351 + for (k = 1; k <= m; k++)
208.352 + mir->x[k] = mip->row[k]->prim;
208.353 + for (k = m+1; k <= m+n; k++)
208.354 + mir->x[k] = mip->col[k-m]->prim;
208.355 + return;
208.356 +}
208.357 +
208.358 +#if _MIR_DEBUG
208.359 +static void check_current_point(struct MIR *mir)
208.360 +{ /* check current point */
208.361 + int m = mir->m;
208.362 + int n = mir->n;
208.363 + int k, kk;
208.364 + double lb, ub, eps;
208.365 + for (k = 1; k <= m+n; k++)
208.366 + { /* determine lower bound */
208.367 + lb = mir->lb[k];
208.368 + kk = mir->vlb[k];
208.369 + if (kk != 0)
208.370 + { xassert(lb != -DBL_MAX);
208.371 + xassert(!mir->isint[k]);
208.372 + xassert(mir->isint[kk]);
208.373 + lb *= mir->x[kk];
208.374 + }
208.375 + /* check lower bound */
208.376 + if (lb != -DBL_MAX)
208.377 + { eps = 1e-6 * (1.0 + fabs(lb));
208.378 + xassert(mir->x[k] >= lb - eps);
208.379 + }
208.380 + /* determine upper bound */
208.381 + ub = mir->ub[k];
208.382 + kk = mir->vub[k];
208.383 + if (kk != 0)
208.384 + { xassert(ub != +DBL_MAX);
208.385 + xassert(!mir->isint[k]);
208.386 + xassert(mir->isint[kk]);
208.387 + ub *= mir->x[kk];
208.388 + }
208.389 + /* check upper bound */
208.390 + if (ub != +DBL_MAX)
208.391 + { eps = 1e-6 * (1.0 + fabs(ub));
208.392 + xassert(mir->x[k] <= ub + eps);
208.393 + }
208.394 + }
208.395 + return;
208.396 +}
208.397 +#endif
208.398 +
208.399 +static void initial_agg_row(glp_tree *tree, struct MIR *mir, int i)
208.400 +{ /* use original i-th row as initial aggregated constraint */
208.401 + glp_prob *mip = tree->mip;
208.402 + int m = mir->m;
208.403 + GLPAIJ *aij;
208.404 + xassert(1 <= i && i <= m);
208.405 + xassert(!mir->skip[i]);
208.406 + /* mark i-th row in order not to use it in the same aggregated
208.407 + constraint */
208.408 + mir->skip[i] = 2;
208.409 + mir->agg_cnt = 1;
208.410 + mir->agg_row[1] = i;
208.411 + /* use x[i] - sum a[i,j] * x[m+j] = 0, where x[i] is auxiliary
208.412 + variable of row i, x[m+j] are structural variables */
208.413 + ios_clear_vec(mir->agg_vec);
208.414 + ios_set_vj(mir->agg_vec, i, 1.0);
208.415 + for (aij = mip->row[i]->ptr; aij != NULL; aij = aij->r_next)
208.416 + ios_set_vj(mir->agg_vec, m + aij->col->j, - aij->val);
208.417 + mir->agg_rhs = 0.0;
208.418 +#if _MIR_DEBUG
208.419 + ios_check_vec(mir->agg_vec);
208.420 +#endif
208.421 + return;
208.422 +}
208.423 +
208.424 +#if _MIR_DEBUG
208.425 +static void check_agg_row(struct MIR *mir)
208.426 +{ /* check aggregated constraint */
208.427 + int m = mir->m;
208.428 + int n = mir->n;
208.429 + int j, k;
208.430 + double r, big;
208.431 + /* compute the residual r = sum a[k] * x[k] - b and determine
208.432 + big = max(1, |a[k]|, |b|) */
208.433 + r = 0.0, big = 1.0;
208.434 + for (j = 1; j <= mir->agg_vec->nnz; j++)
208.435 + { k = mir->agg_vec->ind[j];
208.436 + xassert(1 <= k && k <= m+n);
208.437 + r += mir->agg_vec->val[j] * mir->x[k];
208.438 + if (big < fabs(mir->agg_vec->val[j]))
208.439 + big = fabs(mir->agg_vec->val[j]);
208.440 + }
208.441 + r -= mir->agg_rhs;
208.442 + if (big < fabs(mir->agg_rhs))
208.443 + big = fabs(mir->agg_rhs);
208.444 + /* the residual must be close to zero */
208.445 + xassert(fabs(r) <= 1e-6 * big);
208.446 + return;
208.447 +}
208.448 +#endif
208.449 +
208.450 +static void subst_fixed_vars(struct MIR *mir)
208.451 +{ /* substitute fixed variables into aggregated constraint */
208.452 + int m = mir->m;
208.453 + int n = mir->n;
208.454 + int j, k;
208.455 + for (j = 1; j <= mir->agg_vec->nnz; j++)
208.456 + { k = mir->agg_vec->ind[j];
208.457 + xassert(1 <= k && k <= m+n);
208.458 + if (mir->vlb[k] == 0 && mir->vub[k] == 0 &&
208.459 + mir->lb[k] == mir->ub[k])
208.460 + { /* x[k] is fixed */
208.461 + mir->agg_rhs -= mir->agg_vec->val[j] * mir->lb[k];
208.462 + mir->agg_vec->val[j] = 0.0;
208.463 + }
208.464 + }
208.465 + /* remove terms corresponding to fixed variables */
208.466 + ios_clean_vec(mir->agg_vec, DBL_EPSILON);
208.467 +#if _MIR_DEBUG
208.468 + ios_check_vec(mir->agg_vec);
208.469 +#endif
208.470 + return;
208.471 +}
208.472 +
208.473 +static void bound_subst_heur(struct MIR *mir)
208.474 +{ /* bound substitution heuristic */
208.475 + int m = mir->m;
208.476 + int n = mir->n;
208.477 + int j, k, kk;
208.478 + double d1, d2;
208.479 + for (j = 1; j <= mir->agg_vec->nnz; j++)
208.480 + { k = mir->agg_vec->ind[j];
208.481 + xassert(1 <= k && k <= m+n);
208.482 + if (mir->isint[k]) continue; /* skip integer variable */
208.483 + /* compute distance from x[k] to its lower bound */
208.484 + kk = mir->vlb[k];
208.485 + if (kk == 0)
208.486 + { if (mir->lb[k] == -DBL_MAX)
208.487 + d1 = DBL_MAX;
208.488 + else
208.489 + d1 = mir->x[k] - mir->lb[k];
208.490 + }
208.491 + else
208.492 + { xassert(1 <= kk && kk <= m+n);
208.493 + xassert(mir->isint[kk]);
208.494 + xassert(mir->lb[k] != -DBL_MAX);
208.495 + d1 = mir->x[k] - mir->lb[k] * mir->x[kk];
208.496 + }
208.497 + /* compute distance from x[k] to its upper bound */
208.498 + kk = mir->vub[k];
208.499 + if (kk == 0)
208.500 + { if (mir->vub[k] == +DBL_MAX)
208.501 + d2 = DBL_MAX;
208.502 + else
208.503 + d2 = mir->ub[k] - mir->x[k];
208.504 + }
208.505 + else
208.506 + { xassert(1 <= kk && kk <= m+n);
208.507 + xassert(mir->isint[kk]);
208.508 + xassert(mir->ub[k] != +DBL_MAX);
208.509 + d2 = mir->ub[k] * mir->x[kk] - mir->x[k];
208.510 + }
208.511 + /* x[k] cannot be free */
208.512 + xassert(d1 != DBL_MAX || d2 != DBL_MAX);
208.513 + /* choose the bound which is closer to x[k] */
208.514 + xassert(mir->subst[k] == '?');
208.515 + if (d1 <= d2)
208.516 + mir->subst[k] = 'L';
208.517 + else
208.518 + mir->subst[k] = 'U';
208.519 + }
208.520 + return;
208.521 +}
208.522 +
208.523 +static void build_mod_row(struct MIR *mir)
208.524 +{ /* substitute bounds and build modified constraint */
208.525 + int m = mir->m;
208.526 + int n = mir->n;
208.527 + int j, jj, k, kk;
208.528 + /* initially modified constraint is aggregated constraint */
208.529 + ios_copy_vec(mir->mod_vec, mir->agg_vec);
208.530 + mir->mod_rhs = mir->agg_rhs;
208.531 +#if _MIR_DEBUG
208.532 + ios_check_vec(mir->mod_vec);
208.533 +#endif
208.534 + /* substitute bounds for continuous variables; note that due to
208.535 + substitution of variable bounds additional terms may appear in
208.536 + modified constraint */
208.537 + for (j = mir->mod_vec->nnz; j >= 1; j--)
208.538 + { k = mir->mod_vec->ind[j];
208.539 + xassert(1 <= k && k <= m+n);
208.540 + if (mir->isint[k]) continue; /* skip integer variable */
208.541 + if (mir->subst[k] == 'L')
208.542 + { /* x[k] = (lower bound) + x'[k] */
208.543 + xassert(mir->lb[k] != -DBL_MAX);
208.544 + kk = mir->vlb[k];
208.545 + if (kk == 0)
208.546 + { /* x[k] = lb[k] + x'[k] */
208.547 + mir->mod_rhs -= mir->mod_vec->val[j] * mir->lb[k];
208.548 + }
208.549 + else
208.550 + { /* x[k] = lb[k] * x[kk] + x'[k] */
208.551 + xassert(mir->isint[kk]);
208.552 + jj = mir->mod_vec->pos[kk];
208.553 + if (jj == 0)
208.554 + { ios_set_vj(mir->mod_vec, kk, 1.0);
208.555 + jj = mir->mod_vec->pos[kk];
208.556 + mir->mod_vec->val[jj] = 0.0;
208.557 + }
208.558 + mir->mod_vec->val[jj] +=
208.559 + mir->mod_vec->val[j] * mir->lb[k];
208.560 + }
208.561 + }
208.562 + else if (mir->subst[k] == 'U')
208.563 + { /* x[k] = (upper bound) - x'[k] */
208.564 + xassert(mir->ub[k] != +DBL_MAX);
208.565 + kk = mir->vub[k];
208.566 + if (kk == 0)
208.567 + { /* x[k] = ub[k] - x'[k] */
208.568 + mir->mod_rhs -= mir->mod_vec->val[j] * mir->ub[k];
208.569 + }
208.570 + else
208.571 + { /* x[k] = ub[k] * x[kk] - x'[k] */
208.572 + xassert(mir->isint[kk]);
208.573 + jj = mir->mod_vec->pos[kk];
208.574 + if (jj == 0)
208.575 + { ios_set_vj(mir->mod_vec, kk, 1.0);
208.576 + jj = mir->mod_vec->pos[kk];
208.577 + mir->mod_vec->val[jj] = 0.0;
208.578 + }
208.579 + mir->mod_vec->val[jj] +=
208.580 + mir->mod_vec->val[j] * mir->ub[k];
208.581 + }
208.582 + mir->mod_vec->val[j] = - mir->mod_vec->val[j];
208.583 + }
208.584 + else
208.585 + xassert(k != k);
208.586 + }
208.587 +#if _MIR_DEBUG
208.588 + ios_check_vec(mir->mod_vec);
208.589 +#endif
208.590 + /* substitute bounds for integer variables */
208.591 + for (j = 1; j <= mir->mod_vec->nnz; j++)
208.592 + { k = mir->mod_vec->ind[j];
208.593 + xassert(1 <= k && k <= m+n);
208.594 + if (!mir->isint[k]) continue; /* skip continuous variable */
208.595 + xassert(mir->subst[k] == '?');
208.596 + xassert(mir->vlb[k] == 0 && mir->vub[k] == 0);
208.597 + xassert(mir->lb[k] != -DBL_MAX && mir->ub[k] != +DBL_MAX);
208.598 + if (fabs(mir->lb[k]) <= fabs(mir->ub[k]))
208.599 + { /* x[k] = lb[k] + x'[k] */
208.600 + mir->subst[k] = 'L';
208.601 + mir->mod_rhs -= mir->mod_vec->val[j] * mir->lb[k];
208.602 + }
208.603 + else
208.604 + { /* x[k] = ub[k] - x'[k] */
208.605 + mir->subst[k] = 'U';
208.606 + mir->mod_rhs -= mir->mod_vec->val[j] * mir->ub[k];
208.607 + mir->mod_vec->val[j] = - mir->mod_vec->val[j];
208.608 + }
208.609 + }
208.610 +#if _MIR_DEBUG
208.611 + ios_check_vec(mir->mod_vec);
208.612 +#endif
208.613 + return;
208.614 +}
208.615 +
208.616 +#if _MIR_DEBUG
208.617 +static void check_mod_row(struct MIR *mir)
208.618 +{ /* check modified constraint */
208.619 + int m = mir->m;
208.620 + int n = mir->n;
208.621 + int j, k, kk;
208.622 + double r, big, x;
208.623 + /* compute the residual r = sum a'[k] * x'[k] - b' and determine
208.624 + big = max(1, |a[k]|, |b|) */
208.625 + r = 0.0, big = 1.0;
208.626 + for (j = 1; j <= mir->mod_vec->nnz; j++)
208.627 + { k = mir->mod_vec->ind[j];
208.628 + xassert(1 <= k && k <= m+n);
208.629 + if (mir->subst[k] == 'L')
208.630 + { /* x'[k] = x[k] - (lower bound) */
208.631 + xassert(mir->lb[k] != -DBL_MAX);
208.632 + kk = mir->vlb[k];
208.633 + if (kk == 0)
208.634 + x = mir->x[k] - mir->lb[k];
208.635 + else
208.636 + x = mir->x[k] - mir->lb[k] * mir->x[kk];
208.637 + }
208.638 + else if (mir->subst[k] == 'U')
208.639 + { /* x'[k] = (upper bound) - x[k] */
208.640 + xassert(mir->ub[k] != +DBL_MAX);
208.641 + kk = mir->vub[k];
208.642 + if (kk == 0)
208.643 + x = mir->ub[k] - mir->x[k];
208.644 + else
208.645 + x = mir->ub[k] * mir->x[kk] - mir->x[k];
208.646 + }
208.647 + else
208.648 + xassert(k != k);
208.649 + r += mir->mod_vec->val[j] * x;
208.650 + if (big < fabs(mir->mod_vec->val[j]))
208.651 + big = fabs(mir->mod_vec->val[j]);
208.652 + }
208.653 + r -= mir->mod_rhs;
208.654 + if (big < fabs(mir->mod_rhs))
208.655 + big = fabs(mir->mod_rhs);
208.656 + /* the residual must be close to zero */
208.657 + xassert(fabs(r) <= 1e-6 * big);
208.658 + return;
208.659 +}
208.660 +#endif
208.661 +
208.662 +/***********************************************************************
208.663 +* mir_ineq - construct MIR inequality
208.664 +*
208.665 +* Given the single constraint mixed integer set
208.666 +*
208.667 +* |N|
208.668 +* X = {(x,s) in Z x R : sum a[j] * x[j] <= b + s},
208.669 +* + + j in N
208.670 +*
208.671 +* this routine constructs the mixed integer rounding (MIR) inequality
208.672 +*
208.673 +* sum alpha[j] * x[j] <= beta + gamma * s,
208.674 +* j in N
208.675 +*
208.676 +* which is valid for X.
208.677 +*
208.678 +* If the MIR inequality has been successfully constructed, the routine
208.679 +* returns zero. Otherwise, if b is close to nearest integer, there may
208.680 +* be numeric difficulties due to big coefficients; so in this case the
208.681 +* routine returns non-zero. */
208.682 +
208.683 +static int mir_ineq(const int n, const double a[], const double b,
208.684 + double alpha[], double *beta, double *gamma)
208.685 +{ int j;
208.686 + double f, t;
208.687 + if (fabs(b - floor(b + .5)) < 0.01)
208.688 + return 1;
208.689 + f = b - floor(b);
208.690 + for (j = 1; j <= n; j++)
208.691 + { t = (a[j] - floor(a[j])) - f;
208.692 + if (t <= 0.0)
208.693 + alpha[j] = floor(a[j]);
208.694 + else
208.695 + alpha[j] = floor(a[j]) + t / (1.0 - f);
208.696 + }
208.697 + *beta = floor(b);
208.698 + *gamma = 1.0 / (1.0 - f);
208.699 + return 0;
208.700 +}
208.701 +
208.702 +/***********************************************************************
208.703 +* cmir_ineq - construct c-MIR inequality
208.704 +*
208.705 +* Given the mixed knapsack set
208.706 +*
208.707 +* MK |N|
208.708 +* X = {(x,s) in Z x R : sum a[j] * x[j] <= b + s,
208.709 +* + + j in N
208.710 +*
208.711 +* x[j] <= u[j]},
208.712 +*
208.713 +* a subset C of variables to be complemented, and a divisor delta > 0,
208.714 +* this routine constructs the complemented MIR (c-MIR) inequality
208.715 +*
208.716 +* sum alpha[j] * x[j] <= beta + gamma * s,
208.717 +* j in N
208.718 +* MK
208.719 +* which is valid for X .
208.720 +*
208.721 +* If the c-MIR inequality has been successfully constructed, the
208.722 +* routine returns zero. Otherwise, if there is a risk of numerical
208.723 +* difficulties due to big coefficients (see comments to the routine
208.724 +* mir_ineq), the routine cmir_ineq returns non-zero. */
208.725 +
208.726 +static int cmir_ineq(const int n, const double a[], const double b,
208.727 + const double u[], const char cset[], const double delta,
208.728 + double alpha[], double *beta, double *gamma)
208.729 +{ int j;
208.730 + double *aa, bb;
208.731 + aa = alpha, bb = b;
208.732 + for (j = 1; j <= n; j++)
208.733 + { aa[j] = a[j] / delta;
208.734 + if (cset[j])
208.735 + aa[j] = - aa[j], bb -= a[j] * u[j];
208.736 + }
208.737 + bb /= delta;
208.738 + if (mir_ineq(n, aa, bb, alpha, beta, gamma)) return 1;
208.739 + for (j = 1; j <= n; j++)
208.740 + { if (cset[j])
208.741 + alpha[j] = - alpha[j], *beta += alpha[j] * u[j];
208.742 + }
208.743 + *gamma /= delta;
208.744 + return 0;
208.745 +}
208.746 +
208.747 +/***********************************************************************
208.748 +* cmir_sep - c-MIR separation heuristic
208.749 +*
208.750 +* Given the mixed knapsack set
208.751 +*
208.752 +* MK |N|
208.753 +* X = {(x,s) in Z x R : sum a[j] * x[j] <= b + s,
208.754 +* + + j in N
208.755 +*
208.756 +* x[j] <= u[j]}
208.757 +*
208.758 +* * *
208.759 +* and a fractional point (x , s ), this routine tries to construct
208.760 +* c-MIR inequality
208.761 +*
208.762 +* sum alpha[j] * x[j] <= beta + gamma * s,
208.763 +* j in N
208.764 +* MK
208.765 +* which is valid for X and has (desirably maximal) violation at the
208.766 +* fractional point given. This is attained by choosing an appropriate
208.767 +* set C of variables to be complemented and a divisor delta > 0, which
208.768 +* together define corresponding c-MIR inequality.
208.769 +*
208.770 +* If a violated c-MIR inequality has been successfully constructed,
208.771 +* the routine returns its violation:
208.772 +*
208.773 +* * *
208.774 +* sum alpha[j] * x [j] - beta - gamma * s ,
208.775 +* j in N
208.776 +*
208.777 +* which is positive. In case of failure the routine returns zero. */
208.778 +
208.779 +struct vset { int j; double v; };
208.780 +
208.781 +static int cmir_cmp(const void *p1, const void *p2)
208.782 +{ const struct vset *v1 = p1, *v2 = p2;
208.783 + if (v1->v < v2->v) return -1;
208.784 + if (v1->v > v2->v) return +1;
208.785 + return 0;
208.786 +}
208.787 +
208.788 +static double cmir_sep(const int n, const double a[], const double b,
208.789 + const double u[], const double x[], const double s,
208.790 + double alpha[], double *beta, double *gamma)
208.791 +{ int fail, j, k, nv, v;
208.792 + double delta, eps, d_try[1+3], r, r_best;
208.793 + char *cset;
208.794 + struct vset *vset;
208.795 + /* allocate working arrays */
208.796 + cset = xcalloc(1+n, sizeof(char));
208.797 + vset = xcalloc(1+n, sizeof(struct vset));
208.798 + /* choose initial C */
208.799 + for (j = 1; j <= n; j++)
208.800 + cset[j] = (char)(x[j] >= 0.5 * u[j]);
208.801 + /* choose initial delta */
208.802 + r_best = delta = 0.0;
208.803 + for (j = 1; j <= n; j++)
208.804 + { xassert(a[j] != 0.0);
208.805 + /* if x[j] is close to its bounds, skip it */
208.806 + eps = 1e-9 * (1.0 + fabs(u[j]));
208.807 + if (x[j] < eps || x[j] > u[j] - eps) continue;
208.808 + /* try delta = |a[j]| to construct c-MIR inequality */
208.809 + fail = cmir_ineq(n, a, b, u, cset, fabs(a[j]), alpha, beta,
208.810 + gamma);
208.811 + if (fail) continue;
208.812 + /* compute violation */
208.813 + r = - (*beta) - (*gamma) * s;
208.814 + for (k = 1; k <= n; k++) r += alpha[k] * x[k];
208.815 + if (r_best < r) r_best = r, delta = fabs(a[j]);
208.816 + }
208.817 + if (r_best < 0.001) r_best = 0.0;
208.818 + if (r_best == 0.0) goto done;
208.819 + xassert(delta > 0.0);
208.820 + /* try to increase violation by dividing delta by 2, 4, and 8,
208.821 + respectively */
208.822 + d_try[1] = delta / 2.0;
208.823 + d_try[2] = delta / 4.0;
208.824 + d_try[3] = delta / 8.0;
208.825 + for (j = 1; j <= 3; j++)
208.826 + { /* construct c-MIR inequality */
208.827 + fail = cmir_ineq(n, a, b, u, cset, d_try[j], alpha, beta,
208.828 + gamma);
208.829 + if (fail) continue;
208.830 + /* compute violation */
208.831 + r = - (*beta) - (*gamma) * s;
208.832 + for (k = 1; k <= n; k++) r += alpha[k] * x[k];
208.833 + if (r_best < r) r_best = r, delta = d_try[j];
208.834 + }
208.835 + /* build subset of variables lying strictly between their bounds
208.836 + and order it by nondecreasing values of |x[j] - u[j]/2| */
208.837 + nv = 0;
208.838 + for (j = 1; j <= n; j++)
208.839 + { /* if x[j] is close to its bounds, skip it */
208.840 + eps = 1e-9 * (1.0 + fabs(u[j]));
208.841 + if (x[j] < eps || x[j] > u[j] - eps) continue;
208.842 + /* add x[j] to the subset */
208.843 + nv++;
208.844 + vset[nv].j = j;
208.845 + vset[nv].v = fabs(x[j] - 0.5 * u[j]);
208.846 + }
208.847 + qsort(&vset[1], nv, sizeof(struct vset), cmir_cmp);
208.848 + /* try to increase violation by successively complementing each
208.849 + variable in the subset */
208.850 + for (v = 1; v <= nv; v++)
208.851 + { j = vset[v].j;
208.852 + /* replace x[j] by its complement or vice versa */
208.853 + cset[j] = (char)!cset[j];
208.854 + /* construct c-MIR inequality */
208.855 + fail = cmir_ineq(n, a, b, u, cset, delta, alpha, beta, gamma);
208.856 + /* restore the variable */
208.857 + cset[j] = (char)!cset[j];
208.858 + /* do not replace the variable in case of failure */
208.859 + if (fail) continue;
208.860 + /* compute violation */
208.861 + r = - (*beta) - (*gamma) * s;
208.862 + for (k = 1; k <= n; k++) r += alpha[k] * x[k];
208.863 + if (r_best < r) r_best = r, cset[j] = (char)!cset[j];
208.864 + }
208.865 + /* construct the best c-MIR inequality chosen */
208.866 + fail = cmir_ineq(n, a, b, u, cset, delta, alpha, beta, gamma);
208.867 + xassert(!fail);
208.868 +done: /* free working arrays */
208.869 + xfree(cset);
208.870 + xfree(vset);
208.871 + /* return to the calling routine */
208.872 + return r_best;
208.873 +}
208.874 +
208.875 +static double generate(struct MIR *mir)
208.876 +{ /* try to generate violated c-MIR cut for modified constraint */
208.877 + int m = mir->m;
208.878 + int n = mir->n;
208.879 + int j, k, kk, nint;
208.880 + double s, *u, *x, *alpha, r_best = 0.0, b, beta, gamma;
208.881 + ios_copy_vec(mir->cut_vec, mir->mod_vec);
208.882 + mir->cut_rhs = mir->mod_rhs;
208.883 + /* remove small terms, which can appear due to substitution of
208.884 + variable bounds */
208.885 + ios_clean_vec(mir->cut_vec, DBL_EPSILON);
208.886 +#if _MIR_DEBUG
208.887 + ios_check_vec(mir->cut_vec);
208.888 +#endif
208.889 + /* remove positive continuous terms to obtain MK relaxation */
208.890 + for (j = 1; j <= mir->cut_vec->nnz; j++)
208.891 + { k = mir->cut_vec->ind[j];
208.892 + xassert(1 <= k && k <= m+n);
208.893 + if (!mir->isint[k] && mir->cut_vec->val[j] > 0.0)
208.894 + mir->cut_vec->val[j] = 0.0;
208.895 + }
208.896 + ios_clean_vec(mir->cut_vec, 0.0);
208.897 +#if _MIR_DEBUG
208.898 + ios_check_vec(mir->cut_vec);
208.899 +#endif
208.900 + /* move integer terms to the beginning of the sparse vector and
208.901 + determine the number of integer variables */
208.902 + nint = 0;
208.903 + for (j = 1; j <= mir->cut_vec->nnz; j++)
208.904 + { k = mir->cut_vec->ind[j];
208.905 + xassert(1 <= k && k <= m+n);
208.906 + if (mir->isint[k])
208.907 + { double temp;
208.908 + nint++;
208.909 + /* interchange elements [nint] and [j] */
208.910 + kk = mir->cut_vec->ind[nint];
208.911 + mir->cut_vec->pos[k] = nint;
208.912 + mir->cut_vec->pos[kk] = j;
208.913 + mir->cut_vec->ind[nint] = k;
208.914 + mir->cut_vec->ind[j] = kk;
208.915 + temp = mir->cut_vec->val[nint];
208.916 + mir->cut_vec->val[nint] = mir->cut_vec->val[j];
208.917 + mir->cut_vec->val[j] = temp;
208.918 + }
208.919 + }
208.920 +#if _MIR_DEBUG
208.921 + ios_check_vec(mir->cut_vec);
208.922 +#endif
208.923 + /* if there is no integer variable, nothing to generate */
208.924 + if (nint == 0) goto done;
208.925 + /* allocate working arrays */
208.926 + u = xcalloc(1+nint, sizeof(double));
208.927 + x = xcalloc(1+nint, sizeof(double));
208.928 + alpha = xcalloc(1+nint, sizeof(double));
208.929 + /* determine u and x */
208.930 + for (j = 1; j <= nint; j++)
208.931 + { k = mir->cut_vec->ind[j];
208.932 + xassert(m+1 <= k && k <= m+n);
208.933 + xassert(mir->isint[k]);
208.934 + u[j] = mir->ub[k] - mir->lb[k];
208.935 + xassert(u[j] >= 1.0);
208.936 + if (mir->subst[k] == 'L')
208.937 + x[j] = mir->x[k] - mir->lb[k];
208.938 + else if (mir->subst[k] == 'U')
208.939 + x[j] = mir->ub[k] - mir->x[k];
208.940 + else
208.941 + xassert(k != k);
208.942 + xassert(x[j] >= -0.001);
208.943 + if (x[j] < 0.0) x[j] = 0.0;
208.944 + }
208.945 + /* compute s = - sum of continuous terms */
208.946 + s = 0.0;
208.947 + for (j = nint+1; j <= mir->cut_vec->nnz; j++)
208.948 + { double x;
208.949 + k = mir->cut_vec->ind[j];
208.950 + xassert(1 <= k && k <= m+n);
208.951 + /* must be continuous */
208.952 + xassert(!mir->isint[k]);
208.953 + if (mir->subst[k] == 'L')
208.954 + { xassert(mir->lb[k] != -DBL_MAX);
208.955 + kk = mir->vlb[k];
208.956 + if (kk == 0)
208.957 + x = mir->x[k] - mir->lb[k];
208.958 + else
208.959 + x = mir->x[k] - mir->lb[k] * mir->x[kk];
208.960 + }
208.961 + else if (mir->subst[k] == 'U')
208.962 + { xassert(mir->ub[k] != +DBL_MAX);
208.963 + kk = mir->vub[k];
208.964 + if (kk == 0)
208.965 + x = mir->ub[k] - mir->x[k];
208.966 + else
208.967 + x = mir->ub[k] * mir->x[kk] - mir->x[k];
208.968 + }
208.969 + else
208.970 + xassert(k != k);
208.971 + xassert(x >= -0.001);
208.972 + if (x < 0.0) x = 0.0;
208.973 + s -= mir->cut_vec->val[j] * x;
208.974 + }
208.975 + xassert(s >= 0.0);
208.976 + /* apply heuristic to obtain most violated c-MIR inequality */
208.977 + b = mir->cut_rhs;
208.978 + r_best = cmir_sep(nint, mir->cut_vec->val, b, u, x, s, alpha,
208.979 + &beta, &gamma);
208.980 + if (r_best == 0.0) goto skip;
208.981 + xassert(r_best > 0.0);
208.982 + /* convert to raw cut */
208.983 + /* sum alpha[j] * x[j] <= beta + gamma * s */
208.984 + for (j = 1; j <= nint; j++)
208.985 + mir->cut_vec->val[j] = alpha[j];
208.986 + for (j = nint+1; j <= mir->cut_vec->nnz; j++)
208.987 + { k = mir->cut_vec->ind[j];
208.988 + if (k <= m+n) mir->cut_vec->val[j] *= gamma;
208.989 + }
208.990 + mir->cut_rhs = beta;
208.991 +#if _MIR_DEBUG
208.992 + ios_check_vec(mir->cut_vec);
208.993 +#endif
208.994 +skip: /* free working arrays */
208.995 + xfree(u);
208.996 + xfree(x);
208.997 + xfree(alpha);
208.998 +done: return r_best;
208.999 +}
208.1000 +
208.1001 +#if _MIR_DEBUG
208.1002 +static void check_raw_cut(struct MIR *mir, double r_best)
208.1003 +{ /* check raw cut before back bound substitution */
208.1004 + int m = mir->m;
208.1005 + int n = mir->n;
208.1006 + int j, k, kk;
208.1007 + double r, big, x;
208.1008 + /* compute the residual r = sum a[k] * x[k] - b and determine
208.1009 + big = max(1, |a[k]|, |b|) */
208.1010 + r = 0.0, big = 1.0;
208.1011 + for (j = 1; j <= mir->cut_vec->nnz; j++)
208.1012 + { k = mir->cut_vec->ind[j];
208.1013 + xassert(1 <= k && k <= m+n);
208.1014 + if (mir->subst[k] == 'L')
208.1015 + { xassert(mir->lb[k] != -DBL_MAX);
208.1016 + kk = mir->vlb[k];
208.1017 + if (kk == 0)
208.1018 + x = mir->x[k] - mir->lb[k];
208.1019 + else
208.1020 + x = mir->x[k] - mir->lb[k] * mir->x[kk];
208.1021 + }
208.1022 + else if (mir->subst[k] == 'U')
208.1023 + { xassert(mir->ub[k] != +DBL_MAX);
208.1024 + kk = mir->vub[k];
208.1025 + if (kk == 0)
208.1026 + x = mir->ub[k] - mir->x[k];
208.1027 + else
208.1028 + x = mir->ub[k] * mir->x[kk] - mir->x[k];
208.1029 + }
208.1030 + else
208.1031 + xassert(k != k);
208.1032 + r += mir->cut_vec->val[j] * x;
208.1033 + if (big < fabs(mir->cut_vec->val[j]))
208.1034 + big = fabs(mir->cut_vec->val[j]);
208.1035 + }
208.1036 + r -= mir->cut_rhs;
208.1037 + if (big < fabs(mir->cut_rhs))
208.1038 + big = fabs(mir->cut_rhs);
208.1039 + /* the residual must be close to r_best */
208.1040 + xassert(fabs(r - r_best) <= 1e-6 * big);
208.1041 + return;
208.1042 +}
208.1043 +#endif
208.1044 +
208.1045 +static void back_subst(struct MIR *mir)
208.1046 +{ /* back substitution of original bounds */
208.1047 + int m = mir->m;
208.1048 + int n = mir->n;
208.1049 + int j, jj, k, kk;
208.1050 + /* at first, restore bounds of integer variables (because on
208.1051 + restoring variable bounds of continuous variables we need
208.1052 + original, not shifted, bounds of integer variables) */
208.1053 + for (j = 1; j <= mir->cut_vec->nnz; j++)
208.1054 + { k = mir->cut_vec->ind[j];
208.1055 + xassert(1 <= k && k <= m+n);
208.1056 + if (!mir->isint[k]) continue; /* skip continuous */
208.1057 + if (mir->subst[k] == 'L')
208.1058 + { /* x'[k] = x[k] - lb[k] */
208.1059 + xassert(mir->lb[k] != -DBL_MAX);
208.1060 + xassert(mir->vlb[k] == 0);
208.1061 + mir->cut_rhs += mir->cut_vec->val[j] * mir->lb[k];
208.1062 + }
208.1063 + else if (mir->subst[k] == 'U')
208.1064 + { /* x'[k] = ub[k] - x[k] */
208.1065 + xassert(mir->ub[k] != +DBL_MAX);
208.1066 + xassert(mir->vub[k] == 0);
208.1067 + mir->cut_rhs -= mir->cut_vec->val[j] * mir->ub[k];
208.1068 + mir->cut_vec->val[j] = - mir->cut_vec->val[j];
208.1069 + }
208.1070 + else
208.1071 + xassert(k != k);
208.1072 + }
208.1073 + /* now restore bounds of continuous variables */
208.1074 + for (j = 1; j <= mir->cut_vec->nnz; j++)
208.1075 + { k = mir->cut_vec->ind[j];
208.1076 + xassert(1 <= k && k <= m+n);
208.1077 + if (mir->isint[k]) continue; /* skip integer */
208.1078 + if (mir->subst[k] == 'L')
208.1079 + { /* x'[k] = x[k] - (lower bound) */
208.1080 + xassert(mir->lb[k] != -DBL_MAX);
208.1081 + kk = mir->vlb[k];
208.1082 + if (kk == 0)
208.1083 + { /* x'[k] = x[k] - lb[k] */
208.1084 + mir->cut_rhs += mir->cut_vec->val[j] * mir->lb[k];
208.1085 + }
208.1086 + else
208.1087 + { /* x'[k] = x[k] - lb[k] * x[kk] */
208.1088 + jj = mir->cut_vec->pos[kk];
208.1089 +#if 0
208.1090 + xassert(jj != 0);
208.1091 +#else
208.1092 + if (jj == 0)
208.1093 + { ios_set_vj(mir->cut_vec, kk, 1.0);
208.1094 + jj = mir->cut_vec->pos[kk];
208.1095 + xassert(jj != 0);
208.1096 + mir->cut_vec->val[jj] = 0.0;
208.1097 + }
208.1098 +#endif
208.1099 + mir->cut_vec->val[jj] -= mir->cut_vec->val[j] *
208.1100 + mir->lb[k];
208.1101 + }
208.1102 + }
208.1103 + else if (mir->subst[k] == 'U')
208.1104 + { /* x'[k] = (upper bound) - x[k] */
208.1105 + xassert(mir->ub[k] != +DBL_MAX);
208.1106 + kk = mir->vub[k];
208.1107 + if (kk == 0)
208.1108 + { /* x'[k] = ub[k] - x[k] */
208.1109 + mir->cut_rhs -= mir->cut_vec->val[j] * mir->ub[k];
208.1110 + }
208.1111 + else
208.1112 + { /* x'[k] = ub[k] * x[kk] - x[k] */
208.1113 + jj = mir->cut_vec->pos[kk];
208.1114 + if (jj == 0)
208.1115 + { ios_set_vj(mir->cut_vec, kk, 1.0);
208.1116 + jj = mir->cut_vec->pos[kk];
208.1117 + xassert(jj != 0);
208.1118 + mir->cut_vec->val[jj] = 0.0;
208.1119 + }
208.1120 + mir->cut_vec->val[jj] += mir->cut_vec->val[j] *
208.1121 + mir->ub[k];
208.1122 + }
208.1123 + mir->cut_vec->val[j] = - mir->cut_vec->val[j];
208.1124 + }
208.1125 + else
208.1126 + xassert(k != k);
208.1127 + }
208.1128 +#if _MIR_DEBUG
208.1129 + ios_check_vec(mir->cut_vec);
208.1130 +#endif
208.1131 + return;
208.1132 +}
208.1133 +
208.1134 +#if _MIR_DEBUG
208.1135 +static void check_cut_row(struct MIR *mir, double r_best)
208.1136 +{ /* check the cut after back bound substitution or elimination of
208.1137 + auxiliary variables */
208.1138 + int m = mir->m;
208.1139 + int n = mir->n;
208.1140 + int j, k;
208.1141 + double r, big;
208.1142 + /* compute the residual r = sum a[k] * x[k] - b and determine
208.1143 + big = max(1, |a[k]|, |b|) */
208.1144 + r = 0.0, big = 1.0;
208.1145 + for (j = 1; j <= mir->cut_vec->nnz; j++)
208.1146 + { k = mir->cut_vec->ind[j];
208.1147 + xassert(1 <= k && k <= m+n);
208.1148 + r += mir->cut_vec->val[j] * mir->x[k];
208.1149 + if (big < fabs(mir->cut_vec->val[j]))
208.1150 + big = fabs(mir->cut_vec->val[j]);
208.1151 + }
208.1152 + r -= mir->cut_rhs;
208.1153 + if (big < fabs(mir->cut_rhs))
208.1154 + big = fabs(mir->cut_rhs);
208.1155 + /* the residual must be close to r_best */
208.1156 + xassert(fabs(r - r_best) <= 1e-6 * big);
208.1157 + return;
208.1158 +}
208.1159 +#endif
208.1160 +
208.1161 +static void subst_aux_vars(glp_tree *tree, struct MIR *mir)
208.1162 +{ /* final substitution to eliminate auxiliary variables */
208.1163 + glp_prob *mip = tree->mip;
208.1164 + int m = mir->m;
208.1165 + int n = mir->n;
208.1166 + GLPAIJ *aij;
208.1167 + int j, k, kk, jj;
208.1168 + for (j = mir->cut_vec->nnz; j >= 1; j--)
208.1169 + { k = mir->cut_vec->ind[j];
208.1170 + xassert(1 <= k && k <= m+n);
208.1171 + if (k > m) continue; /* skip structurals */
208.1172 + for (aij = mip->row[k]->ptr; aij != NULL; aij = aij->r_next)
208.1173 + { kk = m + aij->col->j; /* structural */
208.1174 + jj = mir->cut_vec->pos[kk];
208.1175 + if (jj == 0)
208.1176 + { ios_set_vj(mir->cut_vec, kk, 1.0);
208.1177 + jj = mir->cut_vec->pos[kk];
208.1178 + mir->cut_vec->val[jj] = 0.0;
208.1179 + }
208.1180 + mir->cut_vec->val[jj] += mir->cut_vec->val[j] * aij->val;
208.1181 + }
208.1182 + mir->cut_vec->val[j] = 0.0;
208.1183 + }
208.1184 + ios_clean_vec(mir->cut_vec, 0.0);
208.1185 + return;
208.1186 +}
208.1187 +
208.1188 +static void add_cut(glp_tree *tree, struct MIR *mir)
208.1189 +{ /* add constructed cut inequality to the cut pool */
208.1190 + int m = mir->m;
208.1191 + int n = mir->n;
208.1192 + int j, k, len;
208.1193 + int *ind = xcalloc(1+n, sizeof(int));
208.1194 + double *val = xcalloc(1+n, sizeof(double));
208.1195 + len = 0;
208.1196 + for (j = mir->cut_vec->nnz; j >= 1; j--)
208.1197 + { k = mir->cut_vec->ind[j];
208.1198 + xassert(m+1 <= k && k <= m+n);
208.1199 + len++, ind[len] = k - m, val[len] = mir->cut_vec->val[j];
208.1200 + }
208.1201 +#if 0
208.1202 + ios_add_cut_row(tree, pool, GLP_RF_MIR, len, ind, val, GLP_UP,
208.1203 + mir->cut_rhs);
208.1204 +#else
208.1205 + glp_ios_add_row(tree, NULL, GLP_RF_MIR, 0, len, ind, val, GLP_UP,
208.1206 + mir->cut_rhs);
208.1207 +#endif
208.1208 + xfree(ind);
208.1209 + xfree(val);
208.1210 + return;
208.1211 +}
208.1212 +
208.1213 +static int aggregate_row(glp_tree *tree, struct MIR *mir)
208.1214 +{ /* try to aggregate another row */
208.1215 + glp_prob *mip = tree->mip;
208.1216 + int m = mir->m;
208.1217 + int n = mir->n;
208.1218 + GLPAIJ *aij;
208.1219 + IOSVEC *v;
208.1220 + int ii, j, jj, k, kk, kappa = 0, ret = 0;
208.1221 + double d1, d2, d, d_max = 0.0;
208.1222 + /* choose appropriate structural variable in the aggregated row
208.1223 + to be substituted */
208.1224 + for (j = 1; j <= mir->agg_vec->nnz; j++)
208.1225 + { k = mir->agg_vec->ind[j];
208.1226 + xassert(1 <= k && k <= m+n);
208.1227 + if (k <= m) continue; /* skip auxiliary var */
208.1228 + if (mir->isint[k]) continue; /* skip integer var */
208.1229 + if (fabs(mir->agg_vec->val[j]) < 0.001) continue;
208.1230 + /* compute distance from x[k] to its lower bound */
208.1231 + kk = mir->vlb[k];
208.1232 + if (kk == 0)
208.1233 + { if (mir->lb[k] == -DBL_MAX)
208.1234 + d1 = DBL_MAX;
208.1235 + else
208.1236 + d1 = mir->x[k] - mir->lb[k];
208.1237 + }
208.1238 + else
208.1239 + { xassert(1 <= kk && kk <= m+n);
208.1240 + xassert(mir->isint[kk]);
208.1241 + xassert(mir->lb[k] != -DBL_MAX);
208.1242 + d1 = mir->x[k] - mir->lb[k] * mir->x[kk];
208.1243 + }
208.1244 + /* compute distance from x[k] to its upper bound */
208.1245 + kk = mir->vub[k];
208.1246 + if (kk == 0)
208.1247 + { if (mir->vub[k] == +DBL_MAX)
208.1248 + d2 = DBL_MAX;
208.1249 + else
208.1250 + d2 = mir->ub[k] - mir->x[k];
208.1251 + }
208.1252 + else
208.1253 + { xassert(1 <= kk && kk <= m+n);
208.1254 + xassert(mir->isint[kk]);
208.1255 + xassert(mir->ub[k] != +DBL_MAX);
208.1256 + d2 = mir->ub[k] * mir->x[kk] - mir->x[k];
208.1257 + }
208.1258 + /* x[k] cannot be free */
208.1259 + xassert(d1 != DBL_MAX || d2 != DBL_MAX);
208.1260 + /* d = min(d1, d2) */
208.1261 + d = (d1 <= d2 ? d1 : d2);
208.1262 + xassert(d != DBL_MAX);
208.1263 + /* should not be close to corresponding bound */
208.1264 + if (d < 0.001) continue;
208.1265 + if (d_max < d) d_max = d, kappa = k;
208.1266 + }
208.1267 + if (kappa == 0)
208.1268 + { /* nothing chosen */
208.1269 + ret = 1;
208.1270 + goto done;
208.1271 + }
208.1272 + /* x[kappa] has been chosen */
208.1273 + xassert(m+1 <= kappa && kappa <= m+n);
208.1274 + xassert(!mir->isint[kappa]);
208.1275 + /* find another row, which have not been used yet, to eliminate
208.1276 + x[kappa] from the aggregated row */
208.1277 + for (ii = 1; ii <= m; ii++)
208.1278 + { if (mir->skip[ii]) continue;
208.1279 + for (aij = mip->row[ii]->ptr; aij != NULL; aij = aij->r_next)
208.1280 + if (aij->col->j == kappa - m) break;
208.1281 + if (aij != NULL && fabs(aij->val) >= 0.001) break;
208.1282 + }
208.1283 + if (ii > m)
208.1284 + { /* nothing found */
208.1285 + ret = 2;
208.1286 + goto done;
208.1287 + }
208.1288 + /* row ii has been found; include it in the aggregated list */
208.1289 + mir->agg_cnt++;
208.1290 + xassert(mir->agg_cnt <= MAXAGGR);
208.1291 + mir->agg_row[mir->agg_cnt] = ii;
208.1292 + mir->skip[ii] = 2;
208.1293 + /* v := new row */
208.1294 + v = ios_create_vec(m+n);
208.1295 + ios_set_vj(v, ii, 1.0);
208.1296 + for (aij = mip->row[ii]->ptr; aij != NULL; aij = aij->r_next)
208.1297 + ios_set_vj(v, m + aij->col->j, - aij->val);
208.1298 +#if _MIR_DEBUG
208.1299 + ios_check_vec(v);
208.1300 +#endif
208.1301 + /* perform gaussian elimination to remove x[kappa] */
208.1302 + j = mir->agg_vec->pos[kappa];
208.1303 + xassert(j != 0);
208.1304 + jj = v->pos[kappa];
208.1305 + xassert(jj != 0);
208.1306 + ios_linear_comb(mir->agg_vec,
208.1307 + - mir->agg_vec->val[j] / v->val[jj], v);
208.1308 + ios_delete_vec(v);
208.1309 + ios_set_vj(mir->agg_vec, kappa, 0.0);
208.1310 +#if _MIR_DEBUG
208.1311 + ios_check_vec(mir->agg_vec);
208.1312 +#endif
208.1313 +done: return ret;
208.1314 +}
208.1315 +
208.1316 +void ios_mir_gen(glp_tree *tree, void *gen)
208.1317 +{ /* main routine to generate MIR cuts */
208.1318 + glp_prob *mip = tree->mip;
208.1319 + struct MIR *mir = gen;
208.1320 + int m = mir->m;
208.1321 + int n = mir->n;
208.1322 + int i;
208.1323 + double r_best;
208.1324 + xassert(mip->m >= m);
208.1325 + xassert(mip->n == n);
208.1326 + /* obtain current point */
208.1327 + get_current_point(tree, mir);
208.1328 +#if _MIR_DEBUG
208.1329 + /* check current point */
208.1330 + check_current_point(mir);
208.1331 +#endif
208.1332 + /* reset bound substitution flags */
208.1333 + memset(&mir->subst[1], '?', m+n);
208.1334 + /* try to generate a set of violated MIR cuts */
208.1335 + for (i = 1; i <= m; i++)
208.1336 + { if (mir->skip[i]) continue;
208.1337 + /* use original i-th row as initial aggregated constraint */
208.1338 + initial_agg_row(tree, mir, i);
208.1339 +loop: ;
208.1340 +#if _MIR_DEBUG
208.1341 + /* check aggregated row */
208.1342 + check_agg_row(mir);
208.1343 +#endif
208.1344 + /* substitute fixed variables into aggregated constraint */
208.1345 + subst_fixed_vars(mir);
208.1346 +#if _MIR_DEBUG
208.1347 + /* check aggregated row */
208.1348 + check_agg_row(mir);
208.1349 +#endif
208.1350 +#if _MIR_DEBUG
208.1351 + /* check bound substitution flags */
208.1352 + { int k;
208.1353 + for (k = 1; k <= m+n; k++)
208.1354 + xassert(mir->subst[k] == '?');
208.1355 + }
208.1356 +#endif
208.1357 + /* apply bound substitution heuristic */
208.1358 + bound_subst_heur(mir);
208.1359 + /* substitute bounds and build modified constraint */
208.1360 + build_mod_row(mir);
208.1361 +#if _MIR_DEBUG
208.1362 + /* check modified row */
208.1363 + check_mod_row(mir);
208.1364 +#endif
208.1365 + /* try to generate violated c-MIR cut for modified row */
208.1366 + r_best = generate(mir);
208.1367 + if (r_best > 0.0)
208.1368 + { /* success */
208.1369 +#if _MIR_DEBUG
208.1370 + /* check raw cut before back bound substitution */
208.1371 + check_raw_cut(mir, r_best);
208.1372 +#endif
208.1373 + /* back substitution of original bounds */
208.1374 + back_subst(mir);
208.1375 +#if _MIR_DEBUG
208.1376 + /* check the cut after back bound substitution */
208.1377 + check_cut_row(mir, r_best);
208.1378 +#endif
208.1379 + /* final substitution to eliminate auxiliary variables */
208.1380 + subst_aux_vars(tree, mir);
208.1381 +#if _MIR_DEBUG
208.1382 + /* check the cut after elimination of auxiliaries */
208.1383 + check_cut_row(mir, r_best);
208.1384 +#endif
208.1385 + /* add constructed cut inequality to the cut pool */
208.1386 + add_cut(tree, mir);
208.1387 + }
208.1388 + /* reset bound substitution flags */
208.1389 + { int j, k;
208.1390 + for (j = 1; j <= mir->mod_vec->nnz; j++)
208.1391 + { k = mir->mod_vec->ind[j];
208.1392 + xassert(1 <= k && k <= m+n);
208.1393 + xassert(mir->subst[k] != '?');
208.1394 + mir->subst[k] = '?';
208.1395 + }
208.1396 + }
208.1397 + if (r_best == 0.0)
208.1398 + { /* failure */
208.1399 + if (mir->agg_cnt < MAXAGGR)
208.1400 + { /* try to aggregate another row */
208.1401 + if (aggregate_row(tree, mir) == 0) goto loop;
208.1402 + }
208.1403 + }
208.1404 + /* unmark rows used in the aggregated constraint */
208.1405 + { int k, ii;
208.1406 + for (k = 1; k <= mir->agg_cnt; k++)
208.1407 + { ii = mir->agg_row[k];
208.1408 + xassert(1 <= ii && ii <= m);
208.1409 + xassert(mir->skip[ii] == 2);
208.1410 + mir->skip[ii] = 0;
208.1411 + }
208.1412 + }
208.1413 + }
208.1414 + return;
208.1415 +}
208.1416 +
208.1417 +/***********************************************************************
208.1418 +* NAME
208.1419 +*
208.1420 +* ios_mir_term - terminate MIR cut generator
208.1421 +*
208.1422 +* SYNOPSIS
208.1423 +*
208.1424 +* #include "glpios.h"
208.1425 +* void ios_mir_term(void *gen);
208.1426 +*
208.1427 +* DESCRIPTION
208.1428 +*
208.1429 +* The routine ios_mir_term deletes the MIR cut generator working area
208.1430 +* freeing all the memory allocated to it. */
208.1431 +
208.1432 +void ios_mir_term(void *gen)
208.1433 +{ struct MIR *mir = gen;
208.1434 + xfree(mir->skip);
208.1435 + xfree(mir->isint);
208.1436 + xfree(mir->lb);
208.1437 + xfree(mir->vlb);
208.1438 + xfree(mir->ub);
208.1439 + xfree(mir->vub);
208.1440 + xfree(mir->x);
208.1441 + xfree(mir->agg_row);
208.1442 + ios_delete_vec(mir->agg_vec);
208.1443 + xfree(mir->subst);
208.1444 + ios_delete_vec(mir->mod_vec);
208.1445 + ios_delete_vec(mir->cut_vec);
208.1446 + xfree(mir);
208.1447 + return;
208.1448 +}
208.1449 +
208.1450 +/* eof */
209.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
209.2 +++ b/src/glpios07.c Mon Dec 06 13:09:21 2010 +0100
209.3 @@ -0,0 +1,554 @@
209.4 +/* glpios07.c (mixed cover cut generator) */
209.5 +
209.6 +/***********************************************************************
209.7 +* This code is part of GLPK (GNU Linear Programming Kit).
209.8 +*
209.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
209.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
209.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
209.12 +* E-mail: <mao@gnu.org>.
209.13 +*
209.14 +* GLPK is free software: you can redistribute it and/or modify it
209.15 +* under the terms of the GNU General Public License as published by
209.16 +* the Free Software Foundation, either version 3 of the License, or
209.17 +* (at your option) any later version.
209.18 +*
209.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
209.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
209.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
209.22 +* License for more details.
209.23 +*
209.24 +* You should have received a copy of the GNU General Public License
209.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
209.26 +***********************************************************************/
209.27 +
209.28 +#include "glpios.h"
209.29 +
209.30 +/*----------------------------------------------------------------------
209.31 +-- COVER INEQUALITIES
209.32 +--
209.33 +-- Consider the set of feasible solutions to 0-1 knapsack problem:
209.34 +--
209.35 +-- sum a[j]*x[j] <= b, (1)
209.36 +-- j in J
209.37 +--
209.38 +-- x[j] is binary, (2)
209.39 +--
209.40 +-- where, wlog, we assume that a[j] > 0 (since 0-1 variables can be
209.41 +-- complemented) and a[j] <= b (since a[j] > b implies x[j] = 0).
209.42 +--
209.43 +-- A set C within J is called a cover if
209.44 +--
209.45 +-- sum a[j] > b. (3)
209.46 +-- j in C
209.47 +--
209.48 +-- For any cover C the inequality
209.49 +--
209.50 +-- sum x[j] <= |C| - 1 (4)
209.51 +-- j in C
209.52 +--
209.53 +-- is called a cover inequality and is valid for (1)-(2).
209.54 +--
209.55 +-- MIXED COVER INEQUALITIES
209.56 +--
209.57 +-- Consider the set of feasible solutions to mixed knapsack problem:
209.58 +--
209.59 +-- sum a[j]*x[j] + y <= b, (5)
209.60 +-- j in J
209.61 +--
209.62 +-- x[j] is binary, (6)
209.63 +--
209.64 +-- 0 <= y <= u is continuous, (7)
209.65 +--
209.66 +-- where again we assume that a[j] > 0.
209.67 +--
209.68 +-- Let C within J be some set. From (1)-(4) it follows that
209.69 +--
209.70 +-- sum a[j] > b - y (8)
209.71 +-- j in C
209.72 +--
209.73 +-- implies
209.74 +--
209.75 +-- sum x[j] <= |C| - 1. (9)
209.76 +-- j in C
209.77 +--
209.78 +-- Thus, we need to modify the inequality (9) in such a way that it be
209.79 +-- a constraint only if the condition (8) is satisfied.
209.80 +--
209.81 +-- Consider the following inequality:
209.82 +--
209.83 +-- sum x[j] <= |C| - t. (10)
209.84 +-- j in C
209.85 +--
209.86 +-- If 0 < t <= 1, then (10) is equivalent to (9), because all x[j] are
209.87 +-- binary variables. On the other hand, if t <= 0, (10) being satisfied
209.88 +-- for any values of x[j] is not a constraint.
209.89 +--
209.90 +-- Let
209.91 +--
209.92 +-- t' = sum a[j] + y - b. (11)
209.93 +-- j in C
209.94 +--
209.95 +-- It is understood that the condition t' > 0 is equivalent to (8).
209.96 +-- Besides, from (6)-(7) it follows that t' has an implied upper bound:
209.97 +--
209.98 +-- t'max = sum a[j] + u - b. (12)
209.99 +-- j in C
209.100 +--
209.101 +-- This allows to express the parameter t having desired properties:
209.102 +--
209.103 +-- t = t' / t'max. (13)
209.104 +--
209.105 +-- In fact, t <= 1 by definition, and t > 0 being equivalent to t' > 0
209.106 +-- is equivalent to (8).
209.107 +--
209.108 +-- Thus, the inequality (10), where t is given by formula (13) is valid
209.109 +-- for (5)-(7).
209.110 +--
209.111 +-- Note that if u = 0, then y = 0, so t = 1, and the conditions (8) and
209.112 +-- (10) is transformed to the conditions (3) and (4).
209.113 +--
209.114 +-- GENERATING MIXED COVER CUTS
209.115 +--
209.116 +-- To generate a mixed cover cut in the form (10) we need to find such
209.117 +-- set C which satisfies to the inequality (8) and for which, in turn,
209.118 +-- the inequality (10) is violated in the current point.
209.119 +--
209.120 +-- Substituting t from (13) to (10) gives:
209.121 +--
209.122 +-- 1
209.123 +-- sum x[j] <= |C| - ----- (sum a[j] + y - b), (14)
209.124 +-- j in C t'max j in C
209.125 +--
209.126 +-- and finally we have the cut inequality in the standard form:
209.127 +--
209.128 +-- sum x[j] + alfa * y <= beta, (15)
209.129 +-- j in C
209.130 +--
209.131 +-- where:
209.132 +--
209.133 +-- alfa = 1 / t'max, (16)
209.134 +--
209.135 +-- beta = |C| - alfa * (sum a[j] - b). (17)
209.136 +-- j in C */
209.137 +
209.138 +#if 1
209.139 +#define MAXTRY 1000
209.140 +#else
209.141 +#define MAXTRY 10000
209.142 +#endif
209.143 +
209.144 +static int cover2(int n, double a[], double b, double u, double x[],
209.145 + double y, int cov[], double *_alfa, double *_beta)
209.146 +{ /* try to generate mixed cover cut using two-element cover */
209.147 + int i, j, try = 0, ret = 0;
209.148 + double eps, alfa, beta, temp, rmax = 0.001;
209.149 + eps = 0.001 * (1.0 + fabs(b));
209.150 + for (i = 0+1; i <= n; i++)
209.151 + for (j = i+1; j <= n; j++)
209.152 + { /* C = {i, j} */
209.153 + try++;
209.154 + if (try > MAXTRY) goto done;
209.155 + /* check if condition (8) is satisfied */
209.156 + if (a[i] + a[j] + y > b + eps)
209.157 + { /* compute parameters for inequality (15) */
209.158 + temp = a[i] + a[j] - b;
209.159 + alfa = 1.0 / (temp + u);
209.160 + beta = 2.0 - alfa * temp;
209.161 + /* compute violation of inequality (15) */
209.162 + temp = x[i] + x[j] + alfa * y - beta;
209.163 + /* choose C providing maximum violation */
209.164 + if (rmax < temp)
209.165 + { rmax = temp;
209.166 + cov[1] = i;
209.167 + cov[2] = j;
209.168 + *_alfa = alfa;
209.169 + *_beta = beta;
209.170 + ret = 1;
209.171 + }
209.172 + }
209.173 + }
209.174 +done: return ret;
209.175 +}
209.176 +
209.177 +static int cover3(int n, double a[], double b, double u, double x[],
209.178 + double y, int cov[], double *_alfa, double *_beta)
209.179 +{ /* try to generate mixed cover cut using three-element cover */
209.180 + int i, j, k, try = 0, ret = 0;
209.181 + double eps, alfa, beta, temp, rmax = 0.001;
209.182 + eps = 0.001 * (1.0 + fabs(b));
209.183 + for (i = 0+1; i <= n; i++)
209.184 + for (j = i+1; j <= n; j++)
209.185 + for (k = j+1; k <= n; k++)
209.186 + { /* C = {i, j, k} */
209.187 + try++;
209.188 + if (try > MAXTRY) goto done;
209.189 + /* check if condition (8) is satisfied */
209.190 + if (a[i] + a[j] + a[k] + y > b + eps)
209.191 + { /* compute parameters for inequality (15) */
209.192 + temp = a[i] + a[j] + a[k] - b;
209.193 + alfa = 1.0 / (temp + u);
209.194 + beta = 3.0 - alfa * temp;
209.195 + /* compute violation of inequality (15) */
209.196 + temp = x[i] + x[j] + x[k] + alfa * y - beta;
209.197 + /* choose C providing maximum violation */
209.198 + if (rmax < temp)
209.199 + { rmax = temp;
209.200 + cov[1] = i;
209.201 + cov[2] = j;
209.202 + cov[3] = k;
209.203 + *_alfa = alfa;
209.204 + *_beta = beta;
209.205 + ret = 1;
209.206 + }
209.207 + }
209.208 + }
209.209 +done: return ret;
209.210 +}
209.211 +
209.212 +static int cover4(int n, double a[], double b, double u, double x[],
209.213 + double y, int cov[], double *_alfa, double *_beta)
209.214 +{ /* try to generate mixed cover cut using four-element cover */
209.215 + int i, j, k, l, try = 0, ret = 0;
209.216 + double eps, alfa, beta, temp, rmax = 0.001;
209.217 + eps = 0.001 * (1.0 + fabs(b));
209.218 + for (i = 0+1; i <= n; i++)
209.219 + for (j = i+1; j <= n; j++)
209.220 + for (k = j+1; k <= n; k++)
209.221 + for (l = k+1; l <= n; l++)
209.222 + { /* C = {i, j, k, l} */
209.223 + try++;
209.224 + if (try > MAXTRY) goto done;
209.225 + /* check if condition (8) is satisfied */
209.226 + if (a[i] + a[j] + a[k] + a[l] + y > b + eps)
209.227 + { /* compute parameters for inequality (15) */
209.228 + temp = a[i] + a[j] + a[k] + a[l] - b;
209.229 + alfa = 1.0 / (temp + u);
209.230 + beta = 4.0 - alfa * temp;
209.231 + /* compute violation of inequality (15) */
209.232 + temp = x[i] + x[j] + x[k] + x[l] + alfa * y - beta;
209.233 + /* choose C providing maximum violation */
209.234 + if (rmax < temp)
209.235 + { rmax = temp;
209.236 + cov[1] = i;
209.237 + cov[2] = j;
209.238 + cov[3] = k;
209.239 + cov[4] = l;
209.240 + *_alfa = alfa;
209.241 + *_beta = beta;
209.242 + ret = 1;
209.243 + }
209.244 + }
209.245 + }
209.246 +done: return ret;
209.247 +}
209.248 +
209.249 +static int cover(int n, double a[], double b, double u, double x[],
209.250 + double y, int cov[], double *alfa, double *beta)
209.251 +{ /* try to generate mixed cover cut;
209.252 + input (see (5)):
209.253 + n is the number of binary variables;
209.254 + a[1:n] are coefficients at binary variables;
209.255 + b is the right-hand side;
209.256 + u is upper bound of continuous variable;
209.257 + x[1:n] are values of binary variables at current point;
209.258 + y is value of continuous variable at current point;
209.259 + output (see (15), (16), (17)):
209.260 + cov[1:r] are indices of binary variables included in cover C,
209.261 + where r is the set cardinality returned on exit;
209.262 + alfa coefficient at continuous variable;
209.263 + beta is the right-hand side; */
209.264 + int j;
209.265 + /* perform some sanity checks */
209.266 + xassert(n >= 2);
209.267 + for (j = 1; j <= n; j++) xassert(a[j] > 0.0);
209.268 +#if 1 /* ??? */
209.269 + xassert(b > -1e-5);
209.270 +#else
209.271 + xassert(b > 0.0);
209.272 +#endif
209.273 + xassert(u >= 0.0);
209.274 + for (j = 1; j <= n; j++) xassert(0.0 <= x[j] && x[j] <= 1.0);
209.275 + xassert(0.0 <= y && y <= u);
209.276 + /* try to generate mixed cover cut */
209.277 + if (cover2(n, a, b, u, x, y, cov, alfa, beta)) return 2;
209.278 + if (cover3(n, a, b, u, x, y, cov, alfa, beta)) return 3;
209.279 + if (cover4(n, a, b, u, x, y, cov, alfa, beta)) return 4;
209.280 + return 0;
209.281 +}
209.282 +
209.283 +/*----------------------------------------------------------------------
209.284 +-- lpx_cover_cut - generate mixed cover cut.
209.285 +--
209.286 +-- SYNOPSIS
209.287 +--
209.288 +-- #include "glplpx.h"
209.289 +-- int lpx_cover_cut(LPX *lp, int len, int ind[], double val[],
209.290 +-- double work[]);
209.291 +--
209.292 +-- DESCRIPTION
209.293 +--
209.294 +-- The routine lpx_cover_cut generates a mixed cover cut for a given
209.295 +-- row of the MIP problem.
209.296 +--
209.297 +-- The given row of the MIP problem should be explicitly specified in
209.298 +-- the form:
209.299 +--
209.300 +-- sum{j in J} a[j]*x[j] <= b. (1)
209.301 +--
209.302 +-- On entry indices (ordinal numbers) of structural variables, which
209.303 +-- have non-zero constraint coefficients, should be placed in locations
209.304 +-- ind[1], ..., ind[len], and corresponding constraint coefficients
209.305 +-- should be placed in locations val[1], ..., val[len]. The right-hand
209.306 +-- side b should be stored in location val[0].
209.307 +--
209.308 +-- The working array work should have at least nb locations, where nb
209.309 +-- is the number of binary variables in (1).
209.310 +--
209.311 +-- The routine generates a mixed cover cut in the same form as (1) and
209.312 +-- stores the cut coefficients and right-hand side in the same way as
209.313 +-- just described above.
209.314 +--
209.315 +-- RETURNS
209.316 +--
209.317 +-- If the cutting plane has been successfully generated, the routine
209.318 +-- returns 1 <= len' <= n, which is the number of non-zero coefficients
209.319 +-- in the inequality constraint. Otherwise, the routine returns zero. */
209.320 +
209.321 +static int lpx_cover_cut(LPX *lp, int len, int ind[], double val[],
209.322 + double work[])
209.323 +{ int cov[1+4], j, k, nb, newlen, r;
209.324 + double f_min, f_max, alfa, beta, u, *x = work, y;
209.325 + /* substitute and remove fixed variables */
209.326 + newlen = 0;
209.327 + for (k = 1; k <= len; k++)
209.328 + { j = ind[k];
209.329 + if (lpx_get_col_type(lp, j) == LPX_FX)
209.330 + val[0] -= val[k] * lpx_get_col_lb(lp, j);
209.331 + else
209.332 + { newlen++;
209.333 + ind[newlen] = ind[k];
209.334 + val[newlen] = val[k];
209.335 + }
209.336 + }
209.337 + len = newlen;
209.338 + /* move binary variables to the beginning of the list so that
209.339 + elements 1, 2, ..., nb correspond to binary variables, and
209.340 + elements nb+1, nb+2, ..., len correspond to rest variables */
209.341 + nb = 0;
209.342 + for (k = 1; k <= len; k++)
209.343 + { j = ind[k];
209.344 + if (lpx_get_col_kind(lp, j) == LPX_IV &&
209.345 + lpx_get_col_type(lp, j) == LPX_DB &&
209.346 + lpx_get_col_lb(lp, j) == 0.0 &&
209.347 + lpx_get_col_ub(lp, j) == 1.0)
209.348 + { /* binary variable */
209.349 + int ind_k;
209.350 + double val_k;
209.351 + nb++;
209.352 + ind_k = ind[nb], val_k = val[nb];
209.353 + ind[nb] = ind[k], val[nb] = val[k];
209.354 + ind[k] = ind_k, val[k] = val_k;
209.355 + }
209.356 + }
209.357 + /* now the specified row has the form:
209.358 + sum a[j]*x[j] + sum a[j]*y[j] <= b,
209.359 + where x[j] are binary variables, y[j] are rest variables */
209.360 + /* at least two binary variables are needed */
209.361 + if (nb < 2) return 0;
209.362 + /* compute implied lower and upper bounds for sum a[j]*y[j] */
209.363 + f_min = f_max = 0.0;
209.364 + for (k = nb+1; k <= len; k++)
209.365 + { j = ind[k];
209.366 + /* both bounds must be finite */
209.367 + if (lpx_get_col_type(lp, j) != LPX_DB) return 0;
209.368 + if (val[k] > 0.0)
209.369 + { f_min += val[k] * lpx_get_col_lb(lp, j);
209.370 + f_max += val[k] * lpx_get_col_ub(lp, j);
209.371 + }
209.372 + else
209.373 + { f_min += val[k] * lpx_get_col_ub(lp, j);
209.374 + f_max += val[k] * lpx_get_col_lb(lp, j);
209.375 + }
209.376 + }
209.377 + /* sum a[j]*x[j] + sum a[j]*y[j] <= b ===>
209.378 + sum a[j]*x[j] + (sum a[j]*y[j] - f_min) <= b - f_min ===>
209.379 + sum a[j]*x[j] + y <= b - f_min,
209.380 + where y = sum a[j]*y[j] - f_min;
209.381 + note that 0 <= y <= u, u = f_max - f_min */
209.382 + /* determine upper bound of y */
209.383 + u = f_max - f_min;
209.384 + /* determine value of y at the current point */
209.385 + y = 0.0;
209.386 + for (k = nb+1; k <= len; k++)
209.387 + { j = ind[k];
209.388 + y += val[k] * lpx_get_col_prim(lp, j);
209.389 + }
209.390 + y -= f_min;
209.391 + if (y < 0.0) y = 0.0;
209.392 + if (y > u) y = u;
209.393 + /* modify the right-hand side b */
209.394 + val[0] -= f_min;
209.395 + /* now the transformed row has the form:
209.396 + sum a[j]*x[j] + y <= b, where 0 <= y <= u */
209.397 + /* determine values of x[j] at the current point */
209.398 + for (k = 1; k <= nb; k++)
209.399 + { j = ind[k];
209.400 + x[k] = lpx_get_col_prim(lp, j);
209.401 + if (x[k] < 0.0) x[k] = 0.0;
209.402 + if (x[k] > 1.0) x[k] = 1.0;
209.403 + }
209.404 + /* if a[j] < 0, replace x[j] by its complement 1 - x'[j] */
209.405 + for (k = 1; k <= nb; k++)
209.406 + { if (val[k] < 0.0)
209.407 + { ind[k] = - ind[k];
209.408 + val[k] = - val[k];
209.409 + val[0] += val[k];
209.410 + x[k] = 1.0 - x[k];
209.411 + }
209.412 + }
209.413 + /* try to generate a mixed cover cut for the transformed row */
209.414 + r = cover(nb, val, val[0], u, x, y, cov, &alfa, &beta);
209.415 + if (r == 0) return 0;
209.416 + xassert(2 <= r && r <= 4);
209.417 + /* now the cut is in the form:
209.418 + sum{j in C} x[j] + alfa * y <= beta */
209.419 + /* store the right-hand side beta */
209.420 + ind[0] = 0, val[0] = beta;
209.421 + /* restore the original ordinal numbers of x[j] */
209.422 + for (j = 1; j <= r; j++) cov[j] = ind[cov[j]];
209.423 + /* store cut coefficients at binary variables complementing back
209.424 + the variables having negative row coefficients */
209.425 + xassert(r <= nb);
209.426 + for (k = 1; k <= r; k++)
209.427 + { if (cov[k] > 0)
209.428 + { ind[k] = +cov[k];
209.429 + val[k] = +1.0;
209.430 + }
209.431 + else
209.432 + { ind[k] = -cov[k];
209.433 + val[k] = -1.0;
209.434 + val[0] -= 1.0;
209.435 + }
209.436 + }
209.437 + /* substitute y = sum a[j]*y[j] - f_min */
209.438 + for (k = nb+1; k <= len; k++)
209.439 + { r++;
209.440 + ind[r] = ind[k];
209.441 + val[r] = alfa * val[k];
209.442 + }
209.443 + val[0] += alfa * f_min;
209.444 + xassert(r <= len);
209.445 + len = r;
209.446 + return len;
209.447 +}
209.448 +
209.449 +/*----------------------------------------------------------------------
209.450 +-- lpx_eval_row - compute explictily specified row.
209.451 +--
209.452 +-- SYNOPSIS
209.453 +--
209.454 +-- #include "glplpx.h"
209.455 +-- double lpx_eval_row(LPX *lp, int len, int ind[], double val[]);
209.456 +--
209.457 +-- DESCRIPTION
209.458 +--
209.459 +-- The routine lpx_eval_row computes the primal value of an explicitly
209.460 +-- specified row using current values of structural variables.
209.461 +--
209.462 +-- The explicitly specified row may be thought as a linear form:
209.463 +--
209.464 +-- y = a[1]*x[m+1] + a[2]*x[m+2] + ... + a[n]*x[m+n],
209.465 +--
209.466 +-- where y is an auxiliary variable for this row, a[j] are coefficients
209.467 +-- of the linear form, x[m+j] are structural variables.
209.468 +--
209.469 +-- On entry column indices and numerical values of non-zero elements of
209.470 +-- the row should be stored in locations ind[1], ..., ind[len] and
209.471 +-- val[1], ..., val[len], where len is the number of non-zero elements.
209.472 +-- The array ind and val are not changed on exit.
209.473 +--
209.474 +-- RETURNS
209.475 +--
209.476 +-- The routine returns a computed value of y, the auxiliary variable of
209.477 +-- the specified row. */
209.478 +
209.479 +static double lpx_eval_row(LPX *lp, int len, int ind[], double val[])
209.480 +{ int n = lpx_get_num_cols(lp);
209.481 + int j, k;
209.482 + double sum = 0.0;
209.483 + if (len < 0)
209.484 + xerror("lpx_eval_row: len = %d; invalid row length\n", len);
209.485 + for (k = 1; k <= len; k++)
209.486 + { j = ind[k];
209.487 + if (!(1 <= j && j <= n))
209.488 + xerror("lpx_eval_row: j = %d; column number out of range\n",
209.489 + j);
209.490 + sum += val[k] * lpx_get_col_prim(lp, j);
209.491 + }
209.492 + return sum;
209.493 +}
209.494 +
209.495 +/***********************************************************************
209.496 +* NAME
209.497 +*
209.498 +* ios_cov_gen - generate mixed cover cuts
209.499 +*
209.500 +* SYNOPSIS
209.501 +*
209.502 +* #include "glpios.h"
209.503 +* void ios_cov_gen(glp_tree *tree);
209.504 +*
209.505 +* DESCRIPTION
209.506 +*
209.507 +* The routine ios_cov_gen generates mixed cover cuts for the current
209.508 +* point and adds them to the cut pool. */
209.509 +
209.510 +void ios_cov_gen(glp_tree *tree)
209.511 +{ glp_prob *prob = tree->mip;
209.512 + int m = lpx_get_num_rows(prob);
209.513 + int n = lpx_get_num_cols(prob);
209.514 + int i, k, type, kase, len, *ind;
209.515 + double r, *val, *work;
209.516 + xassert(lpx_get_status(prob) == LPX_OPT);
209.517 + /* allocate working arrays */
209.518 + ind = xcalloc(1+n, sizeof(int));
209.519 + val = xcalloc(1+n, sizeof(double));
209.520 + work = xcalloc(1+n, sizeof(double));
209.521 + /* look through all rows */
209.522 + for (i = 1; i <= m; i++)
209.523 + for (kase = 1; kase <= 2; kase++)
209.524 + { type = lpx_get_row_type(prob, i);
209.525 + if (kase == 1)
209.526 + { /* consider rows of '<=' type */
209.527 + if (!(type == LPX_UP || type == LPX_DB)) continue;
209.528 + len = lpx_get_mat_row(prob, i, ind, val);
209.529 + val[0] = lpx_get_row_ub(prob, i);
209.530 + }
209.531 + else
209.532 + { /* consider rows of '>=' type */
209.533 + if (!(type == LPX_LO || type == LPX_DB)) continue;
209.534 + len = lpx_get_mat_row(prob, i, ind, val);
209.535 + for (k = 1; k <= len; k++) val[k] = - val[k];
209.536 + val[0] = - lpx_get_row_lb(prob, i);
209.537 + }
209.538 + /* generate mixed cover cut:
209.539 + sum{j in J} a[j] * x[j] <= b */
209.540 + len = lpx_cover_cut(prob, len, ind, val, work);
209.541 + if (len == 0) continue;
209.542 + /* at the current point the cut inequality is violated, i.e.
209.543 + sum{j in J} a[j] * x[j] - b > 0 */
209.544 + r = lpx_eval_row(prob, len, ind, val) - val[0];
209.545 + if (r < 1e-3) continue;
209.546 + /* add the cut to the cut pool */
209.547 + glp_ios_add_row(tree, NULL, GLP_RF_COV, 0, len, ind, val,
209.548 + GLP_UP, val[0]);
209.549 + }
209.550 + /* free working arrays */
209.551 + xfree(ind);
209.552 + xfree(val);
209.553 + xfree(work);
209.554 + return;
209.555 +}
209.556 +
209.557 +/* eof */
210.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
210.2 +++ b/src/glpios08.c Mon Dec 06 13:09:21 2010 +0100
210.3 @@ -0,0 +1,907 @@
210.4 +/* glpios08.c (clique cut generator) */
210.5 +
210.6 +/***********************************************************************
210.7 +* This code is part of GLPK (GNU Linear Programming Kit).
210.8 +*
210.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
210.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
210.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
210.12 +* E-mail: <mao@gnu.org>.
210.13 +*
210.14 +* GLPK is free software: you can redistribute it and/or modify it
210.15 +* under the terms of the GNU General Public License as published by
210.16 +* the Free Software Foundation, either version 3 of the License, or
210.17 +* (at your option) any later version.
210.18 +*
210.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
210.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
210.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
210.22 +* License for more details.
210.23 +*
210.24 +* You should have received a copy of the GNU General Public License
210.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
210.26 +***********************************************************************/
210.27 +
210.28 +#include "glpios.h"
210.29 +
210.30 +static double get_row_lb(LPX *lp, int i)
210.31 +{ /* this routine returns lower bound of row i or -DBL_MAX if the
210.32 + row has no lower bound */
210.33 + double lb;
210.34 + switch (lpx_get_row_type(lp, i))
210.35 + { case LPX_FR:
210.36 + case LPX_UP:
210.37 + lb = -DBL_MAX;
210.38 + break;
210.39 + case LPX_LO:
210.40 + case LPX_DB:
210.41 + case LPX_FX:
210.42 + lb = lpx_get_row_lb(lp, i);
210.43 + break;
210.44 + default:
210.45 + xassert(lp != lp);
210.46 + }
210.47 + return lb;
210.48 +}
210.49 +
210.50 +static double get_row_ub(LPX *lp, int i)
210.51 +{ /* this routine returns upper bound of row i or +DBL_MAX if the
210.52 + row has no upper bound */
210.53 + double ub;
210.54 + switch (lpx_get_row_type(lp, i))
210.55 + { case LPX_FR:
210.56 + case LPX_LO:
210.57 + ub = +DBL_MAX;
210.58 + break;
210.59 + case LPX_UP:
210.60 + case LPX_DB:
210.61 + case LPX_FX:
210.62 + ub = lpx_get_row_ub(lp, i);
210.63 + break;
210.64 + default:
210.65 + xassert(lp != lp);
210.66 + }
210.67 + return ub;
210.68 +}
210.69 +
210.70 +static double get_col_lb(LPX *lp, int j)
210.71 +{ /* this routine returns lower bound of column j or -DBL_MAX if
210.72 + the column has no lower bound */
210.73 + double lb;
210.74 + switch (lpx_get_col_type(lp, j))
210.75 + { case LPX_FR:
210.76 + case LPX_UP:
210.77 + lb = -DBL_MAX;
210.78 + break;
210.79 + case LPX_LO:
210.80 + case LPX_DB:
210.81 + case LPX_FX:
210.82 + lb = lpx_get_col_lb(lp, j);
210.83 + break;
210.84 + default:
210.85 + xassert(lp != lp);
210.86 + }
210.87 + return lb;
210.88 +}
210.89 +
210.90 +static double get_col_ub(LPX *lp, int j)
210.91 +{ /* this routine returns upper bound of column j or +DBL_MAX if
210.92 + the column has no upper bound */
210.93 + double ub;
210.94 + switch (lpx_get_col_type(lp, j))
210.95 + { case LPX_FR:
210.96 + case LPX_LO:
210.97 + ub = +DBL_MAX;
210.98 + break;
210.99 + case LPX_UP:
210.100 + case LPX_DB:
210.101 + case LPX_FX:
210.102 + ub = lpx_get_col_ub(lp, j);
210.103 + break;
210.104 + default:
210.105 + xassert(lp != lp);
210.106 + }
210.107 + return ub;
210.108 +}
210.109 +
210.110 +static int is_binary(LPX *lp, int j)
210.111 +{ /* this routine checks if variable x[j] is binary */
210.112 + return
210.113 + lpx_get_col_kind(lp, j) == LPX_IV &&
210.114 + lpx_get_col_type(lp, j) == LPX_DB &&
210.115 + lpx_get_col_lb(lp, j) == 0.0 && lpx_get_col_ub(lp, j) == 1.0;
210.116 +}
210.117 +
210.118 +static double eval_lf_min(LPX *lp, int len, int ind[], double val[])
210.119 +{ /* this routine computes the minimum of a specified linear form
210.120 +
210.121 + sum a[j]*x[j]
210.122 + j
210.123 +
210.124 + using the formula:
210.125 +
210.126 + min = sum a[j]*lb[j] + sum a[j]*ub[j],
210.127 + j in J+ j in J-
210.128 +
210.129 + where J+ = {j: a[j] > 0}, J- = {j: a[j] < 0}, lb[j] and ub[j]
210.130 + are lower and upper bound of variable x[j], resp. */
210.131 + int j, t;
210.132 + double lb, ub, sum;
210.133 + sum = 0.0;
210.134 + for (t = 1; t <= len; t++)
210.135 + { j = ind[t];
210.136 + if (val[t] > 0.0)
210.137 + { lb = get_col_lb(lp, j);
210.138 + if (lb == -DBL_MAX)
210.139 + { sum = -DBL_MAX;
210.140 + break;
210.141 + }
210.142 + sum += val[t] * lb;
210.143 + }
210.144 + else if (val[t] < 0.0)
210.145 + { ub = get_col_ub(lp, j);
210.146 + if (ub == +DBL_MAX)
210.147 + { sum = -DBL_MAX;
210.148 + break;
210.149 + }
210.150 + sum += val[t] * ub;
210.151 + }
210.152 + else
210.153 + xassert(val != val);
210.154 + }
210.155 + return sum;
210.156 +}
210.157 +
210.158 +static double eval_lf_max(LPX *lp, int len, int ind[], double val[])
210.159 +{ /* this routine computes the maximum of a specified linear form
210.160 +
210.161 + sum a[j]*x[j]
210.162 + j
210.163 +
210.164 + using the formula:
210.165 +
210.166 + max = sum a[j]*ub[j] + sum a[j]*lb[j],
210.167 + j in J+ j in J-
210.168 +
210.169 + where J+ = {j: a[j] > 0}, J- = {j: a[j] < 0}, lb[j] and ub[j]
210.170 + are lower and upper bound of variable x[j], resp. */
210.171 + int j, t;
210.172 + double lb, ub, sum;
210.173 + sum = 0.0;
210.174 + for (t = 1; t <= len; t++)
210.175 + { j = ind[t];
210.176 + if (val[t] > 0.0)
210.177 + { ub = get_col_ub(lp, j);
210.178 + if (ub == +DBL_MAX)
210.179 + { sum = +DBL_MAX;
210.180 + break;
210.181 + }
210.182 + sum += val[t] * ub;
210.183 + }
210.184 + else if (val[t] < 0.0)
210.185 + { lb = get_col_lb(lp, j);
210.186 + if (lb == -DBL_MAX)
210.187 + { sum = +DBL_MAX;
210.188 + break;
210.189 + }
210.190 + sum += val[t] * lb;
210.191 + }
210.192 + else
210.193 + xassert(val != val);
210.194 + }
210.195 + return sum;
210.196 +}
210.197 +
210.198 +/*----------------------------------------------------------------------
210.199 +-- probing - determine logical relation between binary variables.
210.200 +--
210.201 +-- This routine tentatively sets a binary variable to 0 and then to 1
210.202 +-- and examines whether another binary variable is caused to be fixed.
210.203 +--
210.204 +-- The examination is based only on one row (constraint), which is the
210.205 +-- following:
210.206 +--
210.207 +-- L <= sum a[j]*x[j] <= U. (1)
210.208 +-- j
210.209 +--
210.210 +-- Let x[p] be a probing variable, x[q] be an examined variable. Then
210.211 +-- (1) can be written as:
210.212 +--
210.213 +-- L <= sum a[j]*x[j] + a[p]*x[p] + a[q]*x[q] <= U, (2)
210.214 +-- j in J'
210.215 +--
210.216 +-- where J' = {j: j != p and j != q}.
210.217 +--
210.218 +-- Let
210.219 +--
210.220 +-- L' = L - a[p]*x[p], (3)
210.221 +--
210.222 +-- U' = U - a[p]*x[p], (4)
210.223 +--
210.224 +-- where x[p] is assumed to be fixed at 0 or 1. So (2) can be rewritten
210.225 +-- as follows:
210.226 +--
210.227 +-- L' <= sum a[j]*x[j] + a[q]*x[q] <= U', (5)
210.228 +-- j in J'
210.229 +--
210.230 +-- from where we have:
210.231 +--
210.232 +-- L' - sum a[j]*x[j] <= a[q]*x[q] <= U' - sum a[j]*x[j]. (6)
210.233 +-- j in J' j in J'
210.234 +--
210.235 +-- Thus,
210.236 +--
210.237 +-- min a[q]*x[q] = L' - MAX, (7)
210.238 +--
210.239 +-- max a[q]*x[q] = U' - MIN, (8)
210.240 +--
210.241 +-- where
210.242 +--
210.243 +-- MIN = min sum a[j]*x[j], (9)
210.244 +-- j in J'
210.245 +--
210.246 +-- MAX = max sum a[j]*x[j]. (10)
210.247 +-- j in J'
210.248 +--
210.249 +-- Formulae (7) and (8) allows determining implied lower and upper
210.250 +-- bounds of x[q].
210.251 +--
210.252 +-- Parameters len, val, L and U specify the constraint (1).
210.253 +--
210.254 +-- Parameters lf_min and lf_max specify implied lower and upper bounds
210.255 +-- of the linear form (1). It is assumed that these bounds are computed
210.256 +-- with the routines eval_lf_min and eval_lf_max (see above).
210.257 +--
210.258 +-- Parameter p specifies the probing variable x[p], which is set to 0
210.259 +-- (if set is 0) or to 1 (if set is 1).
210.260 +--
210.261 +-- Parameter q specifies the examined variable x[q].
210.262 +--
210.263 +-- On exit the routine returns one of the following codes:
210.264 +--
210.265 +-- 0 - there is no logical relation between x[p] and x[q];
210.266 +-- 1 - x[q] can take only on value 0;
210.267 +-- 2 - x[q] can take only on value 1. */
210.268 +
210.269 +static int probing(int len, double val[], double L, double U,
210.270 + double lf_min, double lf_max, int p, int set, int q)
210.271 +{ double temp;
210.272 + xassert(1 <= p && p < q && q <= len);
210.273 + /* compute L' (3) */
210.274 + if (L != -DBL_MAX && set) L -= val[p];
210.275 + /* compute U' (4) */
210.276 + if (U != +DBL_MAX && set) U -= val[p];
210.277 + /* compute MIN (9) */
210.278 + if (lf_min != -DBL_MAX)
210.279 + { if (val[p] < 0.0) lf_min -= val[p];
210.280 + if (val[q] < 0.0) lf_min -= val[q];
210.281 + }
210.282 + /* compute MAX (10) */
210.283 + if (lf_max != +DBL_MAX)
210.284 + { if (val[p] > 0.0) lf_max -= val[p];
210.285 + if (val[q] > 0.0) lf_max -= val[q];
210.286 + }
210.287 + /* compute implied lower bound of x[q]; see (7), (8) */
210.288 + if (val[q] > 0.0)
210.289 + { if (L == -DBL_MAX || lf_max == +DBL_MAX)
210.290 + temp = -DBL_MAX;
210.291 + else
210.292 + temp = (L - lf_max) / val[q];
210.293 + }
210.294 + else
210.295 + { if (U == +DBL_MAX || lf_min == -DBL_MAX)
210.296 + temp = -DBL_MAX;
210.297 + else
210.298 + temp = (U - lf_min) / val[q];
210.299 + }
210.300 + if (temp > 0.001) return 2;
210.301 + /* compute implied upper bound of x[q]; see (7), (8) */
210.302 + if (val[q] > 0.0)
210.303 + { if (U == +DBL_MAX || lf_min == -DBL_MAX)
210.304 + temp = +DBL_MAX;
210.305 + else
210.306 + temp = (U - lf_min) / val[q];
210.307 + }
210.308 + else
210.309 + { if (L == -DBL_MAX || lf_max == +DBL_MAX)
210.310 + temp = +DBL_MAX;
210.311 + else
210.312 + temp = (L - lf_max) / val[q];
210.313 + }
210.314 + if (temp < 0.999) return 1;
210.315 + /* there is no logical relation between x[p] and x[q] */
210.316 + return 0;
210.317 +}
210.318 +
210.319 +struct COG
210.320 +{ /* conflict graph; it represents logical relations between binary
210.321 + variables and has a vertex for each binary variable and its
210.322 + complement, and an edge between two vertices when at most one
210.323 + of the variables represented by the vertices can equal one in
210.324 + an optimal solution */
210.325 + int n;
210.326 + /* number of variables */
210.327 + int nb;
210.328 + /* number of binary variables represented in the graph (note that
210.329 + not all binary variables can be represented); vertices which
210.330 + correspond to binary variables have numbers 1, ..., nb while
210.331 + vertices which correspond to complements of binary variables
210.332 + have numbers nb+1, ..., nb+nb */
210.333 + int ne;
210.334 + /* number of edges in the graph */
210.335 + int *vert; /* int vert[1+n]; */
210.336 + /* if x[j] is a binary variable represented in the graph, vert[j]
210.337 + is the vertex number corresponding to x[j]; otherwise vert[j]
210.338 + is zero */
210.339 + int *orig; /* int list[1:nb]; */
210.340 + /* if vert[j] = k > 0, then orig[k] = j */
210.341 + unsigned char *a;
210.342 + /* adjacency matrix of the graph having 2*nb rows and columns;
210.343 + only strict lower triangle is stored in dense packed form */
210.344 +};
210.345 +
210.346 +/*----------------------------------------------------------------------
210.347 +-- lpx_create_cog - create the conflict graph.
210.348 +--
210.349 +-- SYNOPSIS
210.350 +--
210.351 +-- #include "glplpx.h"
210.352 +-- void *lpx_create_cog(LPX *lp);
210.353 +--
210.354 +-- DESCRIPTION
210.355 +--
210.356 +-- The routine lpx_create_cog creates the conflict graph for a given
210.357 +-- problem instance.
210.358 +--
210.359 +-- RETURNS
210.360 +--
210.361 +-- If the graph has been created, the routine returns a pointer to it.
210.362 +-- Otherwise the routine returns NULL. */
210.363 +
210.364 +#define MAX_NB 4000
210.365 +#define MAX_ROW_LEN 500
210.366 +
210.367 +static void lpx_add_cog_edge(void *_cog, int i, int j);
210.368 +
210.369 +static void *lpx_create_cog(LPX *lp)
210.370 +{ struct COG *cog = NULL;
210.371 + int m, n, nb, i, j, p, q, len, *ind, *vert, *orig;
210.372 + double L, U, lf_min, lf_max, *val;
210.373 + xprintf("Creating the conflict graph...\n");
210.374 + m = lpx_get_num_rows(lp);
210.375 + n = lpx_get_num_cols(lp);
210.376 + /* determine which binary variables should be included in the
210.377 + conflict graph */
210.378 + nb = 0;
210.379 + vert = xcalloc(1+n, sizeof(int));
210.380 + for (j = 1; j <= n; j++) vert[j] = 0;
210.381 + orig = xcalloc(1+n, sizeof(int));
210.382 + ind = xcalloc(1+n, sizeof(int));
210.383 + val = xcalloc(1+n, sizeof(double));
210.384 + for (i = 1; i <= m; i++)
210.385 + { L = get_row_lb(lp, i);
210.386 + U = get_row_ub(lp, i);
210.387 + if (L == -DBL_MAX && U == +DBL_MAX) continue;
210.388 + len = lpx_get_mat_row(lp, i, ind, val);
210.389 + if (len > MAX_ROW_LEN) continue;
210.390 + lf_min = eval_lf_min(lp, len, ind, val);
210.391 + lf_max = eval_lf_max(lp, len, ind, val);
210.392 + for (p = 1; p <= len; p++)
210.393 + { if (!is_binary(lp, ind[p])) continue;
210.394 + for (q = p+1; q <= len; q++)
210.395 + { if (!is_binary(lp, ind[q])) continue;
210.396 + if (probing(len, val, L, U, lf_min, lf_max, p, 0, q) ||
210.397 + probing(len, val, L, U, lf_min, lf_max, p, 1, q))
210.398 + { /* there is a logical relation */
210.399 + /* include the first variable in the graph */
210.400 + j = ind[p];
210.401 + if (vert[j] == 0) nb++, vert[j] = nb, orig[nb] = j;
210.402 + /* incude the second variable in the graph */
210.403 + j = ind[q];
210.404 + if (vert[j] == 0) nb++, vert[j] = nb, orig[nb] = j;
210.405 + }
210.406 + }
210.407 + }
210.408 + }
210.409 + /* if the graph is either empty or has too many vertices, do not
210.410 + create it */
210.411 + if (nb == 0 || nb > MAX_NB)
210.412 + { xprintf("The conflict graph is either empty or too big\n");
210.413 + xfree(vert);
210.414 + xfree(orig);
210.415 + goto done;
210.416 + }
210.417 + /* create the conflict graph */
210.418 + cog = xmalloc(sizeof(struct COG));
210.419 + cog->n = n;
210.420 + cog->nb = nb;
210.421 + cog->ne = 0;
210.422 + cog->vert = vert;
210.423 + cog->orig = orig;
210.424 + len = nb + nb; /* number of vertices */
210.425 + len = (len * (len - 1)) / 2; /* number of entries in triangle */
210.426 + len = (len + (CHAR_BIT - 1)) / CHAR_BIT; /* bytes needed */
210.427 + cog->a = xmalloc(len);
210.428 + memset(cog->a, 0, len);
210.429 + for (j = 1; j <= nb; j++)
210.430 + { /* add edge between variable and its complement */
210.431 + lpx_add_cog_edge(cog, +orig[j], -orig[j]);
210.432 + }
210.433 + for (i = 1; i <= m; i++)
210.434 + { L = get_row_lb(lp, i);
210.435 + U = get_row_ub(lp, i);
210.436 + if (L == -DBL_MAX && U == +DBL_MAX) continue;
210.437 + len = lpx_get_mat_row(lp, i, ind, val);
210.438 + if (len > MAX_ROW_LEN) continue;
210.439 + lf_min = eval_lf_min(lp, len, ind, val);
210.440 + lf_max = eval_lf_max(lp, len, ind, val);
210.441 + for (p = 1; p <= len; p++)
210.442 + { if (!is_binary(lp, ind[p])) continue;
210.443 + for (q = p+1; q <= len; q++)
210.444 + { if (!is_binary(lp, ind[q])) continue;
210.445 + /* set x[p] to 0 and examine x[q] */
210.446 + switch (probing(len, val, L, U, lf_min, lf_max, p, 0, q))
210.447 + { case 0:
210.448 + /* no logical relation */
210.449 + break;
210.450 + case 1:
210.451 + /* x[p] = 0 implies x[q] = 0 */
210.452 + lpx_add_cog_edge(cog, -ind[p], +ind[q]);
210.453 + break;
210.454 + case 2:
210.455 + /* x[p] = 0 implies x[q] = 1 */
210.456 + lpx_add_cog_edge(cog, -ind[p], -ind[q]);
210.457 + break;
210.458 + default:
210.459 + xassert(lp != lp);
210.460 + }
210.461 + /* set x[p] to 1 and examine x[q] */
210.462 + switch (probing(len, val, L, U, lf_min, lf_max, p, 1, q))
210.463 + { case 0:
210.464 + /* no logical relation */
210.465 + break;
210.466 + case 1:
210.467 + /* x[p] = 1 implies x[q] = 0 */
210.468 + lpx_add_cog_edge(cog, +ind[p], +ind[q]);
210.469 + break;
210.470 + case 2:
210.471 + /* x[p] = 1 implies x[q] = 1 */
210.472 + lpx_add_cog_edge(cog, +ind[p], -ind[q]);
210.473 + break;
210.474 + default:
210.475 + xassert(lp != lp);
210.476 + }
210.477 + }
210.478 + }
210.479 + }
210.480 + xprintf("The conflict graph has 2*%d vertices and %d edges\n",
210.481 + cog->nb, cog->ne);
210.482 +done: xfree(ind);
210.483 + xfree(val);
210.484 + return cog;
210.485 +}
210.486 +
210.487 +/*----------------------------------------------------------------------
210.488 +-- lpx_add_cog_edge - add edge to the conflict graph.
210.489 +--
210.490 +-- SYNOPSIS
210.491 +--
210.492 +-- #include "glplpx.h"
210.493 +-- void lpx_add_cog_edge(void *cog, int i, int j);
210.494 +--
210.495 +-- DESCRIPTION
210.496 +--
210.497 +-- The routine lpx_add_cog_edge adds an edge to the conflict graph.
210.498 +-- The edge connects x[i] (if i > 0) or its complement (if i < 0) and
210.499 +-- x[j] (if j > 0) or its complement (if j < 0), where i and j are
210.500 +-- original ordinal numbers of corresponding variables. */
210.501 +
210.502 +static void lpx_add_cog_edge(void *_cog, int i, int j)
210.503 +{ struct COG *cog = _cog;
210.504 + int k;
210.505 + xassert(i != j);
210.506 + /* determine indices of corresponding vertices */
210.507 + if (i > 0)
210.508 + { xassert(1 <= i && i <= cog->n);
210.509 + i = cog->vert[i];
210.510 + xassert(i != 0);
210.511 + }
210.512 + else
210.513 + { i = -i;
210.514 + xassert(1 <= i && i <= cog->n);
210.515 + i = cog->vert[i];
210.516 + xassert(i != 0);
210.517 + i += cog->nb;
210.518 + }
210.519 + if (j > 0)
210.520 + { xassert(1 <= j && j <= cog->n);
210.521 + j = cog->vert[j];
210.522 + xassert(j != 0);
210.523 + }
210.524 + else
210.525 + { j = -j;
210.526 + xassert(1 <= j && j <= cog->n);
210.527 + j = cog->vert[j];
210.528 + xassert(j != 0);
210.529 + j += cog->nb;
210.530 + }
210.531 + /* only lower triangle is stored, so we need i > j */
210.532 + if (i < j) k = i, i = j, j = k;
210.533 + k = ((i - 1) * (i - 2)) / 2 + (j - 1);
210.534 + cog->a[k / CHAR_BIT] |=
210.535 + (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT));
210.536 + cog->ne++;
210.537 + return;
210.538 +}
210.539 +
210.540 +/*----------------------------------------------------------------------
210.541 +-- MAXIMUM WEIGHT CLIQUE
210.542 +--
210.543 +-- Two subroutines sub() and wclique() below are intended to find a
210.544 +-- maximum weight clique in a given undirected graph. These subroutines
210.545 +-- are slightly modified version of the program WCLIQUE developed by
210.546 +-- Patric Ostergard <http://www.tcs.hut.fi/~pat/wclique.html> and based
210.547 +-- on ideas from the article "P. R. J. Ostergard, A new algorithm for
210.548 +-- the maximum-weight clique problem, submitted for publication", which
210.549 +-- in turn is a generalization of the algorithm for unweighted graphs
210.550 +-- presented in "P. R. J. Ostergard, A fast algorithm for the maximum
210.551 +-- clique problem, submitted for publication".
210.552 +--
210.553 +-- USED WITH PERMISSION OF THE AUTHOR OF THE ORIGINAL CODE. */
210.554 +
210.555 +struct dsa
210.556 +{ /* dynamic storage area */
210.557 + int n;
210.558 + /* number of vertices */
210.559 + int *wt; /* int wt[0:n-1]; */
210.560 + /* weights */
210.561 + unsigned char *a;
210.562 + /* adjacency matrix (packed lower triangle without main diag.) */
210.563 + int record;
210.564 + /* weight of best clique */
210.565 + int rec_level;
210.566 + /* number of vertices in best clique */
210.567 + int *rec; /* int rec[0:n-1]; */
210.568 + /* best clique so far */
210.569 + int *clique; /* int clique[0:n-1]; */
210.570 + /* table for pruning */
210.571 + int *set; /* int set[0:n-1]; */
210.572 + /* current clique */
210.573 +};
210.574 +
210.575 +#define n (dsa->n)
210.576 +#define wt (dsa->wt)
210.577 +#define a (dsa->a)
210.578 +#define record (dsa->record)
210.579 +#define rec_level (dsa->rec_level)
210.580 +#define rec (dsa->rec)
210.581 +#define clique (dsa->clique)
210.582 +#define set (dsa->set)
210.583 +
210.584 +#if 0
210.585 +static int is_edge(struct dsa *dsa, int i, int j)
210.586 +{ /* if there is arc (i,j), the routine returns true; otherwise
210.587 + false; 0 <= i, j < n */
210.588 + int k;
210.589 + xassert(0 <= i && i < n);
210.590 + xassert(0 <= j && j < n);
210.591 + if (i == j) return 0;
210.592 + if (i < j) k = i, i = j, j = k;
210.593 + k = (i * (i - 1)) / 2 + j;
210.594 + return a[k / CHAR_BIT] &
210.595 + (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT));
210.596 +}
210.597 +#else
210.598 +#define is_edge(dsa, i, j) ((i) == (j) ? 0 : \
210.599 + (i) > (j) ? is_edge1(i, j) : is_edge1(j, i))
210.600 +#define is_edge1(i, j) is_edge2(((i) * ((i) - 1)) / 2 + (j))
210.601 +#define is_edge2(k) (a[(k) / CHAR_BIT] & \
210.602 + (unsigned char)(1 << ((CHAR_BIT - 1) - (k) % CHAR_BIT)))
210.603 +#endif
210.604 +
210.605 +static void sub(struct dsa *dsa, int ct, int table[], int level,
210.606 + int weight, int l_weight)
210.607 +{ int i, j, k, curr_weight, left_weight, *p1, *p2, *newtable;
210.608 + newtable = xcalloc(n, sizeof(int));
210.609 + if (ct <= 0)
210.610 + { /* 0 or 1 elements left; include these */
210.611 + if (ct == 0)
210.612 + { set[level++] = table[0];
210.613 + weight += l_weight;
210.614 + }
210.615 + if (weight > record)
210.616 + { record = weight;
210.617 + rec_level = level;
210.618 + for (i = 0; i < level; i++) rec[i] = set[i];
210.619 + }
210.620 + goto done;
210.621 + }
210.622 + for (i = ct; i >= 0; i--)
210.623 + { if ((level == 0) && (i < ct)) goto done;
210.624 + k = table[i];
210.625 + if ((level > 0) && (clique[k] <= (record - weight)))
210.626 + goto done; /* prune */
210.627 + set[level] = k;
210.628 + curr_weight = weight + wt[k];
210.629 + l_weight -= wt[k];
210.630 + if (l_weight <= (record - curr_weight))
210.631 + goto done; /* prune */
210.632 + p1 = newtable;
210.633 + p2 = table;
210.634 + left_weight = 0;
210.635 + while (p2 < table + i)
210.636 + { j = *p2++;
210.637 + if (is_edge(dsa, j, k))
210.638 + { *p1++ = j;
210.639 + left_weight += wt[j];
210.640 + }
210.641 + }
210.642 + if (left_weight <= (record - curr_weight)) continue;
210.643 + sub(dsa, p1 - newtable - 1, newtable, level + 1, curr_weight,
210.644 + left_weight);
210.645 + }
210.646 +done: xfree(newtable);
210.647 + return;
210.648 +}
210.649 +
210.650 +static int wclique(int _n, int w[], unsigned char _a[], int sol[])
210.651 +{ struct dsa _dsa, *dsa = &_dsa;
210.652 + int i, j, p, max_wt, max_nwt, wth, *used, *nwt, *pos;
210.653 + glp_long timer;
210.654 + n = _n;
210.655 + wt = &w[1];
210.656 + a = _a;
210.657 + record = 0;
210.658 + rec_level = 0;
210.659 + rec = &sol[1];
210.660 + clique = xcalloc(n, sizeof(int));
210.661 + set = xcalloc(n, sizeof(int));
210.662 + used = xcalloc(n, sizeof(int));
210.663 + nwt = xcalloc(n, sizeof(int));
210.664 + pos = xcalloc(n, sizeof(int));
210.665 + /* start timer */
210.666 + timer = xtime();
210.667 + /* order vertices */
210.668 + for (i = 0; i < n; i++)
210.669 + { nwt[i] = 0;
210.670 + for (j = 0; j < n; j++)
210.671 + if (is_edge(dsa, i, j)) nwt[i] += wt[j];
210.672 + }
210.673 + for (i = 0; i < n; i++)
210.674 + used[i] = 0;
210.675 + for (i = n-1; i >= 0; i--)
210.676 + { max_wt = -1;
210.677 + max_nwt = -1;
210.678 + for (j = 0; j < n; j++)
210.679 + { if ((!used[j]) && ((wt[j] > max_wt) || (wt[j] == max_wt
210.680 + && nwt[j] > max_nwt)))
210.681 + { max_wt = wt[j];
210.682 + max_nwt = nwt[j];
210.683 + p = j;
210.684 + }
210.685 + }
210.686 + pos[i] = p;
210.687 + used[p] = 1;
210.688 + for (j = 0; j < n; j++)
210.689 + if ((!used[j]) && (j != p) && (is_edge(dsa, p, j)))
210.690 + nwt[j] -= wt[p];
210.691 + }
210.692 + /* main routine */
210.693 + wth = 0;
210.694 + for (i = 0; i < n; i++)
210.695 + { wth += wt[pos[i]];
210.696 + sub(dsa, i, pos, 0, 0, wth);
210.697 + clique[pos[i]] = record;
210.698 +#if 0
210.699 + if (utime() >= timer + 5.0)
210.700 +#else
210.701 + if (xdifftime(xtime(), timer) >= 5.0 - 0.001)
210.702 +#endif
210.703 + { /* print current record and reset timer */
210.704 + xprintf("level = %d (%d); best = %d\n", i+1, n, record);
210.705 +#if 0
210.706 + timer = utime();
210.707 +#else
210.708 + timer = xtime();
210.709 +#endif
210.710 + }
210.711 + }
210.712 + xfree(clique);
210.713 + xfree(set);
210.714 + xfree(used);
210.715 + xfree(nwt);
210.716 + xfree(pos);
210.717 + /* return the solution found */
210.718 + for (i = 1; i <= rec_level; i++) sol[i]++;
210.719 + return rec_level;
210.720 +}
210.721 +
210.722 +#undef n
210.723 +#undef wt
210.724 +#undef a
210.725 +#undef record
210.726 +#undef rec_level
210.727 +#undef rec
210.728 +#undef clique
210.729 +#undef set
210.730 +
210.731 +/*----------------------------------------------------------------------
210.732 +-- lpx_clique_cut - generate cluque cut.
210.733 +--
210.734 +-- SYNOPSIS
210.735 +--
210.736 +-- #include "glplpx.h"
210.737 +-- int lpx_clique_cut(LPX *lp, void *cog, int ind[], double val[]);
210.738 +--
210.739 +-- DESCRIPTION
210.740 +--
210.741 +-- The routine lpx_clique_cut generates a clique cut using the conflict
210.742 +-- graph specified by the parameter cog.
210.743 +--
210.744 +-- If a violated clique cut has been found, it has the following form:
210.745 +--
210.746 +-- sum{j in J} a[j]*x[j] <= b.
210.747 +--
210.748 +-- Variable indices j in J are stored in elements ind[1], ..., ind[len]
210.749 +-- while corresponding constraint coefficients are stored in elements
210.750 +-- val[1], ..., val[len], where len is returned on exit. The right-hand
210.751 +-- side b is stored in element val[0].
210.752 +--
210.753 +-- RETURNS
210.754 +--
210.755 +-- If the cutting plane has been successfully generated, the routine
210.756 +-- returns 1 <= len <= n, which is the number of non-zero coefficients
210.757 +-- in the inequality constraint. Otherwise, the routine returns zero. */
210.758 +
210.759 +static int lpx_clique_cut(LPX *lp, void *_cog, int ind[], double val[])
210.760 +{ struct COG *cog = _cog;
210.761 + int n = lpx_get_num_cols(lp);
210.762 + int j, t, v, card, temp, len = 0, *w, *sol;
210.763 + double x, sum, b, *vec;
210.764 + /* allocate working arrays */
210.765 + w = xcalloc(1 + 2 * cog->nb, sizeof(int));
210.766 + sol = xcalloc(1 + 2 * cog->nb, sizeof(int));
210.767 + vec = xcalloc(1+n, sizeof(double));
210.768 + /* assign weights to vertices of the conflict graph */
210.769 + for (t = 1; t <= cog->nb; t++)
210.770 + { j = cog->orig[t];
210.771 + x = lpx_get_col_prim(lp, j);
210.772 + temp = (int)(100.0 * x + 0.5);
210.773 + if (temp < 0) temp = 0;
210.774 + if (temp > 100) temp = 100;
210.775 + w[t] = temp;
210.776 + w[cog->nb + t] = 100 - temp;
210.777 + }
210.778 + /* find a clique of maximum weight */
210.779 + card = wclique(2 * cog->nb, w, cog->a, sol);
210.780 + /* compute the clique weight for unscaled values */
210.781 + sum = 0.0;
210.782 + for ( t = 1; t <= card; t++)
210.783 + { v = sol[t];
210.784 + xassert(1 <= v && v <= 2 * cog->nb);
210.785 + if (v <= cog->nb)
210.786 + { /* vertex v corresponds to binary variable x[j] */
210.787 + j = cog->orig[v];
210.788 + x = lpx_get_col_prim(lp, j);
210.789 + sum += x;
210.790 + }
210.791 + else
210.792 + { /* vertex v corresponds to the complement of x[j] */
210.793 + j = cog->orig[v - cog->nb];
210.794 + x = lpx_get_col_prim(lp, j);
210.795 + sum += 1.0 - x;
210.796 + }
210.797 + }
210.798 + /* if the sum of binary variables and their complements in the
210.799 + clique greater than 1, the clique cut is violated */
210.800 + if (sum >= 1.01)
210.801 + { /* construct the inquality */
210.802 + for (j = 1; j <= n; j++) vec[j] = 0;
210.803 + b = 1.0;
210.804 + for (t = 1; t <= card; t++)
210.805 + { v = sol[t];
210.806 + if (v <= cog->nb)
210.807 + { /* vertex v corresponds to binary variable x[j] */
210.808 + j = cog->orig[v];
210.809 + xassert(1 <= j && j <= n);
210.810 + vec[j] += 1.0;
210.811 + }
210.812 + else
210.813 + { /* vertex v corresponds to the complement of x[j] */
210.814 + j = cog->orig[v - cog->nb];
210.815 + xassert(1 <= j && j <= n);
210.816 + vec[j] -= 1.0;
210.817 + b -= 1.0;
210.818 + }
210.819 + }
210.820 + xassert(len == 0);
210.821 + for (j = 1; j <= n; j++)
210.822 + { if (vec[j] != 0.0)
210.823 + { len++;
210.824 + ind[len] = j, val[len] = vec[j];
210.825 + }
210.826 + }
210.827 + ind[0] = 0, val[0] = b;
210.828 + }
210.829 + /* free working arrays */
210.830 + xfree(w);
210.831 + xfree(sol);
210.832 + xfree(vec);
210.833 + /* return to the calling program */
210.834 + return len;
210.835 +}
210.836 +
210.837 +/*----------------------------------------------------------------------
210.838 +-- lpx_delete_cog - delete the conflict graph.
210.839 +--
210.840 +-- SYNOPSIS
210.841 +--
210.842 +-- #include "glplpx.h"
210.843 +-- void lpx_delete_cog(void *cog);
210.844 +--
210.845 +-- DESCRIPTION
210.846 +--
210.847 +-- The routine lpx_delete_cog deletes the conflict graph, which the
210.848 +-- parameter cog points to, freeing all the memory allocated to this
210.849 +-- object. */
210.850 +
210.851 +static void lpx_delete_cog(void *_cog)
210.852 +{ struct COG *cog = _cog;
210.853 + xfree(cog->vert);
210.854 + xfree(cog->orig);
210.855 + xfree(cog->a);
210.856 + xfree(cog);
210.857 +}
210.858 +
210.859 +/**********************************************************************/
210.860 +
210.861 +void *ios_clq_init(glp_tree *tree)
210.862 +{ /* initialize clique cut generator */
210.863 + glp_prob *mip = tree->mip;
210.864 + xassert(mip != NULL);
210.865 + return lpx_create_cog(mip);
210.866 +}
210.867 +
210.868 +/***********************************************************************
210.869 +* NAME
210.870 +*
210.871 +* ios_clq_gen - generate clique cuts
210.872 +*
210.873 +* SYNOPSIS
210.874 +*
210.875 +* #include "glpios.h"
210.876 +* void ios_clq_gen(glp_tree *tree, void *gen);
210.877 +*
210.878 +* DESCRIPTION
210.879 +*
210.880 +* The routine ios_clq_gen generates clique cuts for the current point
210.881 +* and adds them to the clique pool. */
210.882 +
210.883 +void ios_clq_gen(glp_tree *tree, void *gen)
210.884 +{ int n = lpx_get_num_cols(tree->mip);
210.885 + int len, *ind;
210.886 + double *val;
210.887 + xassert(gen != NULL);
210.888 + ind = xcalloc(1+n, sizeof(int));
210.889 + val = xcalloc(1+n, sizeof(double));
210.890 + len = lpx_clique_cut(tree->mip, gen, ind, val);
210.891 + if (len > 0)
210.892 + { /* xprintf("len = %d\n", len); */
210.893 + glp_ios_add_row(tree, NULL, GLP_RF_CLQ, 0, len, ind, val,
210.894 + GLP_UP, val[0]);
210.895 + }
210.896 + xfree(ind);
210.897 + xfree(val);
210.898 + return;
210.899 +}
210.900 +
210.901 +/**********************************************************************/
210.902 +
210.903 +void ios_clq_term(void *gen)
210.904 +{ /* terminate clique cut generator */
210.905 + xassert(gen != NULL);
210.906 + lpx_delete_cog(gen);
210.907 + return;
210.908 +}
210.909 +
210.910 +/* eof */
211.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
211.2 +++ b/src/glpios09.c Mon Dec 06 13:09:21 2010 +0100
211.3 @@ -0,0 +1,659 @@
211.4 +/* glpios09.c (branching heuristics) */
211.5 +
211.6 +/***********************************************************************
211.7 +* This code is part of GLPK (GNU Linear Programming Kit).
211.8 +*
211.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
211.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
211.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
211.12 +* E-mail: <mao@gnu.org>.
211.13 +*
211.14 +* GLPK is free software: you can redistribute it and/or modify it
211.15 +* under the terms of the GNU General Public License as published by
211.16 +* the Free Software Foundation, either version 3 of the License, or
211.17 +* (at your option) any later version.
211.18 +*
211.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
211.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
211.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
211.22 +* License for more details.
211.23 +*
211.24 +* You should have received a copy of the GNU General Public License
211.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
211.26 +***********************************************************************/
211.27 +
211.28 +#include "glpios.h"
211.29 +
211.30 +/***********************************************************************
211.31 +* NAME
211.32 +*
211.33 +* ios_choose_var - select variable to branch on
211.34 +*
211.35 +* SYNOPSIS
211.36 +*
211.37 +* #include "glpios.h"
211.38 +* int ios_choose_var(glp_tree *T, int *next);
211.39 +*
211.40 +* The routine ios_choose_var chooses a variable from the candidate
211.41 +* list to branch on. Additionally the routine provides a flag stored
211.42 +* in the location next to suggests which of the child subproblems
211.43 +* should be solved next.
211.44 +*
211.45 +* RETURNS
211.46 +*
211.47 +* The routine ios_choose_var returns the ordinal number of the column
211.48 +* choosen. */
211.49 +
211.50 +static int branch_first(glp_tree *T, int *next);
211.51 +static int branch_last(glp_tree *T, int *next);
211.52 +static int branch_mostf(glp_tree *T, int *next);
211.53 +static int branch_drtom(glp_tree *T, int *next);
211.54 +
211.55 +int ios_choose_var(glp_tree *T, int *next)
211.56 +{ int j;
211.57 + if (T->parm->br_tech == GLP_BR_FFV)
211.58 + { /* branch on first fractional variable */
211.59 + j = branch_first(T, next);
211.60 + }
211.61 + else if (T->parm->br_tech == GLP_BR_LFV)
211.62 + { /* branch on last fractional variable */
211.63 + j = branch_last(T, next);
211.64 + }
211.65 + else if (T->parm->br_tech == GLP_BR_MFV)
211.66 + { /* branch on most fractional variable */
211.67 + j = branch_mostf(T, next);
211.68 + }
211.69 + else if (T->parm->br_tech == GLP_BR_DTH)
211.70 + { /* branch using the heuristic by Dreebeck and Tomlin */
211.71 + j = branch_drtom(T, next);
211.72 + }
211.73 + else if (T->parm->br_tech == GLP_BR_PCH)
211.74 + { /* hybrid pseudocost heuristic */
211.75 + j = ios_pcost_branch(T, next);
211.76 + }
211.77 + else
211.78 + xassert(T != T);
211.79 + return j;
211.80 +}
211.81 +
211.82 +/***********************************************************************
211.83 +* branch_first - choose first branching variable
211.84 +*
211.85 +* This routine looks up the list of structural variables and chooses
211.86 +* the first one, which is of integer kind and has fractional value in
211.87 +* optimal solution to the current LP relaxation.
211.88 +*
211.89 +* This routine also selects the branch to be solved next where integer
211.90 +* infeasibility of the chosen variable is less than in other one. */
211.91 +
211.92 +static int branch_first(glp_tree *T, int *_next)
211.93 +{ int j, next;
211.94 + double beta;
211.95 + /* choose the column to branch on */
211.96 + for (j = 1; j <= T->n; j++)
211.97 + if (T->non_int[j]) break;
211.98 + xassert(1 <= j && j <= T->n);
211.99 + /* select the branch to be solved next */
211.100 + beta = glp_get_col_prim(T->mip, j);
211.101 + if (beta - floor(beta) < ceil(beta) - beta)
211.102 + next = GLP_DN_BRNCH;
211.103 + else
211.104 + next = GLP_UP_BRNCH;
211.105 + *_next = next;
211.106 + return j;
211.107 +}
211.108 +
211.109 +/***********************************************************************
211.110 +* branch_last - choose last branching variable
211.111 +*
211.112 +* This routine looks up the list of structural variables and chooses
211.113 +* the last one, which is of integer kind and has fractional value in
211.114 +* optimal solution to the current LP relaxation.
211.115 +*
211.116 +* This routine also selects the branch to be solved next where integer
211.117 +* infeasibility of the chosen variable is less than in other one. */
211.118 +
211.119 +static int branch_last(glp_tree *T, int *_next)
211.120 +{ int j, next;
211.121 + double beta;
211.122 + /* choose the column to branch on */
211.123 + for (j = T->n; j >= 1; j--)
211.124 + if (T->non_int[j]) break;
211.125 + xassert(1 <= j && j <= T->n);
211.126 + /* select the branch to be solved next */
211.127 + beta = glp_get_col_prim(T->mip, j);
211.128 + if (beta - floor(beta) < ceil(beta) - beta)
211.129 + next = GLP_DN_BRNCH;
211.130 + else
211.131 + next = GLP_UP_BRNCH;
211.132 + *_next = next;
211.133 + return j;
211.134 +}
211.135 +
211.136 +/***********************************************************************
211.137 +* branch_mostf - choose most fractional branching variable
211.138 +*
211.139 +* This routine looks up the list of structural variables and chooses
211.140 +* that one, which is of integer kind and has most fractional value in
211.141 +* optimal solution to the current LP relaxation.
211.142 +*
211.143 +* This routine also selects the branch to be solved next where integer
211.144 +* infeasibility of the chosen variable is less than in other one.
211.145 +*
211.146 +* (Alexander Martin notices that "...most infeasible is as good as
211.147 +* random...".) */
211.148 +
211.149 +static int branch_mostf(glp_tree *T, int *_next)
211.150 +{ int j, jj, next;
211.151 + double beta, most, temp;
211.152 + /* choose the column to branch on */
211.153 + jj = 0, most = DBL_MAX;
211.154 + for (j = 1; j <= T->n; j++)
211.155 + { if (T->non_int[j])
211.156 + { beta = glp_get_col_prim(T->mip, j);
211.157 + temp = floor(beta) + 0.5;
211.158 + if (most > fabs(beta - temp))
211.159 + { jj = j, most = fabs(beta - temp);
211.160 + if (beta < temp)
211.161 + next = GLP_DN_BRNCH;
211.162 + else
211.163 + next = GLP_UP_BRNCH;
211.164 + }
211.165 + }
211.166 + }
211.167 + *_next = next;
211.168 + return jj;
211.169 +}
211.170 +
211.171 +/***********************************************************************
211.172 +* branch_drtom - choose branching var using Driebeck-Tomlin heuristic
211.173 +*
211.174 +* This routine chooses a structural variable, which is required to be
211.175 +* integral and has fractional value in optimal solution of the current
211.176 +* LP relaxation, using a heuristic proposed by Driebeck and Tomlin.
211.177 +*
211.178 +* The routine also selects the branch to be solved next, again due to
211.179 +* Driebeck and Tomlin.
211.180 +*
211.181 +* This routine is based on the heuristic proposed in:
211.182 +*
211.183 +* Driebeck N.J. An algorithm for the solution of mixed-integer
211.184 +* programming problems, Management Science, 12: 576-87 (1966);
211.185 +*
211.186 +* and improved in:
211.187 +*
211.188 +* Tomlin J.A. Branch and bound methods for integer and non-convex
211.189 +* programming, in J.Abadie (ed.), Integer and Nonlinear Programming,
211.190 +* North-Holland, Amsterdam, pp. 437-50 (1970).
211.191 +*
211.192 +* Must note that this heuristic is time-expensive, because computing
211.193 +* one-step degradation (see the routine below) requires one BTRAN for
211.194 +* each fractional-valued structural variable. */
211.195 +
211.196 +static int branch_drtom(glp_tree *T, int *_next)
211.197 +{ glp_prob *mip = T->mip;
211.198 + int m = mip->m;
211.199 + int n = mip->n;
211.200 + char *non_int = T->non_int;
211.201 + int j, jj, k, t, next, kase, len, stat, *ind;
211.202 + double x, dk, alfa, delta_j, delta_k, delta_z, dz_dn, dz_up,
211.203 + dd_dn, dd_up, degrad, *val;
211.204 + /* basic solution of LP relaxation must be optimal */
211.205 + xassert(glp_get_status(mip) == GLP_OPT);
211.206 + /* allocate working arrays */
211.207 + ind = xcalloc(1+n, sizeof(int));
211.208 + val = xcalloc(1+n, sizeof(double));
211.209 + /* nothing has been chosen so far */
211.210 + jj = 0, degrad = -1.0;
211.211 + /* walk through the list of columns (structural variables) */
211.212 + for (j = 1; j <= n; j++)
211.213 + { /* if j-th column is not marked as fractional, skip it */
211.214 + if (!non_int[j]) continue;
211.215 + /* obtain (fractional) value of j-th column in basic solution
211.216 + of LP relaxation */
211.217 + x = glp_get_col_prim(mip, j);
211.218 + /* since the value of j-th column is fractional, the column is
211.219 + basic; compute corresponding row of the simplex table */
211.220 + len = glp_eval_tab_row(mip, m+j, ind, val);
211.221 + /* the following fragment computes a change in the objective
211.222 + function: delta Z = new Z - old Z, where old Z is the
211.223 + objective value in the current optimal basis, and new Z is
211.224 + the objective value in the adjacent basis, for two cases:
211.225 + 1) if new upper bound ub' = floor(x[j]) is introduced for
211.226 + j-th column (down branch);
211.227 + 2) if new lower bound lb' = ceil(x[j]) is introduced for
211.228 + j-th column (up branch);
211.229 + since in both cases the solution remaining dual feasible
211.230 + becomes primal infeasible, one implicit simplex iteration
211.231 + is performed to determine the change delta Z;
211.232 + it is obvious that new Z, which is never better than old Z,
211.233 + is a lower (minimization) or upper (maximization) bound of
211.234 + the objective function for down- and up-branches. */
211.235 + for (kase = -1; kase <= +1; kase += 2)
211.236 + { /* if kase < 0, the new upper bound of x[j] is introduced;
211.237 + in this case x[j] should decrease in order to leave the
211.238 + basis and go to its new upper bound */
211.239 + /* if kase > 0, the new lower bound of x[j] is introduced;
211.240 + in this case x[j] should increase in order to leave the
211.241 + basis and go to its new lower bound */
211.242 + /* apply the dual ratio test in order to determine which
211.243 + auxiliary or structural variable should enter the basis
211.244 + to keep dual feasibility */
211.245 + k = glp_dual_rtest(mip, len, ind, val, kase, 1e-9);
211.246 + if (k != 0) k = ind[k];
211.247 + /* if no non-basic variable has been chosen, LP relaxation
211.248 + of corresponding branch being primal infeasible and dual
211.249 + unbounded has no primal feasible solution; in this case
211.250 + the change delta Z is formally set to infinity */
211.251 + if (k == 0)
211.252 + { delta_z =
211.253 + (T->mip->dir == GLP_MIN ? +DBL_MAX : -DBL_MAX);
211.254 + goto skip;
211.255 + }
211.256 + /* row of the simplex table that corresponds to non-basic
211.257 + variable x[k] choosen by the dual ratio test is:
211.258 + x[j] = ... + alfa * x[k] + ...
211.259 + where alfa is the influence coefficient (an element of
211.260 + the simplex table row) */
211.261 + /* determine the coefficient alfa */
211.262 + for (t = 1; t <= len; t++) if (ind[t] == k) break;
211.263 + xassert(1 <= t && t <= len);
211.264 + alfa = val[t];
211.265 + /* since in the adjacent basis the variable x[j] becomes
211.266 + non-basic, knowing its value in the current basis we can
211.267 + determine its change delta x[j] = new x[j] - old x[j] */
211.268 + delta_j = (kase < 0 ? floor(x) : ceil(x)) - x;
211.269 + /* and knowing the coefficient alfa we can determine the
211.270 + corresponding change delta x[k] = new x[k] - old x[k],
211.271 + where old x[k] is a value of x[k] in the current basis,
211.272 + and new x[k] is a value of x[k] in the adjacent basis */
211.273 + delta_k = delta_j / alfa;
211.274 + /* Tomlin noticed that if the variable x[k] is of integer
211.275 + kind, its change cannot be less (eventually) than one in
211.276 + the magnitude */
211.277 + if (k > m && glp_get_col_kind(mip, k-m) != GLP_CV)
211.278 + { /* x[k] is structural integer variable */
211.279 + if (fabs(delta_k - floor(delta_k + 0.5)) > 1e-3)
211.280 + { if (delta_k > 0.0)
211.281 + delta_k = ceil(delta_k); /* +3.14 -> +4 */
211.282 + else
211.283 + delta_k = floor(delta_k); /* -3.14 -> -4 */
211.284 + }
211.285 + }
211.286 + /* now determine the status and reduced cost of x[k] in the
211.287 + current basis */
211.288 + if (k <= m)
211.289 + { stat = glp_get_row_stat(mip, k);
211.290 + dk = glp_get_row_dual(mip, k);
211.291 + }
211.292 + else
211.293 + { stat = glp_get_col_stat(mip, k-m);
211.294 + dk = glp_get_col_dual(mip, k-m);
211.295 + }
211.296 + /* if the current basis is dual degenerate, some reduced
211.297 + costs which are close to zero may have wrong sign due to
211.298 + round-off errors, so correct the sign of d[k] */
211.299 + switch (T->mip->dir)
211.300 + { case GLP_MIN:
211.301 + if (stat == GLP_NL && dk < 0.0 ||
211.302 + stat == GLP_NU && dk > 0.0 ||
211.303 + stat == GLP_NF) dk = 0.0;
211.304 + break;
211.305 + case GLP_MAX:
211.306 + if (stat == GLP_NL && dk > 0.0 ||
211.307 + stat == GLP_NU && dk < 0.0 ||
211.308 + stat == GLP_NF) dk = 0.0;
211.309 + break;
211.310 + default:
211.311 + xassert(T != T);
211.312 + }
211.313 + /* now knowing the change of x[k] and its reduced cost d[k]
211.314 + we can compute the corresponding change in the objective
211.315 + function delta Z = new Z - old Z = d[k] * delta x[k];
211.316 + note that due to Tomlin's modification new Z can be even
211.317 + worse than in the adjacent basis */
211.318 + delta_z = dk * delta_k;
211.319 +skip: /* new Z is never better than old Z, therefore the change
211.320 + delta Z is always non-negative (in case of minimization)
211.321 + or non-positive (in case of maximization) */
211.322 + switch (T->mip->dir)
211.323 + { case GLP_MIN: xassert(delta_z >= 0.0); break;
211.324 + case GLP_MAX: xassert(delta_z <= 0.0); break;
211.325 + default: xassert(T != T);
211.326 + }
211.327 + /* save the change in the objective fnction for down- and
211.328 + up-branches, respectively */
211.329 + if (kase < 0) dz_dn = delta_z; else dz_up = delta_z;
211.330 + }
211.331 + /* thus, in down-branch no integer feasible solution can be
211.332 + better than Z + dz_dn, and in up-branch no integer feasible
211.333 + solution can be better than Z + dz_up, where Z is value of
211.334 + the objective function in the current basis */
211.335 + /* following the heuristic by Driebeck and Tomlin we choose a
211.336 + column (i.e. structural variable) which provides largest
211.337 + degradation of the objective function in some of branches;
211.338 + besides, we select the branch with smaller degradation to
211.339 + be solved next and keep other branch with larger degradation
211.340 + in the active list hoping to minimize the number of further
211.341 + backtrackings */
211.342 + if (degrad < fabs(dz_dn) || degrad < fabs(dz_up))
211.343 + { jj = j;
211.344 + if (fabs(dz_dn) < fabs(dz_up))
211.345 + { /* select down branch to be solved next */
211.346 + next = GLP_DN_BRNCH;
211.347 + degrad = fabs(dz_up);
211.348 + }
211.349 + else
211.350 + { /* select up branch to be solved next */
211.351 + next = GLP_UP_BRNCH;
211.352 + degrad = fabs(dz_dn);
211.353 + }
211.354 + /* save the objective changes for printing */
211.355 + dd_dn = dz_dn, dd_up = dz_up;
211.356 + /* if down- or up-branch has no feasible solution, we does
211.357 + not need to consider other candidates (in principle, the
211.358 + corresponding branch could be pruned right now) */
211.359 + if (degrad == DBL_MAX) break;
211.360 + }
211.361 + }
211.362 + /* free working arrays */
211.363 + xfree(ind);
211.364 + xfree(val);
211.365 + /* something must be chosen */
211.366 + xassert(1 <= jj && jj <= n);
211.367 +#if 1 /* 02/XI-2009 */
211.368 + if (degrad < 1e-6 * (1.0 + 0.001 * fabs(mip->obj_val)))
211.369 + { jj = branch_mostf(T, &next);
211.370 + goto done;
211.371 + }
211.372 +#endif
211.373 + if (T->parm->msg_lev >= GLP_MSG_DBG)
211.374 + { xprintf("branch_drtom: column %d chosen to branch on\n", jj);
211.375 + if (fabs(dd_dn) == DBL_MAX)
211.376 + xprintf("branch_drtom: down-branch is infeasible\n");
211.377 + else
211.378 + xprintf("branch_drtom: down-branch bound is %.9e\n",
211.379 + lpx_get_obj_val(mip) + dd_dn);
211.380 + if (fabs(dd_up) == DBL_MAX)
211.381 + xprintf("branch_drtom: up-branch is infeasible\n");
211.382 + else
211.383 + xprintf("branch_drtom: up-branch bound is %.9e\n",
211.384 + lpx_get_obj_val(mip) + dd_up);
211.385 + }
211.386 +done: *_next = next;
211.387 + return jj;
211.388 +}
211.389 +
211.390 +/**********************************************************************/
211.391 +
211.392 +struct csa
211.393 +{ /* common storage area */
211.394 + int *dn_cnt; /* int dn_cnt[1+n]; */
211.395 + /* dn_cnt[j] is the number of subproblems, whose LP relaxations
211.396 + have been solved and which are down-branches for variable x[j];
211.397 + dn_cnt[j] = 0 means the down pseudocost is uninitialized */
211.398 + double *dn_sum; /* double dn_sum[1+n]; */
211.399 + /* dn_sum[j] is the sum of per unit degradations of the objective
211.400 + over all dn_cnt[j] subproblems */
211.401 + int *up_cnt; /* int up_cnt[1+n]; */
211.402 + /* up_cnt[j] is the number of subproblems, whose LP relaxations
211.403 + have been solved and which are up-branches for variable x[j];
211.404 + up_cnt[j] = 0 means the up pseudocost is uninitialized */
211.405 + double *up_sum; /* double up_sum[1+n]; */
211.406 + /* up_sum[j] is the sum of per unit degradations of the objective
211.407 + over all up_cnt[j] subproblems */
211.408 +};
211.409 +
211.410 +void *ios_pcost_init(glp_tree *tree)
211.411 +{ /* initialize working data used on pseudocost branching */
211.412 + struct csa *csa;
211.413 + int n = tree->n, j;
211.414 + csa = xmalloc(sizeof(struct csa));
211.415 + csa->dn_cnt = xcalloc(1+n, sizeof(int));
211.416 + csa->dn_sum = xcalloc(1+n, sizeof(double));
211.417 + csa->up_cnt = xcalloc(1+n, sizeof(int));
211.418 + csa->up_sum = xcalloc(1+n, sizeof(double));
211.419 + for (j = 1; j <= n; j++)
211.420 + { csa->dn_cnt[j] = csa->up_cnt[j] = 0;
211.421 + csa->dn_sum[j] = csa->up_sum[j] = 0.0;
211.422 + }
211.423 + return csa;
211.424 +}
211.425 +
211.426 +static double eval_degrad(glp_prob *P, int j, double bnd)
211.427 +{ /* compute degradation of the objective on fixing x[j] at given
211.428 + value with a limited number of dual simplex iterations */
211.429 + /* this routine fixes column x[j] at specified value bnd,
211.430 + solves resulting LP, and returns a lower bound to degradation
211.431 + of the objective, degrad >= 0 */
211.432 + glp_prob *lp;
211.433 + glp_smcp parm;
211.434 + int ret;
211.435 + double degrad;
211.436 + /* the current basis must be optimal */
211.437 + xassert(glp_get_status(P) == GLP_OPT);
211.438 + /* create a copy of P */
211.439 + lp = glp_create_prob();
211.440 + glp_copy_prob(lp, P, 0);
211.441 + /* fix column x[j] at specified value */
211.442 + glp_set_col_bnds(lp, j, GLP_FX, bnd, bnd);
211.443 + /* try to solve resulting LP */
211.444 + glp_init_smcp(&parm);
211.445 + parm.msg_lev = GLP_MSG_OFF;
211.446 + parm.meth = GLP_DUAL;
211.447 + parm.it_lim = 30;
211.448 + parm.out_dly = 1000;
211.449 + parm.meth = GLP_DUAL;
211.450 + ret = glp_simplex(lp, &parm);
211.451 + if (ret == 0 || ret == GLP_EITLIM)
211.452 + { if (glp_get_prim_stat(lp) == GLP_NOFEAS)
211.453 + { /* resulting LP has no primal feasible solution */
211.454 + degrad = DBL_MAX;
211.455 + }
211.456 + else if (glp_get_dual_stat(lp) == GLP_FEAS)
211.457 + { /* resulting basis is optimal or at least dual feasible,
211.458 + so we have the correct lower bound to degradation */
211.459 + if (P->dir == GLP_MIN)
211.460 + degrad = lp->obj_val - P->obj_val;
211.461 + else if (P->dir == GLP_MAX)
211.462 + degrad = P->obj_val - lp->obj_val;
211.463 + else
211.464 + xassert(P != P);
211.465 + /* degradation cannot be negative by definition */
211.466 + /* note that the lower bound to degradation may be close
211.467 + to zero even if its exact value is zero due to round-off
211.468 + errors on computing the objective value */
211.469 + if (degrad < 1e-6 * (1.0 + 0.001 * fabs(P->obj_val)))
211.470 + degrad = 0.0;
211.471 + }
211.472 + else
211.473 + { /* the final basis reported by the simplex solver is dual
211.474 + infeasible, so we cannot determine a non-trivial lower
211.475 + bound to degradation */
211.476 + degrad = 0.0;
211.477 + }
211.478 + }
211.479 + else
211.480 + { /* the simplex solver failed */
211.481 + degrad = 0.0;
211.482 + }
211.483 + /* delete the copy of P */
211.484 + glp_delete_prob(lp);
211.485 + return degrad;
211.486 +}
211.487 +
211.488 +void ios_pcost_update(glp_tree *tree)
211.489 +{ /* update history information for pseudocost branching */
211.490 + /* this routine is called every time when LP relaxation of the
211.491 + current subproblem has been solved to optimality with all lazy
211.492 + and cutting plane constraints included */
211.493 + int j;
211.494 + double dx, dz, psi;
211.495 + struct csa *csa = tree->pcost;
211.496 + xassert(csa != NULL);
211.497 + xassert(tree->curr != NULL);
211.498 + /* if the current subproblem is the root, skip updating */
211.499 + if (tree->curr->up == NULL) goto skip;
211.500 + /* determine branching variable x[j], which was used in the
211.501 + parent subproblem to create the current subproblem */
211.502 + j = tree->curr->up->br_var;
211.503 + xassert(1 <= j && j <= tree->n);
211.504 + /* determine the change dx[j] = new x[j] - old x[j],
211.505 + where new x[j] is a value of x[j] in optimal solution to LP
211.506 + relaxation of the current subproblem, old x[j] is a value of
211.507 + x[j] in optimal solution to LP relaxation of the parent
211.508 + subproblem */
211.509 + dx = tree->mip->col[j]->prim - tree->curr->up->br_val;
211.510 + xassert(dx != 0.0);
211.511 + /* determine corresponding change dz = new dz - old dz in the
211.512 + objective function value */
211.513 + dz = tree->mip->obj_val - tree->curr->up->lp_obj;
211.514 + /* determine per unit degradation of the objective function */
211.515 + psi = fabs(dz / dx);
211.516 + /* update history information */
211.517 + if (dx < 0.0)
211.518 + { /* the current subproblem is down-branch */
211.519 + csa->dn_cnt[j]++;
211.520 + csa->dn_sum[j] += psi;
211.521 + }
211.522 + else /* dx > 0.0 */
211.523 + { /* the current subproblem is up-branch */
211.524 + csa->up_cnt[j]++;
211.525 + csa->up_sum[j] += psi;
211.526 + }
211.527 +skip: return;
211.528 +}
211.529 +
211.530 +void ios_pcost_free(glp_tree *tree)
211.531 +{ /* free working area used on pseudocost branching */
211.532 + struct csa *csa = tree->pcost;
211.533 + xassert(csa != NULL);
211.534 + xfree(csa->dn_cnt);
211.535 + xfree(csa->dn_sum);
211.536 + xfree(csa->up_cnt);
211.537 + xfree(csa->up_sum);
211.538 + xfree(csa);
211.539 + tree->pcost = NULL;
211.540 + return;
211.541 +}
211.542 +
211.543 +static double eval_psi(glp_tree *T, int j, int brnch)
211.544 +{ /* compute estimation of pseudocost of variable x[j] for down-
211.545 + or up-branch */
211.546 + struct csa *csa = T->pcost;
211.547 + double beta, degrad, psi;
211.548 + xassert(csa != NULL);
211.549 + xassert(1 <= j && j <= T->n);
211.550 + if (brnch == GLP_DN_BRNCH)
211.551 + { /* down-branch */
211.552 + if (csa->dn_cnt[j] == 0)
211.553 + { /* initialize down pseudocost */
211.554 + beta = T->mip->col[j]->prim;
211.555 + degrad = eval_degrad(T->mip, j, floor(beta));
211.556 + if (degrad == DBL_MAX)
211.557 + { psi = DBL_MAX;
211.558 + goto done;
211.559 + }
211.560 + csa->dn_cnt[j] = 1;
211.561 + csa->dn_sum[j] = degrad / (beta - floor(beta));
211.562 + }
211.563 + psi = csa->dn_sum[j] / (double)csa->dn_cnt[j];
211.564 + }
211.565 + else if (brnch == GLP_UP_BRNCH)
211.566 + { /* up-branch */
211.567 + if (csa->up_cnt[j] == 0)
211.568 + { /* initialize up pseudocost */
211.569 + beta = T->mip->col[j]->prim;
211.570 + degrad = eval_degrad(T->mip, j, ceil(beta));
211.571 + if (degrad == DBL_MAX)
211.572 + { psi = DBL_MAX;
211.573 + goto done;
211.574 + }
211.575 + csa->up_cnt[j] = 1;
211.576 + csa->up_sum[j] = degrad / (ceil(beta) - beta);
211.577 + }
211.578 + psi = csa->up_sum[j] / (double)csa->up_cnt[j];
211.579 + }
211.580 + else
211.581 + xassert(brnch != brnch);
211.582 +done: return psi;
211.583 +}
211.584 +
211.585 +static void progress(glp_tree *T)
211.586 +{ /* display progress of pseudocost initialization */
211.587 + struct csa *csa = T->pcost;
211.588 + int j, nv = 0, ni = 0;
211.589 + for (j = 1; j <= T->n; j++)
211.590 + { if (glp_ios_can_branch(T, j))
211.591 + { nv++;
211.592 + if (csa->dn_cnt[j] > 0 && csa->up_cnt[j] > 0) ni++;
211.593 + }
211.594 + }
211.595 + xprintf("Pseudocosts initialized for %d of %d variables\n",
211.596 + ni, nv);
211.597 + return;
211.598 +}
211.599 +
211.600 +int ios_pcost_branch(glp_tree *T, int *_next)
211.601 +{ /* choose branching variable with pseudocost branching */
211.602 + glp_long t = xtime();
211.603 + int j, jjj, sel;
211.604 + double beta, psi, d1, d2, d, dmax;
211.605 + /* initialize the working arrays */
211.606 + if (T->pcost == NULL)
211.607 + T->pcost = ios_pcost_init(T);
211.608 + /* nothing has been chosen so far */
211.609 + jjj = 0, dmax = -1.0;
211.610 + /* go through the list of branching candidates */
211.611 + for (j = 1; j <= T->n; j++)
211.612 + { if (!glp_ios_can_branch(T, j)) continue;
211.613 + /* determine primal value of x[j] in optimal solution to LP
211.614 + relaxation of the current subproblem */
211.615 + beta = T->mip->col[j]->prim;
211.616 + /* estimate pseudocost of x[j] for down-branch */
211.617 + psi = eval_psi(T, j, GLP_DN_BRNCH);
211.618 + if (psi == DBL_MAX)
211.619 + { /* down-branch has no primal feasible solution */
211.620 + jjj = j, sel = GLP_DN_BRNCH;
211.621 + goto done;
211.622 + }
211.623 + /* estimate degradation of the objective for down-branch */
211.624 + d1 = psi * (beta - floor(beta));
211.625 + /* estimate pseudocost of x[j] for up-branch */
211.626 + psi = eval_psi(T, j, GLP_UP_BRNCH);
211.627 + if (psi == DBL_MAX)
211.628 + { /* up-branch has no primal feasible solution */
211.629 + jjj = j, sel = GLP_UP_BRNCH;
211.630 + goto done;
211.631 + }
211.632 + /* estimate degradation of the objective for up-branch */
211.633 + d2 = psi * (ceil(beta) - beta);
211.634 + /* determine d = max(d1, d2) */
211.635 + d = (d1 > d2 ? d1 : d2);
211.636 + /* choose x[j] which provides maximal estimated degradation of
211.637 + the objective either in down- or up-branch */
211.638 + if (dmax < d)
211.639 + { dmax = d;
211.640 + jjj = j;
211.641 + /* continue the search from a subproblem, where degradation
211.642 + is less than in other one */
211.643 + sel = (d1 <= d2 ? GLP_DN_BRNCH : GLP_UP_BRNCH);
211.644 + }
211.645 + /* display progress of pseudocost initialization */
211.646 + if (T->parm->msg_lev >= GLP_ON)
211.647 + { if (xdifftime(xtime(), t) >= 10.0)
211.648 + { progress(T);
211.649 + t = xtime();
211.650 + }
211.651 + }
211.652 + }
211.653 + if (dmax == 0.0)
211.654 + { /* no degradation is indicated; choose a variable having most
211.655 + fractional value */
211.656 + jjj = branch_mostf(T, &sel);
211.657 + }
211.658 +done: *_next = sel;
211.659 + return jjj;
211.660 +}
211.661 +
211.662 +/* eof */
212.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
212.2 +++ b/src/glpios10.c Mon Dec 06 13:09:21 2010 +0100
212.3 @@ -0,0 +1,348 @@
212.4 +/* glpios10.c (feasibility pump heuristic) */
212.5 +
212.6 +/***********************************************************************
212.7 +* This code is part of GLPK (GNU Linear Programming Kit).
212.8 +*
212.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
212.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
212.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
212.12 +* E-mail: <mao@gnu.org>.
212.13 +*
212.14 +* GLPK is free software: you can redistribute it and/or modify it
212.15 +* under the terms of the GNU General Public License as published by
212.16 +* the Free Software Foundation, either version 3 of the License, or
212.17 +* (at your option) any later version.
212.18 +*
212.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
212.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
212.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
212.22 +* License for more details.
212.23 +*
212.24 +* You should have received a copy of the GNU General Public License
212.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
212.26 +***********************************************************************/
212.27 +
212.28 +#include "glpios.h"
212.29 +#include "glprng.h"
212.30 +
212.31 +/***********************************************************************
212.32 +* NAME
212.33 +*
212.34 +* ios_feas_pump - feasibility pump heuristic
212.35 +*
212.36 +* SYNOPSIS
212.37 +*
212.38 +* #include "glpios.h"
212.39 +* void ios_feas_pump(glp_tree *T);
212.40 +*
212.41 +* DESCRIPTION
212.42 +*
212.43 +* The routine ios_feas_pump is a simple implementation of the Feasi-
212.44 +* bility Pump heuristic.
212.45 +*
212.46 +* REFERENCES
212.47 +*
212.48 +* M.Fischetti, F.Glover, and A.Lodi. "The feasibility pump." Math.
212.49 +* Program., Ser. A 104, pp. 91-104 (2005). */
212.50 +
212.51 +struct VAR
212.52 +{ /* binary variable */
212.53 + int j;
212.54 + /* ordinal number */
212.55 + int x;
212.56 + /* value in the rounded solution (0 or 1) */
212.57 + double d;
212.58 + /* sorting key */
212.59 +};
212.60 +
212.61 +static int fcmp(const void *x, const void *y)
212.62 +{ /* comparison routine */
212.63 + const struct VAR *vx = x, *vy = y;
212.64 + if (vx->d > vy->d)
212.65 + return -1;
212.66 + else if (vx->d < vy->d)
212.67 + return +1;
212.68 + else
212.69 + return 0;
212.70 +}
212.71 +
212.72 +void ios_feas_pump(glp_tree *T)
212.73 +{ glp_prob *P = T->mip;
212.74 + int n = P->n;
212.75 + glp_prob *lp = NULL;
212.76 + struct VAR *var = NULL;
212.77 + RNG *rand = NULL;
212.78 + GLPCOL *col;
212.79 + glp_smcp parm;
212.80 + int j, k, new_x, nfail, npass, nv, ret, stalling;
212.81 + double dist, tol;
212.82 + xassert(glp_get_status(P) == GLP_OPT);
212.83 + /* this heuristic is applied only once on the root level */
212.84 + if (!(T->curr->level == 0 && T->curr->solved == 1)) goto done;
212.85 + /* determine number of binary variables */
212.86 + nv = 0;
212.87 + for (j = 1; j <= n; j++)
212.88 + { col = P->col[j];
212.89 + /* if x[j] is continuous, skip it */
212.90 + if (col->kind == GLP_CV) continue;
212.91 + /* if x[j] is fixed, skip it */
212.92 + if (col->type == GLP_FX) continue;
212.93 + /* x[j] is non-fixed integer */
212.94 + xassert(col->kind == GLP_IV);
212.95 + if (col->type == GLP_DB && col->lb == 0.0 && col->ub == 1.0)
212.96 + { /* x[j] is binary */
212.97 + nv++;
212.98 + }
212.99 + else
212.100 + { /* x[j] is general integer */
212.101 + if (T->parm->msg_lev >= GLP_MSG_ALL)
212.102 + xprintf("FPUMP heuristic cannot be applied due to genera"
212.103 + "l integer variables\n");
212.104 + goto done;
212.105 + }
212.106 + }
212.107 + /* there must be at least one binary variable */
212.108 + if (nv == 0) goto done;
212.109 + if (T->parm->msg_lev >= GLP_MSG_ALL)
212.110 + xprintf("Applying FPUMP heuristic...\n");
212.111 + /* build the list of binary variables */
212.112 + var = xcalloc(1+nv, sizeof(struct VAR));
212.113 + k = 0;
212.114 + for (j = 1; j <= n; j++)
212.115 + { col = P->col[j];
212.116 + if (col->kind == GLP_IV && col->type == GLP_DB)
212.117 + var[++k].j = j;
212.118 + }
212.119 + xassert(k == nv);
212.120 + /* create working problem object */
212.121 + lp = glp_create_prob();
212.122 +more: /* copy the original problem object to keep it intact */
212.123 + glp_copy_prob(lp, P, GLP_OFF);
212.124 + /* we are interested to find an integer feasible solution, which
212.125 + is better than the best known one */
212.126 + if (P->mip_stat == GLP_FEAS)
212.127 + { int *ind;
212.128 + double *val, bnd;
212.129 + /* add a row and make it identical to the objective row */
212.130 + glp_add_rows(lp, 1);
212.131 + ind = xcalloc(1+n, sizeof(int));
212.132 + val = xcalloc(1+n, sizeof(double));
212.133 + for (j = 1; j <= n; j++)
212.134 + { ind[j] = j;
212.135 + val[j] = P->col[j]->coef;
212.136 + }
212.137 + glp_set_mat_row(lp, lp->m, n, ind, val);
212.138 + xfree(ind);
212.139 + xfree(val);
212.140 + /* introduce upper (minimization) or lower (maximization)
212.141 + bound to the original objective function; note that this
212.142 + additional constraint is not violated at the optimal point
212.143 + to LP relaxation */
212.144 +#if 0 /* modified by xypron <xypron.glpk@gmx.de> */
212.145 + if (P->dir == GLP_MIN)
212.146 + { bnd = P->mip_obj - 0.10 * (1.0 + fabs(P->mip_obj));
212.147 + if (bnd < P->obj_val) bnd = P->obj_val;
212.148 + glp_set_row_bnds(lp, lp->m, GLP_UP, 0.0, bnd - P->c0);
212.149 + }
212.150 + else if (P->dir == GLP_MAX)
212.151 + { bnd = P->mip_obj + 0.10 * (1.0 + fabs(P->mip_obj));
212.152 + if (bnd > P->obj_val) bnd = P->obj_val;
212.153 + glp_set_row_bnds(lp, lp->m, GLP_LO, bnd - P->c0, 0.0);
212.154 + }
212.155 + else
212.156 + xassert(P != P);
212.157 +#else
212.158 + bnd = 0.1 * P->obj_val + 0.9 * P->mip_obj;
212.159 + /* xprintf("bnd = %f\n", bnd); */
212.160 + if (P->dir == GLP_MIN)
212.161 + glp_set_row_bnds(lp, lp->m, GLP_UP, 0.0, bnd - P->c0);
212.162 + else if (P->dir == GLP_MAX)
212.163 + glp_set_row_bnds(lp, lp->m, GLP_LO, bnd - P->c0, 0.0);
212.164 + else
212.165 + xassert(P != P);
212.166 +#endif
212.167 + }
212.168 + /* reset pass count */
212.169 + npass = 0;
212.170 + /* invalidate the rounded point */
212.171 + for (k = 1; k <= nv; k++)
212.172 + var[k].x = -1;
212.173 +pass: /* next pass starts here */
212.174 + npass++;
212.175 + if (T->parm->msg_lev >= GLP_MSG_ALL)
212.176 + xprintf("Pass %d\n", npass);
212.177 + /* initialize minimal distance between the basic point and the
212.178 + rounded one obtained during this pass */
212.179 + dist = DBL_MAX;
212.180 + /* reset failure count (the number of succeeded iterations failed
212.181 + to improve the distance) */
212.182 + nfail = 0;
212.183 + /* if it is not the first pass, perturb the last rounded point
212.184 + rather than construct it from the basic solution */
212.185 + if (npass > 1)
212.186 + { double rho, temp;
212.187 + if (rand == NULL)
212.188 + rand = rng_create_rand();
212.189 + for (k = 1; k <= nv; k++)
212.190 + { j = var[k].j;
212.191 + col = lp->col[j];
212.192 + rho = rng_uniform(rand, -0.3, 0.7);
212.193 + if (rho < 0.0) rho = 0.0;
212.194 + temp = fabs((double)var[k].x - col->prim);
212.195 + if (temp + rho > 0.5) var[k].x = 1 - var[k].x;
212.196 + }
212.197 + goto skip;
212.198 + }
212.199 +loop: /* innermost loop begins here */
212.200 + /* round basic solution (which is assumed primal feasible) */
212.201 + stalling = 1;
212.202 + for (k = 1; k <= nv; k++)
212.203 + { col = lp->col[var[k].j];
212.204 + if (col->prim < 0.5)
212.205 + { /* rounded value is 0 */
212.206 + new_x = 0;
212.207 + }
212.208 + else
212.209 + { /* rounded value is 1 */
212.210 + new_x = 1;
212.211 + }
212.212 + if (var[k].x != new_x)
212.213 + { stalling = 0;
212.214 + var[k].x = new_x;
212.215 + }
212.216 + }
212.217 + /* if the rounded point has not changed (stalling), choose and
212.218 + flip some its entries heuristically */
212.219 + if (stalling)
212.220 + { /* compute d[j] = |x[j] - round(x[j])| */
212.221 + for (k = 1; k <= nv; k++)
212.222 + { col = lp->col[var[k].j];
212.223 + var[k].d = fabs(col->prim - (double)var[k].x);
212.224 + }
212.225 + /* sort the list of binary variables by descending d[j] */
212.226 + qsort(&var[1], nv, sizeof(struct VAR), fcmp);
212.227 + /* choose and flip some rounded components */
212.228 + for (k = 1; k <= nv; k++)
212.229 + { if (k >= 5 && var[k].d < 0.35 || k >= 10) break;
212.230 + var[k].x = 1 - var[k].x;
212.231 + }
212.232 + }
212.233 +skip: /* check if the time limit has been exhausted */
212.234 + if (T->parm->tm_lim < INT_MAX &&
212.235 + (double)(T->parm->tm_lim - 1) <=
212.236 + 1000.0 * xdifftime(xtime(), T->tm_beg)) goto done;
212.237 + /* build the objective, which is the distance between the current
212.238 + (basic) point and the rounded one */
212.239 + lp->dir = GLP_MIN;
212.240 + lp->c0 = 0.0;
212.241 + for (j = 1; j <= n; j++)
212.242 + lp->col[j]->coef = 0.0;
212.243 + for (k = 1; k <= nv; k++)
212.244 + { j = var[k].j;
212.245 + if (var[k].x == 0)
212.246 + lp->col[j]->coef = +1.0;
212.247 + else
212.248 + { lp->col[j]->coef = -1.0;
212.249 + lp->c0 += 1.0;
212.250 + }
212.251 + }
212.252 + /* minimize the distance with the simplex method */
212.253 + glp_init_smcp(&parm);
212.254 + if (T->parm->msg_lev <= GLP_MSG_ERR)
212.255 + parm.msg_lev = T->parm->msg_lev;
212.256 + else if (T->parm->msg_lev <= GLP_MSG_ALL)
212.257 + { parm.msg_lev = GLP_MSG_ON;
212.258 + parm.out_dly = 10000;
212.259 + }
212.260 + ret = glp_simplex(lp, &parm);
212.261 + if (ret != 0)
212.262 + { if (T->parm->msg_lev >= GLP_MSG_ERR)
212.263 + xprintf("Warning: glp_simplex returned %d\n", ret);
212.264 + goto done;
212.265 + }
212.266 + ret = glp_get_status(lp);
212.267 + if (ret != GLP_OPT)
212.268 + { if (T->parm->msg_lev >= GLP_MSG_ERR)
212.269 + xprintf("Warning: glp_get_status returned %d\n", ret);
212.270 + goto done;
212.271 + }
212.272 + if (T->parm->msg_lev >= GLP_MSG_DBG)
212.273 + xprintf("delta = %g\n", lp->obj_val);
212.274 + /* check if the basic solution is integer feasible; note that it
212.275 + may be so even if the minimial distance is positive */
212.276 + tol = 0.3 * T->parm->tol_int;
212.277 + for (k = 1; k <= nv; k++)
212.278 + { col = lp->col[var[k].j];
212.279 + if (tol < col->prim && col->prim < 1.0 - tol) break;
212.280 + }
212.281 + if (k > nv)
212.282 + { /* okay; the basic solution seems to be integer feasible */
212.283 + double *x = xcalloc(1+n, sizeof(double));
212.284 + for (j = 1; j <= n; j++)
212.285 + { x[j] = lp->col[j]->prim;
212.286 + if (P->col[j]->kind == GLP_IV) x[j] = floor(x[j] + 0.5);
212.287 + }
212.288 +#if 1 /* modified by xypron <xypron.glpk@gmx.de> */
212.289 + /* reset direction and right-hand side of objective */
212.290 + lp->c0 = P->c0;
212.291 + lp->dir = P->dir;
212.292 + /* fix integer variables */
212.293 + for (k = 1; k <= nv; k++)
212.294 + { lp->col[var[k].j]->lb = x[var[k].j];
212.295 + lp->col[var[k].j]->ub = x[var[k].j];
212.296 + lp->col[var[k].j]->type = GLP_FX;
212.297 + }
212.298 + /* copy original objective function */
212.299 + for (j = 1; j <= n; j++)
212.300 + lp->col[j]->coef = P->col[j]->coef;
212.301 + /* solve original LP and copy result */
212.302 + ret = glp_simplex(lp, &parm);
212.303 + if (ret != 0)
212.304 + { if (T->parm->msg_lev >= GLP_MSG_ERR)
212.305 + xprintf("Warning: glp_simplex returned %d\n", ret);
212.306 + goto done;
212.307 + }
212.308 + ret = glp_get_status(lp);
212.309 + if (ret != GLP_OPT)
212.310 + { if (T->parm->msg_lev >= GLP_MSG_ERR)
212.311 + xprintf("Warning: glp_get_status returned %d\n", ret);
212.312 + goto done;
212.313 + }
212.314 + for (j = 1; j <= n; j++)
212.315 + if (P->col[j]->kind != GLP_IV) x[j] = lp->col[j]->prim;
212.316 +#endif
212.317 + ret = glp_ios_heur_sol(T, x);
212.318 + xfree(x);
212.319 + if (ret == 0)
212.320 + { /* the integer solution is accepted */
212.321 + if (ios_is_hopeful(T, T->curr->bound))
212.322 + { /* it is reasonable to apply the heuristic once again */
212.323 + goto more;
212.324 + }
212.325 + else
212.326 + { /* the best known integer feasible solution just found
212.327 + is close to optimal solution to LP relaxation */
212.328 + goto done;
212.329 + }
212.330 + }
212.331 + }
212.332 + /* the basic solution is fractional */
212.333 + if (dist == DBL_MAX ||
212.334 + lp->obj_val <= dist - 1e-6 * (1.0 + dist))
212.335 + { /* the distance is reducing */
212.336 + nfail = 0, dist = lp->obj_val;
212.337 + }
212.338 + else
212.339 + { /* improving the distance failed */
212.340 + nfail++;
212.341 + }
212.342 + if (nfail < 3) goto loop;
212.343 + if (npass < 5) goto pass;
212.344 +done: /* delete working objects */
212.345 + if (lp != NULL) glp_delete_prob(lp);
212.346 + if (var != NULL) xfree(var);
212.347 + if (rand != NULL) rng_delete_rand(rand);
212.348 + return;
212.349 +}
212.350 +
212.351 +/* eof */
213.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
213.2 +++ b/src/glpios11.c Mon Dec 06 13:09:21 2010 +0100
213.3 @@ -0,0 +1,280 @@
213.4 +/* glpios11.c (process cuts stored in the local cut pool) */
213.5 +
213.6 +/***********************************************************************
213.7 +* This code is part of GLPK (GNU Linear Programming Kit).
213.8 +*
213.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
213.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
213.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
213.12 +* E-mail: <mao@gnu.org>.
213.13 +*
213.14 +* GLPK is free software: you can redistribute it and/or modify it
213.15 +* under the terms of the GNU General Public License as published by
213.16 +* the Free Software Foundation, either version 3 of the License, or
213.17 +* (at your option) any later version.
213.18 +*
213.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
213.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
213.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
213.22 +* License for more details.
213.23 +*
213.24 +* You should have received a copy of the GNU General Public License
213.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
213.26 +***********************************************************************/
213.27 +
213.28 +#include "glpios.h"
213.29 +
213.30 +/***********************************************************************
213.31 +* NAME
213.32 +*
213.33 +* ios_process_cuts - process cuts stored in the local cut pool
213.34 +*
213.35 +* SYNOPSIS
213.36 +*
213.37 +* #include "glpios.h"
213.38 +* void ios_process_cuts(glp_tree *T);
213.39 +*
213.40 +* DESCRIPTION
213.41 +*
213.42 +* The routine ios_process_cuts analyzes each cut currently stored in
213.43 +* the local cut pool, which must be non-empty, and either adds the cut
213.44 +* to the current subproblem or just discards it. All cuts are assumed
213.45 +* to be locally valid. On exit the local cut pool remains unchanged.
213.46 +*
213.47 +* REFERENCES
213.48 +*
213.49 +* 1. E.Balas, S.Ceria, G.Cornuejols, "Mixed 0-1 Programming by
213.50 +* Lift-and-Project in a Branch-and-Cut Framework", Management Sc.,
213.51 +* 42 (1996) 1229-1246.
213.52 +*
213.53 +* 2. G.Andreello, A.Caprara, and M.Fischetti, "Embedding Cuts in
213.54 +* a Branch&Cut Framework: a Computational Study with {0,1/2}-Cuts",
213.55 +* Preliminary Draft, October 28, 2003, pp.6-8. */
213.56 +
213.57 +struct info
213.58 +{ /* estimated cut efficiency */
213.59 + IOSCUT *cut;
213.60 + /* pointer to cut in the cut pool */
213.61 + char flag;
213.62 + /* if this flag is set, the cut is included into the current
213.63 + subproblem */
213.64 + double eff;
213.65 + /* cut efficacy (normalized residual) */
213.66 + double deg;
213.67 + /* lower bound to objective degradation */
213.68 +};
213.69 +
213.70 +static int fcmp(const void *arg1, const void *arg2)
213.71 +{ const struct info *info1 = arg1, *info2 = arg2;
213.72 + if (info1->deg == 0.0 && info2->deg == 0.0)
213.73 + { if (info1->eff > info2->eff) return -1;
213.74 + if (info1->eff < info2->eff) return +1;
213.75 + }
213.76 + else
213.77 + { if (info1->deg > info2->deg) return -1;
213.78 + if (info1->deg < info2->deg) return +1;
213.79 + }
213.80 + return 0;
213.81 +}
213.82 +
213.83 +static double parallel(IOSCUT *a, IOSCUT *b, double work[]);
213.84 +
213.85 +void ios_process_cuts(glp_tree *T)
213.86 +{ IOSPOOL *pool;
213.87 + IOSCUT *cut;
213.88 + IOSAIJ *aij;
213.89 + struct info *info;
213.90 + int k, kk, max_cuts, len, ret, *ind;
213.91 + double *val, *work;
213.92 + /* the current subproblem must exist */
213.93 + xassert(T->curr != NULL);
213.94 + /* the pool must exist and be non-empty */
213.95 + pool = T->local;
213.96 + xassert(pool != NULL);
213.97 + xassert(pool->size > 0);
213.98 + /* allocate working arrays */
213.99 + info = xcalloc(1+pool->size, sizeof(struct info));
213.100 + ind = xcalloc(1+T->n, sizeof(int));
213.101 + val = xcalloc(1+T->n, sizeof(double));
213.102 + work = xcalloc(1+T->n, sizeof(double));
213.103 + for (k = 1; k <= T->n; k++) work[k] = 0.0;
213.104 + /* build the list of cuts stored in the cut pool */
213.105 + for (k = 0, cut = pool->head; cut != NULL; cut = cut->next)
213.106 + k++, info[k].cut = cut, info[k].flag = 0;
213.107 + xassert(k == pool->size);
213.108 + /* estimate efficiency of all cuts in the cut pool */
213.109 + for (k = 1; k <= pool->size; k++)
213.110 + { double temp, dy, dz;
213.111 + cut = info[k].cut;
213.112 + /* build the vector of cut coefficients and compute its
213.113 + Euclidean norm */
213.114 + len = 0; temp = 0.0;
213.115 + for (aij = cut->ptr; aij != NULL; aij = aij->next)
213.116 + { xassert(1 <= aij->j && aij->j <= T->n);
213.117 + len++, ind[len] = aij->j, val[len] = aij->val;
213.118 + temp += aij->val * aij->val;
213.119 + }
213.120 + if (temp < DBL_EPSILON * DBL_EPSILON) temp = DBL_EPSILON;
213.121 + /* transform the cut to express it only through non-basic
213.122 + (auxiliary and structural) variables */
213.123 + len = glp_transform_row(T->mip, len, ind, val);
213.124 + /* determine change in the cut value and in the objective
213.125 + value for the adjacent basis by simulating one step of the
213.126 + dual simplex */
213.127 + ret = _glp_analyze_row(T->mip, len, ind, val, cut->type,
213.128 + cut->rhs, 1e-9, NULL, NULL, NULL, NULL, &dy, &dz);
213.129 + /* determine normalized residual and lower bound to objective
213.130 + degradation */
213.131 + if (ret == 0)
213.132 + { info[k].eff = fabs(dy) / sqrt(temp);
213.133 + /* if some reduced costs violates (slightly) their zero
213.134 + bounds (i.e. have wrong signs) due to round-off errors,
213.135 + dz also may have wrong sign being close to zero */
213.136 + if (T->mip->dir == GLP_MIN)
213.137 + { if (dz < 0.0) dz = 0.0;
213.138 + info[k].deg = + dz;
213.139 + }
213.140 + else /* GLP_MAX */
213.141 + { if (dz > 0.0) dz = 0.0;
213.142 + info[k].deg = - dz;
213.143 + }
213.144 + }
213.145 + else if (ret == 1)
213.146 + { /* the constraint is not violated at the current point */
213.147 + info[k].eff = info[k].deg = 0.0;
213.148 + }
213.149 + else if (ret == 2)
213.150 + { /* no dual feasible adjacent basis exists */
213.151 + info[k].eff = 1.0;
213.152 + info[k].deg = DBL_MAX;
213.153 + }
213.154 + else
213.155 + xassert(ret != ret);
213.156 + /* if the degradation is too small, just ignore it */
213.157 + if (info[k].deg < 0.01) info[k].deg = 0.0;
213.158 + }
213.159 + /* sort the list of cuts by decreasing objective degradation and
213.160 + then by decreasing efficacy */
213.161 + qsort(&info[1], pool->size, sizeof(struct info), fcmp);
213.162 + /* only first (most efficient) max_cuts in the list are qualified
213.163 + as candidates to be added to the current subproblem */
213.164 + max_cuts = (T->curr->level == 0 ? 90 : 10);
213.165 + if (max_cuts > pool->size) max_cuts = pool->size;
213.166 + /* add cuts to the current subproblem */
213.167 +#if 0
213.168 + xprintf("*** adding cuts ***\n");
213.169 +#endif
213.170 + for (k = 1; k <= max_cuts; k++)
213.171 + { int i, len;
213.172 + /* if this cut seems to be inefficient, skip it */
213.173 + if (info[k].deg < 0.01 && info[k].eff < 0.01) continue;
213.174 + /* if the angle between this cut and every other cut included
213.175 + in the current subproblem is small, skip this cut */
213.176 + for (kk = 1; kk < k; kk++)
213.177 + { if (info[kk].flag)
213.178 + { if (parallel(info[k].cut, info[kk].cut, work) > 0.90)
213.179 + break;
213.180 + }
213.181 + }
213.182 + if (kk < k) continue;
213.183 + /* add this cut to the current subproblem */
213.184 +#if 0
213.185 + xprintf("eff = %g; deg = %g\n", info[k].eff, info[k].deg);
213.186 +#endif
213.187 + cut = info[k].cut, info[k].flag = 1;
213.188 + i = glp_add_rows(T->mip, 1);
213.189 + if (cut->name != NULL)
213.190 + glp_set_row_name(T->mip, i, cut->name);
213.191 + xassert(T->mip->row[i]->origin == GLP_RF_CUT);
213.192 + T->mip->row[i]->klass = cut->klass;
213.193 + len = 0;
213.194 + for (aij = cut->ptr; aij != NULL; aij = aij->next)
213.195 + len++, ind[len] = aij->j, val[len] = aij->val;
213.196 + glp_set_mat_row(T->mip, i, len, ind, val);
213.197 + xassert(cut->type == GLP_LO || cut->type == GLP_UP);
213.198 + glp_set_row_bnds(T->mip, i, cut->type, cut->rhs, cut->rhs);
213.199 + }
213.200 + /* free working arrays */
213.201 + xfree(info);
213.202 + xfree(ind);
213.203 + xfree(val);
213.204 + xfree(work);
213.205 + return;
213.206 +}
213.207 +
213.208 +#if 0
213.209 +/***********************************************************************
213.210 +* Given a cut a * x >= b (<= b) the routine efficacy computes the cut
213.211 +* efficacy as follows:
213.212 +*
213.213 +* eff = d * (a * x~ - b) / ||a||,
213.214 +*
213.215 +* where d is -1 (in case of '>= b') or +1 (in case of '<= b'), x~ is
213.216 +* the vector of values of structural variables in optimal solution to
213.217 +* LP relaxation of the current subproblem, ||a|| is the Euclidean norm
213.218 +* of the vector of cut coefficients.
213.219 +*
213.220 +* If the cut is violated at point x~, the efficacy eff is positive,
213.221 +* and its value is the Euclidean distance between x~ and the cut plane
213.222 +* a * x = b in the space of structural variables.
213.223 +*
213.224 +* Following geometrical intuition, it is quite natural to consider
213.225 +* this distance as a first-order measure of the expected efficacy of
213.226 +* the cut: the larger the distance the better the cut [1]. */
213.227 +
213.228 +static double efficacy(glp_tree *T, IOSCUT *cut)
213.229 +{ glp_prob *mip = T->mip;
213.230 + IOSAIJ *aij;
213.231 + double s = 0.0, t = 0.0, temp;
213.232 + for (aij = cut->ptr; aij != NULL; aij = aij->next)
213.233 + { xassert(1 <= aij->j && aij->j <= mip->n);
213.234 + s += aij->val * mip->col[aij->j]->prim;
213.235 + t += aij->val * aij->val;
213.236 + }
213.237 + temp = sqrt(t);
213.238 + if (temp < DBL_EPSILON) temp = DBL_EPSILON;
213.239 + if (cut->type == GLP_LO)
213.240 + temp = (s >= cut->rhs ? 0.0 : (cut->rhs - s) / temp);
213.241 + else if (cut->type == GLP_UP)
213.242 + temp = (s <= cut->rhs ? 0.0 : (s - cut->rhs) / temp);
213.243 + else
213.244 + xassert(cut != cut);
213.245 + return temp;
213.246 +}
213.247 +#endif
213.248 +
213.249 +/***********************************************************************
213.250 +* Given two cuts a1 * x >= b1 (<= b1) and a2 * x >= b2 (<= b2) the
213.251 +* routine parallel computes the cosine of angle between the cut planes
213.252 +* a1 * x = b1 and a2 * x = b2 (which is the acute angle between two
213.253 +* normals to these planes) in the space of structural variables as
213.254 +* follows:
213.255 +*
213.256 +* cos phi = (a1' * a2) / (||a1|| * ||a2||),
213.257 +*
213.258 +* where (a1' * a2) is a dot product of vectors of cut coefficients,
213.259 +* ||a1|| and ||a2|| are Euclidean norms of vectors a1 and a2.
213.260 +*
213.261 +* Note that requirement cos phi = 0 forces the cuts to be orthogonal,
213.262 +* i.e. with disjoint support, while requirement cos phi <= 0.999 means
213.263 +* only avoiding duplicate (parallel) cuts [1]. */
213.264 +
213.265 +static double parallel(IOSCUT *a, IOSCUT *b, double work[])
213.266 +{ IOSAIJ *aij;
213.267 + double s = 0.0, sa = 0.0, sb = 0.0, temp;
213.268 + for (aij = a->ptr; aij != NULL; aij = aij->next)
213.269 + { work[aij->j] = aij->val;
213.270 + sa += aij->val * aij->val;
213.271 + }
213.272 + for (aij = b->ptr; aij != NULL; aij = aij->next)
213.273 + { s += work[aij->j] * aij->val;
213.274 + sb += aij->val * aij->val;
213.275 + }
213.276 + for (aij = a->ptr; aij != NULL; aij = aij->next)
213.277 + work[aij->j] = 0.0;
213.278 + temp = sqrt(sa) * sqrt(sb);
213.279 + if (temp < DBL_EPSILON * DBL_EPSILON) temp = DBL_EPSILON;
213.280 + return s / temp;
213.281 +}
213.282 +
213.283 +/* eof */
214.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
214.2 +++ b/src/glpios12.c Mon Dec 06 13:09:21 2010 +0100
214.3 @@ -0,0 +1,176 @@
214.4 +/* glpios12.c (node selection heuristics) */
214.5 +
214.6 +/***********************************************************************
214.7 +* This code is part of GLPK (GNU Linear Programming Kit).
214.8 +*
214.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
214.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
214.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
214.12 +* E-mail: <mao@gnu.org>.
214.13 +*
214.14 +* GLPK is free software: you can redistribute it and/or modify it
214.15 +* under the terms of the GNU General Public License as published by
214.16 +* the Free Software Foundation, either version 3 of the License, or
214.17 +* (at your option) any later version.
214.18 +*
214.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
214.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
214.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
214.22 +* License for more details.
214.23 +*
214.24 +* You should have received a copy of the GNU General Public License
214.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
214.26 +***********************************************************************/
214.27 +
214.28 +#include "glpios.h"
214.29 +
214.30 +/***********************************************************************
214.31 +* NAME
214.32 +*
214.33 +* ios_choose_node - select subproblem to continue the search
214.34 +*
214.35 +* SYNOPSIS
214.36 +*
214.37 +* #include "glpios.h"
214.38 +* int ios_choose_node(glp_tree *T);
214.39 +*
214.40 +* DESCRIPTION
214.41 +*
214.42 +* The routine ios_choose_node selects a subproblem from the active
214.43 +* list to continue the search. The choice depends on the backtracking
214.44 +* technique option.
214.45 +*
214.46 +* RETURNS
214.47 +*
214.48 +* The routine ios_choose_node return the reference number of the
214.49 +* subproblem selected. */
214.50 +
214.51 +static int most_feas(glp_tree *T);
214.52 +static int best_proj(glp_tree *T);
214.53 +static int best_node(glp_tree *T);
214.54 +
214.55 +int ios_choose_node(glp_tree *T)
214.56 +{ int p;
214.57 + if (T->parm->bt_tech == GLP_BT_DFS)
214.58 + { /* depth first search */
214.59 + xassert(T->tail != NULL);
214.60 + p = T->tail->p;
214.61 + }
214.62 + else if (T->parm->bt_tech == GLP_BT_BFS)
214.63 + { /* breadth first search */
214.64 + xassert(T->head != NULL);
214.65 + p = T->head->p;
214.66 + }
214.67 + else if (T->parm->bt_tech == GLP_BT_BLB)
214.68 + { /* select node with best local bound */
214.69 + p = best_node(T);
214.70 + }
214.71 + else if (T->parm->bt_tech == GLP_BT_BPH)
214.72 + { if (T->mip->mip_stat == GLP_UNDEF)
214.73 + { /* "most integer feasible" subproblem */
214.74 + p = most_feas(T);
214.75 + }
214.76 + else
214.77 + { /* best projection heuristic */
214.78 + p = best_proj(T);
214.79 + }
214.80 + }
214.81 + else
214.82 + xassert(T != T);
214.83 + return p;
214.84 +}
214.85 +
214.86 +static int most_feas(glp_tree *T)
214.87 +{ /* select subproblem whose parent has minimal sum of integer
214.88 + infeasibilities */
214.89 + IOSNPD *node;
214.90 + int p;
214.91 + double best;
214.92 + p = 0, best = DBL_MAX;
214.93 + for (node = T->head; node != NULL; node = node->next)
214.94 + { xassert(node->up != NULL);
214.95 + if (best > node->up->ii_sum)
214.96 + p = node->p, best = node->up->ii_sum;
214.97 + }
214.98 + return p;
214.99 +}
214.100 +
214.101 +static int best_proj(glp_tree *T)
214.102 +{ /* select subproblem using the best projection heuristic */
214.103 + IOSNPD *root, *node;
214.104 + int p;
214.105 + double best, deg, obj;
214.106 + /* the global bound must exist */
214.107 + xassert(T->mip->mip_stat == GLP_FEAS);
214.108 + /* obtain pointer to the root node, which must exist */
214.109 + root = T->slot[1].node;
214.110 + xassert(root != NULL);
214.111 + /* deg estimates degradation of the objective function per unit
214.112 + of the sum of integer infeasibilities */
214.113 + xassert(root->ii_sum > 0.0);
214.114 + deg = (T->mip->mip_obj - root->bound) / root->ii_sum;
214.115 + /* nothing has been selected so far */
214.116 + p = 0, best = DBL_MAX;
214.117 + /* walk through the list of active subproblems */
214.118 + for (node = T->head; node != NULL; node = node->next)
214.119 + { xassert(node->up != NULL);
214.120 + /* obj estimates optimal objective value if the sum of integer
214.121 + infeasibilities were zero */
214.122 + obj = node->up->bound + deg * node->up->ii_sum;
214.123 + if (T->mip->dir == GLP_MAX) obj = - obj;
214.124 + /* select the subproblem which has the best estimated optimal
214.125 + objective value */
214.126 + if (best > obj) p = node->p, best = obj;
214.127 + }
214.128 + return p;
214.129 +}
214.130 +
214.131 +static int best_node(glp_tree *T)
214.132 +{ /* select subproblem with best local bound */
214.133 + IOSNPD *node, *best = NULL;
214.134 + double bound, eps;
214.135 + switch (T->mip->dir)
214.136 + { case GLP_MIN:
214.137 + bound = +DBL_MAX;
214.138 + for (node = T->head; node != NULL; node = node->next)
214.139 + if (bound > node->bound) bound = node->bound;
214.140 + xassert(bound != +DBL_MAX);
214.141 + eps = 0.001 * (1.0 + fabs(bound));
214.142 + for (node = T->head; node != NULL; node = node->next)
214.143 + { if (node->bound <= bound + eps)
214.144 + { xassert(node->up != NULL);
214.145 + if (best == NULL ||
214.146 +#if 1
214.147 + best->up->ii_sum > node->up->ii_sum) best = node;
214.148 +#else
214.149 + best->lp_obj > node->lp_obj) best = node;
214.150 +#endif
214.151 + }
214.152 + }
214.153 + break;
214.154 + case GLP_MAX:
214.155 + bound = -DBL_MAX;
214.156 + for (node = T->head; node != NULL; node = node->next)
214.157 + if (bound < node->bound) bound = node->bound;
214.158 + xassert(bound != -DBL_MAX);
214.159 + eps = 0.001 * (1.0 + fabs(bound));
214.160 + for (node = T->head; node != NULL; node = node->next)
214.161 + { if (node->bound >= bound - eps)
214.162 + { xassert(node->up != NULL);
214.163 + if (best == NULL ||
214.164 +#if 1
214.165 + best->up->ii_sum > node->up->ii_sum) best = node;
214.166 +#else
214.167 + best->lp_obj < node->lp_obj) best = node;
214.168 +#endif
214.169 + }
214.170 + }
214.171 + break;
214.172 + default:
214.173 + xassert(T != T);
214.174 + }
214.175 + xassert(best != NULL);
214.176 + return best->p;
214.177 +}
214.178 +
214.179 +/* eof */
215.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
215.2 +++ b/src/glpipm.c Mon Dec 06 13:09:21 2010 +0100
215.3 @@ -0,0 +1,1143 @@
215.4 +/* glpipm.c */
215.5 +
215.6 +/***********************************************************************
215.7 +* This code is part of GLPK (GNU Linear Programming Kit).
215.8 +*
215.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
215.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
215.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
215.12 +* E-mail: <mao@gnu.org>.
215.13 +*
215.14 +* GLPK is free software: you can redistribute it and/or modify it
215.15 +* under the terms of the GNU General Public License as published by
215.16 +* the Free Software Foundation, either version 3 of the License, or
215.17 +* (at your option) any later version.
215.18 +*
215.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
215.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
215.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
215.22 +* License for more details.
215.23 +*
215.24 +* You should have received a copy of the GNU General Public License
215.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
215.26 +***********************************************************************/
215.27 +
215.28 +#include "glpipm.h"
215.29 +#include "glpmat.h"
215.30 +
215.31 +#define ITER_MAX 100
215.32 +/* maximal number of iterations */
215.33 +
215.34 +struct csa
215.35 +{ /* common storage area */
215.36 + /*--------------------------------------------------------------*/
215.37 + /* LP data */
215.38 + int m;
215.39 + /* number of rows (equality constraints) */
215.40 + int n;
215.41 + /* number of columns (structural variables) */
215.42 + int *A_ptr; /* int A_ptr[1+m+1]; */
215.43 + int *A_ind; /* int A_ind[A_ptr[m+1]]; */
215.44 + double *A_val; /* double A_val[A_ptr[m+1]]; */
215.45 + /* mxn-matrix A in storage-by-rows format */
215.46 + double *b; /* double b[1+m]; */
215.47 + /* m-vector b of right-hand sides */
215.48 + double *c; /* double c[1+n]; */
215.49 + /* n-vector c of objective coefficients; c[0] is constant term of
215.50 + the objective function */
215.51 + /*--------------------------------------------------------------*/
215.52 + /* LP solution */
215.53 + double *x; /* double x[1+n]; */
215.54 + double *y; /* double y[1+m]; */
215.55 + double *z; /* double z[1+n]; */
215.56 + /* current point in primal-dual space; the best point on exit */
215.57 + /*--------------------------------------------------------------*/
215.58 + /* control parameters */
215.59 + const glp_iptcp *parm;
215.60 + /*--------------------------------------------------------------*/
215.61 + /* working arrays and variables */
215.62 + double *D; /* double D[1+n]; */
215.63 + /* diagonal nxn-matrix D = X*inv(Z), where X = diag(x[j]) and
215.64 + Z = diag(z[j]) */
215.65 + int *P; /* int P[1+m+m]; */
215.66 + /* permutation mxm-matrix P used to minimize fill-in in Cholesky
215.67 + factorization */
215.68 + int *S_ptr; /* int S_ptr[1+m+1]; */
215.69 + int *S_ind; /* int S_ind[S_ptr[m+1]]; */
215.70 + double *S_val; /* double S_val[S_ptr[m+1]]; */
215.71 + double *S_diag; /* double S_diag[1+m]; */
215.72 + /* symmetric mxm-matrix S = P*A*D*A'*P' whose upper triangular
215.73 + part without diagonal elements is stored in S_ptr, S_ind, and
215.74 + S_val in storage-by-rows format, diagonal elements are stored
215.75 + in S_diag */
215.76 + int *U_ptr; /* int U_ptr[1+m+1]; */
215.77 + int *U_ind; /* int U_ind[U_ptr[m+1]]; */
215.78 + double *U_val; /* double U_val[U_ptr[m+1]]; */
215.79 + double *U_diag; /* double U_diag[1+m]; */
215.80 + /* upper triangular mxm-matrix U defining Cholesky factorization
215.81 + S = U'*U; its non-diagonal elements are stored in U_ptr, U_ind,
215.82 + U_val in storage-by-rows format, diagonal elements are stored
215.83 + in U_diag */
215.84 + int iter;
215.85 + /* iteration number (0, 1, 2, ...); iter = 0 corresponds to the
215.86 + initial point */
215.87 + double obj;
215.88 + /* current value of the objective function */
215.89 + double rpi;
215.90 + /* relative primal infeasibility rpi = ||A*x-b||/(1+||b||) */
215.91 + double rdi;
215.92 + /* relative dual infeasibility rdi = ||A'*y+z-c||/(1+||c||) */
215.93 + double gap;
215.94 + /* primal-dual gap = |c'*x-b'*y|/(1+|c'*x|) which is a relative
215.95 + difference between primal and dual objective functions */
215.96 + double phi;
215.97 + /* merit function phi = ||A*x-b||/max(1,||b||) +
215.98 + + ||A'*y+z-c||/max(1,||c||) +
215.99 + + |c'*x-b'*y|/max(1,||b||,||c||) */
215.100 + double mu;
215.101 + /* duality measure mu = x'*z/n (used as barrier parameter) */
215.102 + double rmu;
215.103 + /* rmu = max(||A*x-b||,||A'*y+z-c||)/mu */
215.104 + double rmu0;
215.105 + /* the initial value of rmu on iteration 0 */
215.106 + double *phi_min; /* double phi_min[1+ITER_MAX]; */
215.107 + /* phi_min[k] = min(phi[k]), where phi[k] is the value of phi on
215.108 + k-th iteration, 0 <= k <= iter */
215.109 + int best_iter;
215.110 + /* iteration number, on which the value of phi reached its best
215.111 + (minimal) value */
215.112 + double *best_x; /* double best_x[1+n]; */
215.113 + double *best_y; /* double best_y[1+m]; */
215.114 + double *best_z; /* double best_z[1+n]; */
215.115 + /* best point (in the sense of the merit function phi) which has
215.116 + been reached on iteration iter_best */
215.117 + double best_obj;
215.118 + /* objective value at the best point */
215.119 + double *dx_aff; /* double dx_aff[1+n]; */
215.120 + double *dy_aff; /* double dy_aff[1+m]; */
215.121 + double *dz_aff; /* double dz_aff[1+n]; */
215.122 + /* affine scaling direction */
215.123 + double alfa_aff_p, alfa_aff_d;
215.124 + /* maximal primal and dual stepsizes in affine scaling direction,
215.125 + on which x and z are still non-negative */
215.126 + double mu_aff;
215.127 + /* duality measure mu_aff = x_aff'*z_aff/n in the boundary point
215.128 + x_aff' = x+alfa_aff_p*dx_aff, z_aff' = z+alfa_aff_d*dz_aff */
215.129 + double sigma;
215.130 + /* Mehrotra's heuristic parameter (0 <= sigma <= 1) */
215.131 + double *dx_cc; /* double dx_cc[1+n]; */
215.132 + double *dy_cc; /* double dy_cc[1+m]; */
215.133 + double *dz_cc; /* double dz_cc[1+n]; */
215.134 + /* centering corrector direction */
215.135 + double *dx; /* double dx[1+n]; */
215.136 + double *dy; /* double dy[1+m]; */
215.137 + double *dz; /* double dz[1+n]; */
215.138 + /* final combined direction dx = dx_aff+dx_cc, dy = dy_aff+dy_cc,
215.139 + dz = dz_aff+dz_cc */
215.140 + double alfa_max_p;
215.141 + double alfa_max_d;
215.142 + /* maximal primal and dual stepsizes in combined direction, on
215.143 + which x and z are still non-negative */
215.144 +};
215.145 +
215.146 +/***********************************************************************
215.147 +* initialize - allocate and initialize common storage area
215.148 +*
215.149 +* This routine allocates and initializes the common storage area (CSA)
215.150 +* used by interior-point method routines. */
215.151 +
215.152 +static void initialize(struct csa *csa)
215.153 +{ int m = csa->m;
215.154 + int n = csa->n;
215.155 + int i;
215.156 + if (csa->parm->msg_lev >= GLP_MSG_ALL)
215.157 + xprintf("Matrix A has %d non-zeros\n", csa->A_ptr[m+1]-1);
215.158 + csa->D = xcalloc(1+n, sizeof(double));
215.159 + /* P := I */
215.160 + csa->P = xcalloc(1+m+m, sizeof(int));
215.161 + for (i = 1; i <= m; i++) csa->P[i] = csa->P[m+i] = i;
215.162 + /* S := A*A', symbolically */
215.163 + csa->S_ptr = xcalloc(1+m+1, sizeof(int));
215.164 + csa->S_ind = adat_symbolic(m, n, csa->P, csa->A_ptr, csa->A_ind,
215.165 + csa->S_ptr);
215.166 + if (csa->parm->msg_lev >= GLP_MSG_ALL)
215.167 + xprintf("Matrix S = A*A' has %d non-zeros (upper triangle)\n",
215.168 + csa->S_ptr[m+1]-1 + m);
215.169 + /* determine P using specified ordering algorithm */
215.170 + if (csa->parm->ord_alg == GLP_ORD_NONE)
215.171 + { if (csa->parm->msg_lev >= GLP_MSG_ALL)
215.172 + xprintf("Original ordering is being used\n");
215.173 + for (i = 1; i <= m; i++)
215.174 + csa->P[i] = csa->P[m+i] = i;
215.175 + }
215.176 + else if (csa->parm->ord_alg == GLP_ORD_QMD)
215.177 + { if (csa->parm->msg_lev >= GLP_MSG_ALL)
215.178 + xprintf("Minimum degree ordering (QMD)...\n");
215.179 + min_degree(m, csa->S_ptr, csa->S_ind, csa->P);
215.180 + }
215.181 + else if (csa->parm->ord_alg == GLP_ORD_AMD)
215.182 + { if (csa->parm->msg_lev >= GLP_MSG_ALL)
215.183 + xprintf("Approximate minimum degree ordering (AMD)...\n");
215.184 + amd_order1(m, csa->S_ptr, csa->S_ind, csa->P);
215.185 + }
215.186 + else if (csa->parm->ord_alg == GLP_ORD_SYMAMD)
215.187 + { if (csa->parm->msg_lev >= GLP_MSG_ALL)
215.188 + xprintf("Approximate minimum degree ordering (SYMAMD)...\n")
215.189 + ;
215.190 + symamd_ord(m, csa->S_ptr, csa->S_ind, csa->P);
215.191 + }
215.192 + else
215.193 + xassert(csa != csa);
215.194 + /* S := P*A*A'*P', symbolically */
215.195 + xfree(csa->S_ind);
215.196 + csa->S_ind = adat_symbolic(m, n, csa->P, csa->A_ptr, csa->A_ind,
215.197 + csa->S_ptr);
215.198 + csa->S_val = xcalloc(csa->S_ptr[m+1], sizeof(double));
215.199 + csa->S_diag = xcalloc(1+m, sizeof(double));
215.200 + /* compute Cholesky factorization S = U'*U, symbolically */
215.201 + if (csa->parm->msg_lev >= GLP_MSG_ALL)
215.202 + xprintf("Computing Cholesky factorization S = L*L'...\n");
215.203 + csa->U_ptr = xcalloc(1+m+1, sizeof(int));
215.204 + csa->U_ind = chol_symbolic(m, csa->S_ptr, csa->S_ind, csa->U_ptr);
215.205 + if (csa->parm->msg_lev >= GLP_MSG_ALL)
215.206 + xprintf("Matrix L has %d non-zeros\n", csa->U_ptr[m+1]-1 + m);
215.207 + csa->U_val = xcalloc(csa->U_ptr[m+1], sizeof(double));
215.208 + csa->U_diag = xcalloc(1+m, sizeof(double));
215.209 + csa->iter = 0;
215.210 + csa->obj = 0.0;
215.211 + csa->rpi = 0.0;
215.212 + csa->rdi = 0.0;
215.213 + csa->gap = 0.0;
215.214 + csa->phi = 0.0;
215.215 + csa->mu = 0.0;
215.216 + csa->rmu = 0.0;
215.217 + csa->rmu0 = 0.0;
215.218 + csa->phi_min = xcalloc(1+ITER_MAX, sizeof(double));
215.219 + csa->best_iter = 0;
215.220 + csa->best_x = xcalloc(1+n, sizeof(double));
215.221 + csa->best_y = xcalloc(1+m, sizeof(double));
215.222 + csa->best_z = xcalloc(1+n, sizeof(double));
215.223 + csa->best_obj = 0.0;
215.224 + csa->dx_aff = xcalloc(1+n, sizeof(double));
215.225 + csa->dy_aff = xcalloc(1+m, sizeof(double));
215.226 + csa->dz_aff = xcalloc(1+n, sizeof(double));
215.227 + csa->alfa_aff_p = 0.0;
215.228 + csa->alfa_aff_d = 0.0;
215.229 + csa->mu_aff = 0.0;
215.230 + csa->sigma = 0.0;
215.231 + csa->dx_cc = xcalloc(1+n, sizeof(double));
215.232 + csa->dy_cc = xcalloc(1+m, sizeof(double));
215.233 + csa->dz_cc = xcalloc(1+n, sizeof(double));
215.234 + csa->dx = csa->dx_aff;
215.235 + csa->dy = csa->dy_aff;
215.236 + csa->dz = csa->dz_aff;
215.237 + csa->alfa_max_p = 0.0;
215.238 + csa->alfa_max_d = 0.0;
215.239 + return;
215.240 +}
215.241 +
215.242 +/***********************************************************************
215.243 +* A_by_vec - compute y = A*x
215.244 +*
215.245 +* This routine computes matrix-vector product y = A*x, where A is the
215.246 +* constraint matrix. */
215.247 +
215.248 +static void A_by_vec(struct csa *csa, double x[], double y[])
215.249 +{ /* compute y = A*x */
215.250 + int m = csa->m;
215.251 + int *A_ptr = csa->A_ptr;
215.252 + int *A_ind = csa->A_ind;
215.253 + double *A_val = csa->A_val;
215.254 + int i, t, beg, end;
215.255 + double temp;
215.256 + for (i = 1; i <= m; i++)
215.257 + { temp = 0.0;
215.258 + beg = A_ptr[i], end = A_ptr[i+1];
215.259 + for (t = beg; t < end; t++) temp += A_val[t] * x[A_ind[t]];
215.260 + y[i] = temp;
215.261 + }
215.262 + return;
215.263 +}
215.264 +
215.265 +/***********************************************************************
215.266 +* AT_by_vec - compute y = A'*x
215.267 +*
215.268 +* This routine computes matrix-vector product y = A'*x, where A' is a
215.269 +* matrix transposed to the constraint matrix A. */
215.270 +
215.271 +static void AT_by_vec(struct csa *csa, double x[], double y[])
215.272 +{ /* compute y = A'*x, where A' is transposed to A */
215.273 + int m = csa->m;
215.274 + int n = csa->n;
215.275 + int *A_ptr = csa->A_ptr;
215.276 + int *A_ind = csa->A_ind;
215.277 + double *A_val = csa->A_val;
215.278 + int i, j, t, beg, end;
215.279 + double temp;
215.280 + for (j = 1; j <= n; j++) y[j] = 0.0;
215.281 + for (i = 1; i <= m; i++)
215.282 + { temp = x[i];
215.283 + if (temp == 0.0) continue;
215.284 + beg = A_ptr[i], end = A_ptr[i+1];
215.285 + for (t = beg; t < end; t++) y[A_ind[t]] += A_val[t] * temp;
215.286 + }
215.287 + return;
215.288 +}
215.289 +
215.290 +/***********************************************************************
215.291 +* decomp_NE - numeric factorization of matrix S = P*A*D*A'*P'
215.292 +*
215.293 +* This routine implements numeric phase of Cholesky factorization of
215.294 +* the matrix S = P*A*D*A'*P', which is a permuted matrix of the normal
215.295 +* equation system. Matrix D is assumed to be already computed. */
215.296 +
215.297 +static void decomp_NE(struct csa *csa)
215.298 +{ adat_numeric(csa->m, csa->n, csa->P, csa->A_ptr, csa->A_ind,
215.299 + csa->A_val, csa->D, csa->S_ptr, csa->S_ind, csa->S_val,
215.300 + csa->S_diag);
215.301 + chol_numeric(csa->m, csa->S_ptr, csa->S_ind, csa->S_val,
215.302 + csa->S_diag, csa->U_ptr, csa->U_ind, csa->U_val, csa->U_diag);
215.303 + return;
215.304 +}
215.305 +
215.306 +/***********************************************************************
215.307 +* solve_NE - solve normal equation system
215.308 +*
215.309 +* This routine solves the normal equation system:
215.310 +*
215.311 +* A*D*A'*y = h.
215.312 +*
215.313 +* It is assumed that the matrix A*D*A' has been previously factorized
215.314 +* by the routine decomp_NE.
215.315 +*
215.316 +* On entry the array y contains the vector of right-hand sides h. On
215.317 +* exit this array contains the computed vector of unknowns y.
215.318 +*
215.319 +* Once the vector y has been computed the routine checks for numeric
215.320 +* stability. If the residual vector:
215.321 +*
215.322 +* r = A*D*A'*y - h
215.323 +*
215.324 +* is relatively small, the routine returns zero, otherwise non-zero is
215.325 +* returned. */
215.326 +
215.327 +static int solve_NE(struct csa *csa, double y[])
215.328 +{ int m = csa->m;
215.329 + int n = csa->n;
215.330 + int *P = csa->P;
215.331 + int i, j, ret = 0;
215.332 + double *h, *r, *w;
215.333 + /* save vector of right-hand sides h */
215.334 + h = xcalloc(1+m, sizeof(double));
215.335 + for (i = 1; i <= m; i++) h[i] = y[i];
215.336 + /* solve normal equation system (A*D*A')*y = h */
215.337 + /* since S = P*A*D*A'*P' = U'*U, then A*D*A' = P'*U'*U*P, so we
215.338 + have inv(A*D*A') = P'*inv(U)*inv(U')*P */
215.339 + /* w := P*h */
215.340 + w = xcalloc(1+m, sizeof(double));
215.341 + for (i = 1; i <= m; i++) w[i] = y[P[i]];
215.342 + /* w := inv(U')*w */
215.343 + ut_solve(m, csa->U_ptr, csa->U_ind, csa->U_val, csa->U_diag, w);
215.344 + /* w := inv(U)*w */
215.345 + u_solve(m, csa->U_ptr, csa->U_ind, csa->U_val, csa->U_diag, w);
215.346 + /* y := P'*w */
215.347 + for (i = 1; i <= m; i++) y[i] = w[P[m+i]];
215.348 + xfree(w);
215.349 + /* compute residual vector r = A*D*A'*y - h */
215.350 + r = xcalloc(1+m, sizeof(double));
215.351 + /* w := A'*y */
215.352 + w = xcalloc(1+n, sizeof(double));
215.353 + AT_by_vec(csa, y, w);
215.354 + /* w := D*w */
215.355 + for (j = 1; j <= n; j++) w[j] *= csa->D[j];
215.356 + /* r := A*w */
215.357 + A_by_vec(csa, w, r);
215.358 + xfree(w);
215.359 + /* r := r - h */
215.360 + for (i = 1; i <= m; i++) r[i] -= h[i];
215.361 + /* check for numeric stability */
215.362 + for (i = 1; i <= m; i++)
215.363 + { if (fabs(r[i]) / (1.0 + fabs(h[i])) > 1e-4)
215.364 + { ret = 1;
215.365 + break;
215.366 + }
215.367 + }
215.368 + xfree(h);
215.369 + xfree(r);
215.370 + return ret;
215.371 +}
215.372 +
215.373 +/***********************************************************************
215.374 +* solve_NS - solve Newtonian system
215.375 +*
215.376 +* This routine solves the Newtonian system:
215.377 +*
215.378 +* A*dx = p
215.379 +*
215.380 +* A'*dy + dz = q
215.381 +*
215.382 +* Z*dx + X*dz = r
215.383 +*
215.384 +* where X = diag(x[j]), Z = diag(z[j]), by reducing it to the normal
215.385 +* equation system:
215.386 +*
215.387 +* (A*inv(Z)*X*A')*dy = A*inv(Z)*(X*q-r)+p
215.388 +*
215.389 +* (it is assumed that the matrix A*inv(Z)*X*A' has been factorized by
215.390 +* the routine decomp_NE).
215.391 +*
215.392 +* Once vector dy has been computed the routine computes vectors dx and
215.393 +* dz as follows:
215.394 +*
215.395 +* dx = inv(Z)*(X*(A'*dy-q)+r)
215.396 +*
215.397 +* dz = inv(X)*(r-Z*dx)
215.398 +*
215.399 +* The routine solve_NS returns the same code which was reported by the
215.400 +* routine solve_NE (see above). */
215.401 +
215.402 +static int solve_NS(struct csa *csa, double p[], double q[], double r[],
215.403 + double dx[], double dy[], double dz[])
215.404 +{ int m = csa->m;
215.405 + int n = csa->n;
215.406 + double *x = csa->x;
215.407 + double *z = csa->z;
215.408 + int i, j, ret;
215.409 + double *w = dx;
215.410 + /* compute the vector of right-hand sides A*inv(Z)*(X*q-r)+p for
215.411 + the normal equation system */
215.412 + for (j = 1; j <= n; j++)
215.413 + w[j] = (x[j] * q[j] - r[j]) / z[j];
215.414 + A_by_vec(csa, w, dy);
215.415 + for (i = 1; i <= m; i++) dy[i] += p[i];
215.416 + /* solve the normal equation system to compute vector dy */
215.417 + ret = solve_NE(csa, dy);
215.418 + /* compute vectors dx and dz */
215.419 + AT_by_vec(csa, dy, dx);
215.420 + for (j = 1; j <= n; j++)
215.421 + { dx[j] = (x[j] * (dx[j] - q[j]) + r[j]) / z[j];
215.422 + dz[j] = (r[j] - z[j] * dx[j]) / x[j];
215.423 + }
215.424 + return ret;
215.425 +}
215.426 +
215.427 +/***********************************************************************
215.428 +* initial_point - choose initial point using Mehrotra's heuristic
215.429 +*
215.430 +* This routine chooses a starting point using a heuristic proposed in
215.431 +* the paper:
215.432 +*
215.433 +* S. Mehrotra. On the implementation of a primal-dual interior point
215.434 +* method. SIAM J. on Optim., 2(4), pp. 575-601, 1992.
215.435 +*
215.436 +* The starting point x in the primal space is chosen as a solution of
215.437 +* the following least squares problem:
215.438 +*
215.439 +* minimize ||x||
215.440 +*
215.441 +* subject to A*x = b
215.442 +*
215.443 +* which can be computed explicitly as follows:
215.444 +*
215.445 +* x = A'*inv(A*A')*b
215.446 +*
215.447 +* Similarly, the starting point (y, z) in the dual space is chosen as
215.448 +* a solution of the following least squares problem:
215.449 +*
215.450 +* minimize ||z||
215.451 +*
215.452 +* subject to A'*y + z = c
215.453 +*
215.454 +* which can be computed explicitly as follows:
215.455 +*
215.456 +* y = inv(A*A')*A*c
215.457 +*
215.458 +* z = c - A'*y
215.459 +*
215.460 +* However, some components of the vectors x and z may be non-positive
215.461 +* or close to zero, so the routine uses a Mehrotra's heuristic to find
215.462 +* a more appropriate starting point. */
215.463 +
215.464 +static void initial_point(struct csa *csa)
215.465 +{ int m = csa->m;
215.466 + int n = csa->n;
215.467 + double *b = csa->b;
215.468 + double *c = csa->c;
215.469 + double *x = csa->x;
215.470 + double *y = csa->y;
215.471 + double *z = csa->z;
215.472 + double *D = csa->D;
215.473 + int i, j;
215.474 + double dp, dd, ex, ez, xz;
215.475 + /* factorize A*A' */
215.476 + for (j = 1; j <= n; j++) D[j] = 1.0;
215.477 + decomp_NE(csa);
215.478 + /* x~ = A'*inv(A*A')*b */
215.479 + for (i = 1; i <= m; i++) y[i] = b[i];
215.480 + solve_NE(csa, y);
215.481 + AT_by_vec(csa, y, x);
215.482 + /* y~ = inv(A*A')*A*c */
215.483 + A_by_vec(csa, c, y);
215.484 + solve_NE(csa, y);
215.485 + /* z~ = c - A'*y~ */
215.486 + AT_by_vec(csa, y,z);
215.487 + for (j = 1; j <= n; j++) z[j] = c[j] - z[j];
215.488 + /* use Mehrotra's heuristic in order to choose more appropriate
215.489 + starting point with positive components of vectors x and z */
215.490 + dp = dd = 0.0;
215.491 + for (j = 1; j <= n; j++)
215.492 + { if (dp < -1.5 * x[j]) dp = -1.5 * x[j];
215.493 + if (dd < -1.5 * z[j]) dd = -1.5 * z[j];
215.494 + }
215.495 + /* note that b = 0 involves x = 0, and c = 0 involves y = 0 and
215.496 + z = 0, so we need to be careful */
215.497 + if (dp == 0.0) dp = 1.5;
215.498 + if (dd == 0.0) dd = 1.5;
215.499 + ex = ez = xz = 0.0;
215.500 + for (j = 1; j <= n; j++)
215.501 + { ex += (x[j] + dp);
215.502 + ez += (z[j] + dd);
215.503 + xz += (x[j] + dp) * (z[j] + dd);
215.504 + }
215.505 + dp += 0.5 * (xz / ez);
215.506 + dd += 0.5 * (xz / ex);
215.507 + for (j = 1; j <= n; j++)
215.508 + { x[j] += dp;
215.509 + z[j] += dd;
215.510 + xassert(x[j] > 0.0 && z[j] > 0.0);
215.511 + }
215.512 + return;
215.513 +}
215.514 +
215.515 +/***********************************************************************
215.516 +* basic_info - perform basic computations at the current point
215.517 +*
215.518 +* This routine computes the following quantities at the current point:
215.519 +*
215.520 +* 1) value of the objective function:
215.521 +*
215.522 +* F = c'*x + c[0]
215.523 +*
215.524 +* 2) relative primal infeasibility:
215.525 +*
215.526 +* rpi = ||A*x-b|| / (1+||b||)
215.527 +*
215.528 +* 3) relative dual infeasibility:
215.529 +*
215.530 +* rdi = ||A'*y+z-c|| / (1+||c||)
215.531 +*
215.532 +* 4) primal-dual gap (relative difference between the primal and the
215.533 +* dual objective function values):
215.534 +*
215.535 +* gap = |c'*x-b'*y| / (1+|c'*x|)
215.536 +*
215.537 +* 5) merit function:
215.538 +*
215.539 +* phi = ||A*x-b|| / max(1,||b||) + ||A'*y+z-c|| / max(1,||c||) +
215.540 +*
215.541 +* + |c'*x-b'*y| / max(1,||b||,||c||)
215.542 +*
215.543 +* 6) duality measure:
215.544 +*
215.545 +* mu = x'*z / n
215.546 +*
215.547 +* 7) the ratio of infeasibility to mu:
215.548 +*
215.549 +* rmu = max(||A*x-b||,||A'*y+z-c||) / mu
215.550 +*
215.551 +* where ||*|| denotes euclidian norm, *' denotes transposition. */
215.552 +
215.553 +static void basic_info(struct csa *csa)
215.554 +{ int m = csa->m;
215.555 + int n = csa->n;
215.556 + double *b = csa->b;
215.557 + double *c = csa->c;
215.558 + double *x = csa->x;
215.559 + double *y = csa->y;
215.560 + double *z = csa->z;
215.561 + int i, j;
215.562 + double norm1, bnorm, norm2, cnorm, cx, by, *work, temp;
215.563 + /* compute value of the objective function */
215.564 + temp = c[0];
215.565 + for (j = 1; j <= n; j++) temp += c[j] * x[j];
215.566 + csa->obj = temp;
215.567 + /* norm1 = ||A*x-b|| */
215.568 + work = xcalloc(1+m, sizeof(double));
215.569 + A_by_vec(csa, x, work);
215.570 + norm1 = 0.0;
215.571 + for (i = 1; i <= m; i++)
215.572 + norm1 += (work[i] - b[i]) * (work[i] - b[i]);
215.573 + norm1 = sqrt(norm1);
215.574 + xfree(work);
215.575 + /* bnorm = ||b|| */
215.576 + bnorm = 0.0;
215.577 + for (i = 1; i <= m; i++) bnorm += b[i] * b[i];
215.578 + bnorm = sqrt(bnorm);
215.579 + /* compute relative primal infeasibility */
215.580 + csa->rpi = norm1 / (1.0 + bnorm);
215.581 + /* norm2 = ||A'*y+z-c|| */
215.582 + work = xcalloc(1+n, sizeof(double));
215.583 + AT_by_vec(csa, y, work);
215.584 + norm2 = 0.0;
215.585 + for (j = 1; j <= n; j++)
215.586 + norm2 += (work[j] + z[j] - c[j]) * (work[j] + z[j] - c[j]);
215.587 + norm2 = sqrt(norm2);
215.588 + xfree(work);
215.589 + /* cnorm = ||c|| */
215.590 + cnorm = 0.0;
215.591 + for (j = 1; j <= n; j++) cnorm += c[j] * c[j];
215.592 + cnorm = sqrt(cnorm);
215.593 + /* compute relative dual infeasibility */
215.594 + csa->rdi = norm2 / (1.0 + cnorm);
215.595 + /* by = b'*y */
215.596 + by = 0.0;
215.597 + for (i = 1; i <= m; i++) by += b[i] * y[i];
215.598 + /* cx = c'*x */
215.599 + cx = 0.0;
215.600 + for (j = 1; j <= n; j++) cx += c[j] * x[j];
215.601 + /* compute primal-dual gap */
215.602 + csa->gap = fabs(cx - by) / (1.0 + fabs(cx));
215.603 + /* compute merit function */
215.604 + csa->phi = 0.0;
215.605 + csa->phi += norm1 / (bnorm > 1.0 ? bnorm : 1.0);
215.606 + csa->phi += norm2 / (cnorm > 1.0 ? cnorm : 1.0);
215.607 + temp = 1.0;
215.608 + if (temp < bnorm) temp = bnorm;
215.609 + if (temp < cnorm) temp = cnorm;
215.610 + csa->phi += fabs(cx - by) / temp;
215.611 + /* compute duality measure */
215.612 + temp = 0.0;
215.613 + for (j = 1; j <= n; j++) temp += x[j] * z[j];
215.614 + csa->mu = temp / (double)n;
215.615 + /* compute the ratio of infeasibility to mu */
215.616 + csa->rmu = (norm1 > norm2 ? norm1 : norm2) / csa->mu;
215.617 + return;
215.618 +}
215.619 +
215.620 +/***********************************************************************
215.621 +* make_step - compute next point using Mehrotra's technique
215.622 +*
215.623 +* This routine computes the next point using the predictor-corrector
215.624 +* technique proposed in the paper:
215.625 +*
215.626 +* S. Mehrotra. On the implementation of a primal-dual interior point
215.627 +* method. SIAM J. on Optim., 2(4), pp. 575-601, 1992.
215.628 +*
215.629 +* At first, the routine computes so called affine scaling (predictor)
215.630 +* direction (dx_aff,dy_aff,dz_aff) which is a solution of the system:
215.631 +*
215.632 +* A*dx_aff = b - A*x
215.633 +*
215.634 +* A'*dy_aff + dz_aff = c - A'*y - z
215.635 +*
215.636 +* Z*dx_aff + X*dz_aff = - X*Z*e
215.637 +*
215.638 +* where (x,y,z) is the current point, X = diag(x[j]), Z = diag(z[j]),
215.639 +* e = (1,...,1)'.
215.640 +*
215.641 +* Then, the routine computes the centering parameter sigma, using the
215.642 +* following Mehrotra's heuristic:
215.643 +*
215.644 +* alfa_aff_p = inf{0 <= alfa <= 1 | x+alfa*dx_aff >= 0}
215.645 +*
215.646 +* alfa_aff_d = inf{0 <= alfa <= 1 | z+alfa*dz_aff >= 0}
215.647 +*
215.648 +* mu_aff = (x+alfa_aff_p*dx_aff)'*(z+alfa_aff_d*dz_aff)/n
215.649 +*
215.650 +* sigma = (mu_aff/mu)^3
215.651 +*
215.652 +* where alfa_aff_p is the maximal stepsize along the affine scaling
215.653 +* direction in the primal space, alfa_aff_d is the maximal stepsize
215.654 +* along the same direction in the dual space.
215.655 +*
215.656 +* After determining sigma the routine computes so called centering
215.657 +* (corrector) direction (dx_cc,dy_cc,dz_cc) which is the solution of
215.658 +* the system:
215.659 +*
215.660 +* A*dx_cc = 0
215.661 +*
215.662 +* A'*dy_cc + dz_cc = 0
215.663 +*
215.664 +* Z*dx_cc + X*dz_cc = sigma*mu*e - X*Z*e
215.665 +*
215.666 +* Finally, the routine computes the combined direction
215.667 +*
215.668 +* (dx,dy,dz) = (dx_aff,dy_aff,dz_aff) + (dx_cc,dy_cc,dz_cc)
215.669 +*
215.670 +* and determines maximal primal and dual stepsizes along the combined
215.671 +* direction:
215.672 +*
215.673 +* alfa_max_p = inf{0 <= alfa <= 1 | x+alfa*dx >= 0}
215.674 +*
215.675 +* alfa_max_d = inf{0 <= alfa <= 1 | z+alfa*dz >= 0}
215.676 +*
215.677 +* In order to prevent the next point to be too close to the boundary
215.678 +* of the positive ortant, the routine decreases maximal stepsizes:
215.679 +*
215.680 +* alfa_p = gamma_p * alfa_max_p
215.681 +*
215.682 +* alfa_d = gamma_d * alfa_max_d
215.683 +*
215.684 +* where gamma_p and gamma_d are scaling factors, and computes the next
215.685 +* point:
215.686 +*
215.687 +* x_new = x + alfa_p * dx
215.688 +*
215.689 +* y_new = y + alfa_d * dy
215.690 +*
215.691 +* z_new = z + alfa_d * dz
215.692 +*
215.693 +* which becomes the current point on the next iteration. */
215.694 +
215.695 +static int make_step(struct csa *csa)
215.696 +{ int m = csa->m;
215.697 + int n = csa->n;
215.698 + double *b = csa->b;
215.699 + double *c = csa->c;
215.700 + double *x = csa->x;
215.701 + double *y = csa->y;
215.702 + double *z = csa->z;
215.703 + double *dx_aff = csa->dx_aff;
215.704 + double *dy_aff = csa->dy_aff;
215.705 + double *dz_aff = csa->dz_aff;
215.706 + double *dx_cc = csa->dx_cc;
215.707 + double *dy_cc = csa->dy_cc;
215.708 + double *dz_cc = csa->dz_cc;
215.709 + double *dx = csa->dx;
215.710 + double *dy = csa->dy;
215.711 + double *dz = csa->dz;
215.712 + int i, j, ret = 0;
215.713 + double temp, gamma_p, gamma_d, *p, *q, *r;
215.714 + /* allocate working arrays */
215.715 + p = xcalloc(1+m, sizeof(double));
215.716 + q = xcalloc(1+n, sizeof(double));
215.717 + r = xcalloc(1+n, sizeof(double));
215.718 + /* p = b - A*x */
215.719 + A_by_vec(csa, x, p);
215.720 + for (i = 1; i <= m; i++) p[i] = b[i] - p[i];
215.721 + /* q = c - A'*y - z */
215.722 + AT_by_vec(csa, y,q);
215.723 + for (j = 1; j <= n; j++) q[j] = c[j] - q[j] - z[j];
215.724 + /* r = - X * Z * e */
215.725 + for (j = 1; j <= n; j++) r[j] = - x[j] * z[j];
215.726 + /* solve the first Newtonian system */
215.727 + if (solve_NS(csa, p, q, r, dx_aff, dy_aff, dz_aff))
215.728 + { ret = 1;
215.729 + goto done;
215.730 + }
215.731 + /* alfa_aff_p = inf{0 <= alfa <= 1 | x + alfa*dx_aff >= 0} */
215.732 + /* alfa_aff_d = inf{0 <= alfa <= 1 | z + alfa*dz_aff >= 0} */
215.733 + csa->alfa_aff_p = csa->alfa_aff_d = 1.0;
215.734 + for (j = 1; j <= n; j++)
215.735 + { if (dx_aff[j] < 0.0)
215.736 + { temp = - x[j] / dx_aff[j];
215.737 + if (csa->alfa_aff_p > temp) csa->alfa_aff_p = temp;
215.738 + }
215.739 + if (dz_aff[j] < 0.0)
215.740 + { temp = - z[j] / dz_aff[j];
215.741 + if (csa->alfa_aff_d > temp) csa->alfa_aff_d = temp;
215.742 + }
215.743 + }
215.744 + /* mu_aff = (x+alfa_aff_p*dx_aff)' * (z+alfa_aff_d*dz_aff) / n */
215.745 + temp = 0.0;
215.746 + for (j = 1; j <= n; j++)
215.747 + temp += (x[j] + csa->alfa_aff_p * dx_aff[j]) *
215.748 + (z[j] + csa->alfa_aff_d * dz_aff[j]);
215.749 + csa->mu_aff = temp / (double)n;
215.750 + /* sigma = (mu_aff/mu)^3 */
215.751 + temp = csa->mu_aff / csa->mu;
215.752 + csa->sigma = temp * temp * temp;
215.753 + /* p = 0 */
215.754 + for (i = 1; i <= m; i++) p[i] = 0.0;
215.755 + /* q = 0 */
215.756 + for (j = 1; j <= n; j++) q[j] = 0.0;
215.757 + /* r = sigma * mu * e - X * Z * e */
215.758 + for (j = 1; j <= n; j++)
215.759 + r[j] = csa->sigma * csa->mu - dx_aff[j] * dz_aff[j];
215.760 + /* solve the second Newtonian system with the same coefficients
215.761 + but with altered right-hand sides */
215.762 + if (solve_NS(csa, p, q, r, dx_cc, dy_cc, dz_cc))
215.763 + { ret = 1;
215.764 + goto done;
215.765 + }
215.766 + /* (dx,dy,dz) = (dx_aff,dy_aff,dz_aff) + (dx_cc,dy_cc,dz_cc) */
215.767 + for (j = 1; j <= n; j++) dx[j] = dx_aff[j] + dx_cc[j];
215.768 + for (i = 1; i <= m; i++) dy[i] = dy_aff[i] + dy_cc[i];
215.769 + for (j = 1; j <= n; j++) dz[j] = dz_aff[j] + dz_cc[j];
215.770 + /* alfa_max_p = inf{0 <= alfa <= 1 | x + alfa*dx >= 0} */
215.771 + /* alfa_max_d = inf{0 <= alfa <= 1 | z + alfa*dz >= 0} */
215.772 + csa->alfa_max_p = csa->alfa_max_d = 1.0;
215.773 + for (j = 1; j <= n; j++)
215.774 + { if (dx[j] < 0.0)
215.775 + { temp = - x[j] / dx[j];
215.776 + if (csa->alfa_max_p > temp) csa->alfa_max_p = temp;
215.777 + }
215.778 + if (dz[j] < 0.0)
215.779 + { temp = - z[j] / dz[j];
215.780 + if (csa->alfa_max_d > temp) csa->alfa_max_d = temp;
215.781 + }
215.782 + }
215.783 + /* determine scale factors (not implemented yet) */
215.784 + gamma_p = 0.90;
215.785 + gamma_d = 0.90;
215.786 + /* compute the next point */
215.787 + for (j = 1; j <= n; j++)
215.788 + { x[j] += gamma_p * csa->alfa_max_p * dx[j];
215.789 + xassert(x[j] > 0.0);
215.790 + }
215.791 + for (i = 1; i <= m; i++)
215.792 + y[i] += gamma_d * csa->alfa_max_d * dy[i];
215.793 + for (j = 1; j <= n; j++)
215.794 + { z[j] += gamma_d * csa->alfa_max_d * dz[j];
215.795 + xassert(z[j] > 0.0);
215.796 + }
215.797 +done: /* free working arrays */
215.798 + xfree(p);
215.799 + xfree(q);
215.800 + xfree(r);
215.801 + return ret;
215.802 +}
215.803 +
215.804 +/***********************************************************************
215.805 +* terminate - deallocate common storage area
215.806 +*
215.807 +* This routine frees all memory allocated to the common storage area
215.808 +* used by interior-point method routines. */
215.809 +
215.810 +static void terminate(struct csa *csa)
215.811 +{ xfree(csa->D);
215.812 + xfree(csa->P);
215.813 + xfree(csa->S_ptr);
215.814 + xfree(csa->S_ind);
215.815 + xfree(csa->S_val);
215.816 + xfree(csa->S_diag);
215.817 + xfree(csa->U_ptr);
215.818 + xfree(csa->U_ind);
215.819 + xfree(csa->U_val);
215.820 + xfree(csa->U_diag);
215.821 + xfree(csa->phi_min);
215.822 + xfree(csa->best_x);
215.823 + xfree(csa->best_y);
215.824 + xfree(csa->best_z);
215.825 + xfree(csa->dx_aff);
215.826 + xfree(csa->dy_aff);
215.827 + xfree(csa->dz_aff);
215.828 + xfree(csa->dx_cc);
215.829 + xfree(csa->dy_cc);
215.830 + xfree(csa->dz_cc);
215.831 + return;
215.832 +}
215.833 +
215.834 +/***********************************************************************
215.835 +* ipm_main - main interior-point method routine
215.836 +*
215.837 +* This is a main routine of the primal-dual interior-point method.
215.838 +*
215.839 +* The routine ipm_main returns one of the following codes:
215.840 +*
215.841 +* 0 - optimal solution found;
215.842 +* 1 - problem has no feasible (primal or dual) solution;
215.843 +* 2 - no convergence;
215.844 +* 3 - iteration limit exceeded;
215.845 +* 4 - numeric instability on solving Newtonian system.
215.846 +*
215.847 +* In case of non-zero return code the routine returns the best point,
215.848 +* which has been reached during optimization. */
215.849 +
215.850 +static int ipm_main(struct csa *csa)
215.851 +{ int m = csa->m;
215.852 + int n = csa->n;
215.853 + int i, j, status;
215.854 + double temp;
215.855 + /* choose initial point using Mehrotra's heuristic */
215.856 + if (csa->parm->msg_lev >= GLP_MSG_ALL)
215.857 + xprintf("Guessing initial point...\n");
215.858 + initial_point(csa);
215.859 + /* main loop starts here */
215.860 + if (csa->parm->msg_lev >= GLP_MSG_ALL)
215.861 + xprintf("Optimization begins...\n");
215.862 + for (;;)
215.863 + { /* perform basic computations at the current point */
215.864 + basic_info(csa);
215.865 + /* save initial value of rmu */
215.866 + if (csa->iter == 0) csa->rmu0 = csa->rmu;
215.867 + /* accumulate values of min(phi[k]) and save the best point */
215.868 + xassert(csa->iter <= ITER_MAX);
215.869 + if (csa->iter == 0 || csa->phi_min[csa->iter-1] > csa->phi)
215.870 + { csa->phi_min[csa->iter] = csa->phi;
215.871 + csa->best_iter = csa->iter;
215.872 + for (j = 1; j <= n; j++) csa->best_x[j] = csa->x[j];
215.873 + for (i = 1; i <= m; i++) csa->best_y[i] = csa->y[i];
215.874 + for (j = 1; j <= n; j++) csa->best_z[j] = csa->z[j];
215.875 + csa->best_obj = csa->obj;
215.876 + }
215.877 + else
215.878 + csa->phi_min[csa->iter] = csa->phi_min[csa->iter-1];
215.879 + /* display information at the current point */
215.880 + if (csa->parm->msg_lev >= GLP_MSG_ON)
215.881 + xprintf("%3d: obj = %17.9e; rpi = %8.1e; rdi = %8.1e; gap ="
215.882 + " %8.1e\n", csa->iter, csa->obj, csa->rpi, csa->rdi,
215.883 + csa->gap);
215.884 + /* check if the current point is optimal */
215.885 + if (csa->rpi < 1e-8 && csa->rdi < 1e-8 && csa->gap < 1e-8)
215.886 + { if (csa->parm->msg_lev >= GLP_MSG_ALL)
215.887 + xprintf("OPTIMAL SOLUTION FOUND\n");
215.888 + status = 0;
215.889 + break;
215.890 + }
215.891 + /* check if the problem has no feasible solution */
215.892 + temp = 1e5 * csa->phi_min[csa->iter];
215.893 + if (temp < 1e-8) temp = 1e-8;
215.894 + if (csa->phi >= temp)
215.895 + { if (csa->parm->msg_lev >= GLP_MSG_ALL)
215.896 + xprintf("PROBLEM HAS NO FEASIBLE PRIMAL/DUAL SOLUTION\n")
215.897 + ;
215.898 + status = 1;
215.899 + break;
215.900 + }
215.901 + /* check for very slow convergence or divergence */
215.902 + if (((csa->rpi >= 1e-8 || csa->rdi >= 1e-8) && csa->rmu /
215.903 + csa->rmu0 >= 1e6) ||
215.904 + (csa->iter >= 30 && csa->phi_min[csa->iter] >= 0.5 *
215.905 + csa->phi_min[csa->iter - 30]))
215.906 + { if (csa->parm->msg_lev >= GLP_MSG_ALL)
215.907 + xprintf("NO CONVERGENCE; SEARCH TERMINATED\n");
215.908 + status = 2;
215.909 + break;
215.910 + }
215.911 + /* check for maximal number of iterations */
215.912 + if (csa->iter == ITER_MAX)
215.913 + { if (csa->parm->msg_lev >= GLP_MSG_ALL)
215.914 + xprintf("ITERATION LIMIT EXCEEDED; SEARCH TERMINATED\n");
215.915 + status = 3;
215.916 + break;
215.917 + }
215.918 + /* start the next iteration */
215.919 + csa->iter++;
215.920 + /* factorize normal equation system */
215.921 + for (j = 1; j <= n; j++) csa->D[j] = csa->x[j] / csa->z[j];
215.922 + decomp_NE(csa);
215.923 + /* compute the next point using Mehrotra's predictor-corrector
215.924 + technique */
215.925 + if (make_step(csa))
215.926 + { if (csa->parm->msg_lev >= GLP_MSG_ALL)
215.927 + xprintf("NUMERIC INSTABILITY; SEARCH TERMINATED\n");
215.928 + status = 4;
215.929 + break;
215.930 + }
215.931 + }
215.932 + /* restore the best point */
215.933 + if (status != 0)
215.934 + { for (j = 1; j <= n; j++) csa->x[j] = csa->best_x[j];
215.935 + for (i = 1; i <= m; i++) csa->y[i] = csa->best_y[i];
215.936 + for (j = 1; j <= n; j++) csa->z[j] = csa->best_z[j];
215.937 + if (csa->parm->msg_lev >= GLP_MSG_ALL)
215.938 + xprintf("Best point %17.9e was reached on iteration %d\n",
215.939 + csa->best_obj, csa->best_iter);
215.940 + }
215.941 + /* return to the calling program */
215.942 + return status;
215.943 +}
215.944 +
215.945 +/***********************************************************************
215.946 +* NAME
215.947 +*
215.948 +* ipm_solve - core LP solver based on the interior-point method
215.949 +*
215.950 +* SYNOPSIS
215.951 +*
215.952 +* #include "glpipm.h"
215.953 +* int ipm_solve(glp_prob *P, const glp_iptcp *parm);
215.954 +*
215.955 +* DESCRIPTION
215.956 +*
215.957 +* The routine ipm_solve is a core LP solver based on the primal-dual
215.958 +* interior-point method.
215.959 +*
215.960 +* The routine assumes the following standard formulation of LP problem
215.961 +* to be solved:
215.962 +*
215.963 +* minimize
215.964 +*
215.965 +* F = c[0] + c[1]*x[1] + c[2]*x[2] + ... + c[n]*x[n]
215.966 +*
215.967 +* subject to linear constraints
215.968 +*
215.969 +* a[1,1]*x[1] + a[1,2]*x[2] + ... + a[1,n]*x[n] = b[1]
215.970 +*
215.971 +* a[2,1]*x[1] + a[2,2]*x[2] + ... + a[2,n]*x[n] = b[2]
215.972 +*
215.973 +* . . . . . .
215.974 +*
215.975 +* a[m,1]*x[1] + a[m,2]*x[2] + ... + a[m,n]*x[n] = b[m]
215.976 +*
215.977 +* and non-negative variables
215.978 +*
215.979 +* x[1] >= 0, x[2] >= 0, ..., x[n] >= 0
215.980 +*
215.981 +* where:
215.982 +* F is the objective function;
215.983 +* x[1], ..., x[n] are (structural) variables;
215.984 +* c[0] is a constant term of the objective function;
215.985 +* c[1], ..., c[n] are objective coefficients;
215.986 +* a[1,1], ..., a[m,n] are constraint coefficients;
215.987 +* b[1], ..., b[n] are right-hand sides.
215.988 +*
215.989 +* The solution is three vectors x, y, and z, which are stored by the
215.990 +* routine in the arrays x, y, and z, respectively. These vectors
215.991 +* correspond to the best primal-dual point found during optimization.
215.992 +* They are approximate solution of the following system (which is the
215.993 +* Karush-Kuhn-Tucker optimality conditions):
215.994 +*
215.995 +* A*x = b (primal feasibility condition)
215.996 +*
215.997 +* A'*y + z = c (dual feasibility condition)
215.998 +*
215.999 +* x'*z = 0 (primal-dual complementarity condition)
215.1000 +*
215.1001 +* x >= 0, z >= 0 (non-negativity condition)
215.1002 +*
215.1003 +* where:
215.1004 +* x[1], ..., x[n] are primal (structural) variables;
215.1005 +* y[1], ..., y[m] are dual variables (Lagrange multipliers) for
215.1006 +* equality constraints;
215.1007 +* z[1], ..., z[n] are dual variables (Lagrange multipliers) for
215.1008 +* non-negativity constraints.
215.1009 +*
215.1010 +* RETURNS
215.1011 +*
215.1012 +* 0 LP has been successfully solved.
215.1013 +*
215.1014 +* GLP_ENOCVG
215.1015 +* No convergence.
215.1016 +*
215.1017 +* GLP_EITLIM
215.1018 +* Iteration limit exceeded.
215.1019 +*
215.1020 +* GLP_EINSTAB
215.1021 +* Numeric instability on solving Newtonian system.
215.1022 +*
215.1023 +* In case of non-zero return code the routine returns the best point,
215.1024 +* which has been reached during optimization. */
215.1025 +
215.1026 +int ipm_solve(glp_prob *P, const glp_iptcp *parm)
215.1027 +{ struct csa _dsa, *csa = &_dsa;
215.1028 + int m = P->m;
215.1029 + int n = P->n;
215.1030 + int nnz = P->nnz;
215.1031 + GLPROW *row;
215.1032 + GLPCOL *col;
215.1033 + GLPAIJ *aij;
215.1034 + int i, j, loc, ret, *A_ind, *A_ptr;
215.1035 + double dir, *A_val, *b, *c, *x, *y, *z;
215.1036 + xassert(m > 0);
215.1037 + xassert(n > 0);
215.1038 + /* allocate working arrays */
215.1039 + A_ptr = xcalloc(1+m+1, sizeof(int));
215.1040 + A_ind = xcalloc(1+nnz, sizeof(int));
215.1041 + A_val = xcalloc(1+nnz, sizeof(double));
215.1042 + b = xcalloc(1+m, sizeof(double));
215.1043 + c = xcalloc(1+n, sizeof(double));
215.1044 + x = xcalloc(1+n, sizeof(double));
215.1045 + y = xcalloc(1+m, sizeof(double));
215.1046 + z = xcalloc(1+n, sizeof(double));
215.1047 + /* prepare rows and constraint coefficients */
215.1048 + loc = 1;
215.1049 + for (i = 1; i <= m; i++)
215.1050 + { row = P->row[i];
215.1051 + xassert(row->type == GLP_FX);
215.1052 + b[i] = row->lb * row->rii;
215.1053 + A_ptr[i] = loc;
215.1054 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
215.1055 + { A_ind[loc] = aij->col->j;
215.1056 + A_val[loc] = row->rii * aij->val * aij->col->sjj;
215.1057 + loc++;
215.1058 + }
215.1059 + }
215.1060 + A_ptr[m+1] = loc;
215.1061 + xassert(loc-1 == nnz);
215.1062 + /* prepare columns and objective coefficients */
215.1063 + if (P->dir == GLP_MIN)
215.1064 + dir = +1.0;
215.1065 + else if (P->dir == GLP_MAX)
215.1066 + dir = -1.0;
215.1067 + else
215.1068 + xassert(P != P);
215.1069 + c[0] = dir * P->c0;
215.1070 + for (j = 1; j <= n; j++)
215.1071 + { col = P->col[j];
215.1072 + xassert(col->type == GLP_LO && col->lb == 0.0);
215.1073 + c[j] = dir * col->coef * col->sjj;
215.1074 + }
215.1075 + /* allocate and initialize the common storage area */
215.1076 + csa->m = m;
215.1077 + csa->n = n;
215.1078 + csa->A_ptr = A_ptr;
215.1079 + csa->A_ind = A_ind;
215.1080 + csa->A_val = A_val;
215.1081 + csa->b = b;
215.1082 + csa->c = c;
215.1083 + csa->x = x;
215.1084 + csa->y = y;
215.1085 + csa->z = z;
215.1086 + csa->parm = parm;
215.1087 + initialize(csa);
215.1088 + /* solve LP with the interior-point method */
215.1089 + ret = ipm_main(csa);
215.1090 + /* deallocate the common storage area */
215.1091 + terminate(csa);
215.1092 + /* determine solution status */
215.1093 + if (ret == 0)
215.1094 + { /* optimal solution found */
215.1095 + P->ipt_stat = GLP_OPT;
215.1096 + ret = 0;
215.1097 + }
215.1098 + else if (ret == 1)
215.1099 + { /* problem has no feasible (primal or dual) solution */
215.1100 + P->ipt_stat = GLP_NOFEAS;
215.1101 + ret = 0;
215.1102 + }
215.1103 + else if (ret == 2)
215.1104 + { /* no convergence */
215.1105 + P->ipt_stat = GLP_INFEAS;
215.1106 + ret = GLP_ENOCVG;
215.1107 + }
215.1108 + else if (ret == 3)
215.1109 + { /* iteration limit exceeded */
215.1110 + P->ipt_stat = GLP_INFEAS;
215.1111 + ret = GLP_EITLIM;
215.1112 + }
215.1113 + else if (ret == 4)
215.1114 + { /* numeric instability on solving Newtonian system */
215.1115 + P->ipt_stat = GLP_INFEAS;
215.1116 + ret = GLP_EINSTAB;
215.1117 + }
215.1118 + else
215.1119 + xassert(ret != ret);
215.1120 + /* store row solution components */
215.1121 + for (i = 1; i <= m; i++)
215.1122 + { row = P->row[i];
215.1123 + row->pval = row->lb;
215.1124 + row->dval = dir * y[i] * row->rii;
215.1125 + }
215.1126 + /* store column solution components */
215.1127 + P->ipt_obj = P->c0;
215.1128 + for (j = 1; j <= n; j++)
215.1129 + { col = P->col[j];
215.1130 + col->pval = x[j] * col->sjj;
215.1131 + col->dval = dir * z[j] / col->sjj;
215.1132 + P->ipt_obj += col->coef * col->pval;
215.1133 + }
215.1134 + /* free working arrays */
215.1135 + xfree(A_ptr);
215.1136 + xfree(A_ind);
215.1137 + xfree(A_val);
215.1138 + xfree(b);
215.1139 + xfree(c);
215.1140 + xfree(x);
215.1141 + xfree(y);
215.1142 + xfree(z);
215.1143 + return ret;
215.1144 +}
215.1145 +
215.1146 +/* eof */
216.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
216.2 +++ b/src/glpipm.h Mon Dec 06 13:09:21 2010 +0100
216.3 @@ -0,0 +1,36 @@
216.4 +/* glpipm.h (primal-dual interior-point method) */
216.5 +
216.6 +/***********************************************************************
216.7 +* This code is part of GLPK (GNU Linear Programming Kit).
216.8 +*
216.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
216.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
216.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
216.12 +* E-mail: <mao@gnu.org>.
216.13 +*
216.14 +* GLPK is free software: you can redistribute it and/or modify it
216.15 +* under the terms of the GNU General Public License as published by
216.16 +* the Free Software Foundation, either version 3 of the License, or
216.17 +* (at your option) any later version.
216.18 +*
216.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
216.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
216.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
216.22 +* License for more details.
216.23 +*
216.24 +* You should have received a copy of the GNU General Public License
216.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
216.26 +***********************************************************************/
216.27 +
216.28 +#ifndef GLPIPM_H
216.29 +#define GLPIPM_H
216.30 +
216.31 +#include "glpapi.h"
216.32 +
216.33 +#define ipm_solve _glp_ipm_solve
216.34 +int ipm_solve(glp_prob *P, const glp_iptcp *parm);
216.35 +/* core LP solver based on the interior-point method */
216.36 +
216.37 +#endif
216.38 +
216.39 +/* eof */
217.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
217.2 +++ b/src/glplib.h Mon Dec 06 13:09:21 2010 +0100
217.3 @@ -0,0 +1,135 @@
217.4 +/* glplib.h (miscellaneous library routines) */
217.5 +
217.6 +/***********************************************************************
217.7 +* This code is part of GLPK (GNU Linear Programming Kit).
217.8 +*
217.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
217.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
217.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
217.12 +* E-mail: <mao@gnu.org>.
217.13 +*
217.14 +* GLPK is free software: you can redistribute it and/or modify it
217.15 +* under the terms of the GNU General Public License as published by
217.16 +* the Free Software Foundation, either version 3 of the License, or
217.17 +* (at your option) any later version.
217.18 +*
217.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
217.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
217.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
217.22 +* License for more details.
217.23 +*
217.24 +* You should have received a copy of the GNU General Public License
217.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
217.26 +***********************************************************************/
217.27 +
217.28 +#ifndef GLPLIB_H
217.29 +#define GLPLIB_H
217.30 +
217.31 +#define bigmul _glp_lib_bigmul
217.32 +void bigmul(int n, int m, unsigned short x[], unsigned short y[]);
217.33 +/* multiply unsigned integer numbers of arbitrary precision */
217.34 +
217.35 +#define bigdiv _glp_lib_bigdiv
217.36 +void bigdiv(int n, int m, unsigned short x[], unsigned short y[]);
217.37 +/* divide unsigned integer numbers of arbitrary precision */
217.38 +
217.39 +#ifndef GLP_LONG_DEFINED
217.40 +#define GLP_LONG_DEFINED
217.41 +typedef struct { int lo, hi; } glp_long;
217.42 +/* long integer data type */
217.43 +#endif
217.44 +
217.45 +typedef struct { glp_long quot, rem; } glp_ldiv;
217.46 +/* result of long integer division */
217.47 +
217.48 +#define xlset _glp_lib_xlset
217.49 +glp_long xlset(int x);
217.50 +/* expand integer to long integer */
217.51 +
217.52 +#define xlneg _glp_lib_xlneg
217.53 +glp_long xlneg(glp_long x);
217.54 +/* negate long integer */
217.55 +
217.56 +#define xladd _glp_lib_xladd
217.57 +glp_long xladd(glp_long x, glp_long y);
217.58 +/* add long integers */
217.59 +
217.60 +#define xlsub _glp_lib_xlsub
217.61 +glp_long xlsub(glp_long x, glp_long y);
217.62 +/* subtract long integers */
217.63 +
217.64 +#define xlcmp _glp_lib_xlcmp
217.65 +int xlcmp(glp_long x, glp_long y);
217.66 +/* compare long integers */
217.67 +
217.68 +#define xlmul _glp_lib_xlmul
217.69 +glp_long xlmul(glp_long x, glp_long y);
217.70 +/* multiply long integers */
217.71 +
217.72 +#define xldiv _glp_lib_xldiv
217.73 +glp_ldiv xldiv(glp_long x, glp_long y);
217.74 +/* divide long integers */
217.75 +
217.76 +#define xltod _glp_lib_xltod
217.77 +double xltod(glp_long x);
217.78 +/* convert long integer to double */
217.79 +
217.80 +#define xltoa _glp_lib_xltoa
217.81 +char *xltoa(glp_long x, char *s);
217.82 +/* convert long integer to character string */
217.83 +
217.84 +#define str2int _glp_lib_str2int
217.85 +int str2int(const char *str, int *val);
217.86 +/* convert character string to value of int type */
217.87 +
217.88 +#define str2num _glp_lib_str2num
217.89 +int str2num(const char *str, double *val);
217.90 +/* convert character string to value of double type */
217.91 +
217.92 +#define strspx _glp_lib_strspx
217.93 +char *strspx(char *str);
217.94 +/* remove all spaces from character string */
217.95 +
217.96 +#define strtrim _glp_lib_strtrim
217.97 +char *strtrim(char *str);
217.98 +/* remove trailing spaces from character string */
217.99 +
217.100 +#define strrev _glp_lib_strrev
217.101 +char *strrev(char *s);
217.102 +/* reverse character string */
217.103 +
217.104 +#define gcd _glp_lib_gcd
217.105 +int gcd(int x, int y);
217.106 +/* find greatest common divisor of two integers */
217.107 +
217.108 +#define gcdn _glp_lib_gcdn
217.109 +int gcdn(int n, int x[]);
217.110 +/* find greatest common divisor of n integers */
217.111 +
217.112 +#define lcm _glp_lib_lcm
217.113 +int lcm(int x, int y);
217.114 +/* find least common multiple of two integers */
217.115 +
217.116 +#define lcmn _glp_lib_lcmn
217.117 +int lcmn(int n, int x[]);
217.118 +/* find least common multiple of n integers */
217.119 +
217.120 +#define round2n _glp_lib_round2n
217.121 +double round2n(double x);
217.122 +/* round floating-point number to nearest power of two */
217.123 +
217.124 +#define fp2rat _glp_lib_fp2rat
217.125 +int fp2rat(double x, double eps, double *p, double *q);
217.126 +/* convert floating-point number to rational number */
217.127 +
217.128 +#define jday _glp_lib_jday
217.129 +int jday(int d, int m, int y);
217.130 +/* convert calendar date to Julian day number */
217.131 +
217.132 +#define jdate _glp_lib_jdate
217.133 +int jdate(int j, int *d, int *m, int *y);
217.134 +/* convert Julian day number to calendar date */
217.135 +
217.136 +#endif
217.137 +
217.138 +/* eof */
218.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
218.2 +++ b/src/glplib01.c Mon Dec 06 13:09:21 2010 +0100
218.3 @@ -0,0 +1,287 @@
218.4 +/* glplib01.c (bignum arithmetic) */
218.5 +
218.6 +/***********************************************************************
218.7 +* This code is part of GLPK (GNU Linear Programming Kit).
218.8 +*
218.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
218.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
218.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
218.12 +* E-mail: <mao@gnu.org>.
218.13 +*
218.14 +* GLPK is free software: you can redistribute it and/or modify it
218.15 +* under the terms of the GNU General Public License as published by
218.16 +* the Free Software Foundation, either version 3 of the License, or
218.17 +* (at your option) any later version.
218.18 +*
218.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
218.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
218.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
218.22 +* License for more details.
218.23 +*
218.24 +* You should have received a copy of the GNU General Public License
218.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
218.26 +***********************************************************************/
218.27 +
218.28 +#include "glpenv.h"
218.29 +#include "glplib.h"
218.30 +
218.31 +/***********************************************************************
218.32 +* Two routines below are intended to multiply and divide unsigned
218.33 +* integer numbers of arbitrary precision.
218.34 +*
218.35 +* The routines assume that an unsigned integer number is represented in
218.36 +* the positional numeral system with the base 2^16 = 65536, i.e. each
218.37 +* "digit" of the number is in the range [0, 65535] and represented as
218.38 +* a 16-bit value of the unsigned short type. In other words, a number x
218.39 +* has the following representation:
218.40 +*
218.41 +* n-1
218.42 +* x = sum d[j] * 65536^j,
218.43 +* j=0
218.44 +*
218.45 +* where n is the number of places (positions), and d[j] is j-th "digit"
218.46 +* of x, 0 <= d[j] <= 65535.
218.47 +***********************************************************************/
218.48 +
218.49 +/***********************************************************************
218.50 +* NAME
218.51 +*
218.52 +* bigmul - multiply unsigned integer numbers of arbitrary precision
218.53 +*
218.54 +* SYNOPSIS
218.55 +*
218.56 +* #include "glplib.h"
218.57 +* void bigmul(int n, int m, unsigned short x[], unsigned short y[]);
218.58 +*
218.59 +* DESCRIPTION
218.60 +*
218.61 +* The routine bigmul multiplies unsigned integer numbers of arbitrary
218.62 +* precision.
218.63 +*
218.64 +* n is the number of digits of multiplicand, n >= 1;
218.65 +*
218.66 +* m is the number of digits of multiplier, m >= 1;
218.67 +*
218.68 +* x is an array containing digits of the multiplicand in elements
218.69 +* x[m], x[m+1], ..., x[n+m-1]. Contents of x[0], x[1], ..., x[m-1] are
218.70 +* ignored on entry.
218.71 +*
218.72 +* y is an array containing digits of the multiplier in elements y[0],
218.73 +* y[1], ..., y[m-1].
218.74 +*
218.75 +* On exit digits of the product are stored in elements x[0], x[1], ...,
218.76 +* x[n+m-1]. The array y is not changed. */
218.77 +
218.78 +void bigmul(int n, int m, unsigned short x[], unsigned short y[])
218.79 +{ int i, j;
218.80 + unsigned int t;
218.81 + xassert(n >= 1);
218.82 + xassert(m >= 1);
218.83 + for (j = 0; j < m; j++) x[j] = 0;
218.84 + for (i = 0; i < n; i++)
218.85 + { if (x[i+m])
218.86 + { t = 0;
218.87 + for (j = 0; j < m; j++)
218.88 + { t += (unsigned int)x[i+m] * (unsigned int)y[j] +
218.89 + (unsigned int)x[i+j];
218.90 + x[i+j] = (unsigned short)t;
218.91 + t >>= 16;
218.92 + }
218.93 + x[i+m] = (unsigned short)t;
218.94 + }
218.95 + }
218.96 + return;
218.97 +}
218.98 +
218.99 +/***********************************************************************
218.100 +* NAME
218.101 +*
218.102 +* bigdiv - divide unsigned integer numbers of arbitrary precision
218.103 +*
218.104 +* SYNOPSIS
218.105 +*
218.106 +* #include "glplib.h"
218.107 +* void bigdiv(int n, int m, unsigned short x[], unsigned short y[]);
218.108 +*
218.109 +* DESCRIPTION
218.110 +*
218.111 +* The routine bigdiv divides one unsigned integer number of arbitrary
218.112 +* precision by another with the algorithm described in [1].
218.113 +*
218.114 +* n is the difference between the number of digits of dividend and the
218.115 +* number of digits of divisor, n >= 0.
218.116 +*
218.117 +* m is the number of digits of divisor, m >= 1.
218.118 +*
218.119 +* x is an array containing digits of the dividend in elements x[0],
218.120 +* x[1], ..., x[n+m-1].
218.121 +*
218.122 +* y is an array containing digits of the divisor in elements y[0],
218.123 +* y[1], ..., y[m-1]. The highest digit y[m-1] must be non-zero.
218.124 +*
218.125 +* On exit n+1 digits of the quotient are stored in elements x[m],
218.126 +* x[m+1], ..., x[n+m], and m digits of the remainder are stored in
218.127 +* elements x[0], x[1], ..., x[m-1]. The array y is changed but then
218.128 +* restored.
218.129 +*
218.130 +* REFERENCES
218.131 +*
218.132 +* 1. D. Knuth. The Art of Computer Programming. Vol. 2: Seminumerical
218.133 +* Algorithms. Stanford University, 1969. */
218.134 +
218.135 +void bigdiv(int n, int m, unsigned short x[], unsigned short y[])
218.136 +{ int i, j;
218.137 + unsigned int t;
218.138 + unsigned short d, q, r;
218.139 + xassert(n >= 0);
218.140 + xassert(m >= 1);
218.141 + xassert(y[m-1] != 0);
218.142 + /* special case when divisor has the only digit */
218.143 + if (m == 1)
218.144 + { d = 0;
218.145 + for (i = n; i >= 0; i--)
218.146 + { t = ((unsigned int)d << 16) + (unsigned int)x[i];
218.147 + x[i+1] = (unsigned short)(t / y[0]);
218.148 + d = (unsigned short)(t % y[0]);
218.149 + }
218.150 + x[0] = d;
218.151 + goto done;
218.152 + }
218.153 + /* multiply dividend and divisor by a normalizing coefficient in
218.154 + order to provide the condition y[m-1] >= base / 2 */
218.155 + d = (unsigned short)(0x10000 / ((unsigned int)y[m-1] + 1));
218.156 + if (d == 1)
218.157 + x[n+m] = 0;
218.158 + else
218.159 + { t = 0;
218.160 + for (i = 0; i < n+m; i++)
218.161 + { t += (unsigned int)x[i] * (unsigned int)d;
218.162 + x[i] = (unsigned short)t;
218.163 + t >>= 16;
218.164 + }
218.165 + x[n+m] = (unsigned short)t;
218.166 + t = 0;
218.167 + for (j = 0; j < m; j++)
218.168 + { t += (unsigned int)y[j] * (unsigned int)d;
218.169 + y[j] = (unsigned short)t;
218.170 + t >>= 16;
218.171 + }
218.172 + }
218.173 + /* main loop */
218.174 + for (i = n; i >= 0; i--)
218.175 + { /* estimate and correct the current digit of quotient */
218.176 + if (x[i+m] < y[m-1])
218.177 + { t = ((unsigned int)x[i+m] << 16) + (unsigned int)x[i+m-1];
218.178 + q = (unsigned short)(t / (unsigned int)y[m-1]);
218.179 + r = (unsigned short)(t % (unsigned int)y[m-1]);
218.180 + if (q == 0) goto putq; else goto test;
218.181 + }
218.182 + q = 0;
218.183 + r = x[i+m-1];
218.184 +decr: q--; /* if q = 0 then q-- = 0xFFFF */
218.185 + t = (unsigned int)r + (unsigned int)y[m-1];
218.186 + r = (unsigned short)t;
218.187 + if (t > 0xFFFF) goto msub;
218.188 +test: t = (unsigned int)y[m-2] * (unsigned int)q;
218.189 + if ((unsigned short)(t >> 16) > r) goto decr;
218.190 + if ((unsigned short)(t >> 16) < r) goto msub;
218.191 + if ((unsigned short)t > x[i+m-2]) goto decr;
218.192 +msub: /* now subtract divisor multiplied by the current digit of
218.193 + quotient from the current dividend */
218.194 + if (q == 0) goto putq;
218.195 + t = 0;
218.196 + for (j = 0; j < m; j++)
218.197 + { t += (unsigned int)y[j] * (unsigned int)q;
218.198 + if (x[i+j] < (unsigned short)t) t += 0x10000;
218.199 + x[i+j] -= (unsigned short)t;
218.200 + t >>= 16;
218.201 + }
218.202 + if (x[i+m] >= (unsigned short)t) goto putq;
218.203 + /* perform correcting addition, because the current digit of
218.204 + quotient is greater by one than its correct value */
218.205 + q--;
218.206 + t = 0;
218.207 + for (j = 0; j < m; j++)
218.208 + { t += (unsigned int)x[i+j] + (unsigned int)y[j];
218.209 + x[i+j] = (unsigned short)t;
218.210 + t >>= 16;
218.211 + }
218.212 +putq: /* store the current digit of quotient */
218.213 + x[i+m] = q;
218.214 + }
218.215 + /* divide divisor and remainder by the normalizing coefficient in
218.216 + order to restore their original values */
218.217 + if (d > 1)
218.218 + { t = 0;
218.219 + for (i = m-1; i >= 0; i--)
218.220 + { t = (t << 16) + (unsigned int)x[i];
218.221 + x[i] = (unsigned short)(t / (unsigned int)d);
218.222 + t %= (unsigned int)d;
218.223 + }
218.224 + t = 0;
218.225 + for (j = m-1; j >= 0; j--)
218.226 + { t = (t << 16) + (unsigned int)y[j];
218.227 + y[j] = (unsigned short)(t / (unsigned int)d);
218.228 + t %= (unsigned int)d;
218.229 + }
218.230 + }
218.231 +done: return;
218.232 +}
218.233 +
218.234 +/**********************************************************************/
218.235 +
218.236 +#if 0
218.237 +#include <assert.h>
218.238 +#include <stdio.h>
218.239 +#include <stdlib.h>
218.240 +#include "glprng.h"
218.241 +
218.242 +#define N_MAX 7
218.243 +/* maximal number of digits in multiplicand */
218.244 +
218.245 +#define M_MAX 5
218.246 +/* maximal number of digits in multiplier */
218.247 +
218.248 +#define N_TEST 1000000
218.249 +/* number of tests */
218.250 +
218.251 +int main(void)
218.252 +{ RNG *rand;
218.253 + int d, j, n, m, test;
218.254 + unsigned short x[N_MAX], y[M_MAX], z[N_MAX+M_MAX];
218.255 + rand = rng_create_rand();
218.256 + for (test = 1; test <= N_TEST; test++)
218.257 + { /* x[0,...,n-1] := multiplicand */
218.258 + n = 1 + rng_unif_rand(rand, N_MAX-1);
218.259 + assert(1 <= n && n <= N_MAX);
218.260 + for (j = 0; j < n; j++)
218.261 + { d = rng_unif_rand(rand, 65536);
218.262 + assert(0 <= d && d <= 65535);
218.263 + x[j] = (unsigned short)d;
218.264 + }
218.265 + /* y[0,...,m-1] := multiplier */
218.266 + m = 1 + rng_unif_rand(rand, M_MAX-1);
218.267 + assert(1 <= m && m <= M_MAX);
218.268 + for (j = 0; j < m; j++)
218.269 + { d = rng_unif_rand(rand, 65536);
218.270 + assert(0 <= d && d <= 65535);
218.271 + y[j] = (unsigned short)d;
218.272 + }
218.273 + if (y[m-1] == 0) y[m-1] = 1;
218.274 + /* z[0,...,n+m-1] := x * y */
218.275 + for (j = 0; j < n; j++) z[m+j] = x[j];
218.276 + bigmul(n, m, z, y);
218.277 + /* z[0,...,m-1] := z mod y, z[m,...,n+m-1] := z div y */
218.278 + bigdiv(n, m, z, y);
218.279 + /* z mod y must be 0 */
218.280 + for (j = 0; j < m; j++) assert(z[j] == 0);
218.281 + /* z div y must be x */
218.282 + for (j = 0; j < n; j++) assert(z[m+j] == x[j]);
218.283 + }
218.284 + fprintf(stderr, "%d tests successfully passed\n", N_TEST);
218.285 + rng_delete_rand(rand);
218.286 + return 0;
218.287 +}
218.288 +#endif
218.289 +
218.290 +/* eof */
219.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
219.2 +++ b/src/glplib02.c Mon Dec 06 13:09:21 2010 +0100
219.3 @@ -0,0 +1,335 @@
219.4 +/* glplib02.c (64-bit arithmetic) */
219.5 +
219.6 +/***********************************************************************
219.7 +* This code is part of GLPK (GNU Linear Programming Kit).
219.8 +*
219.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
219.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
219.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
219.12 +* E-mail: <mao@gnu.org>.
219.13 +*
219.14 +* GLPK is free software: you can redistribute it and/or modify it
219.15 +* under the terms of the GNU General Public License as published by
219.16 +* the Free Software Foundation, either version 3 of the License, or
219.17 +* (at your option) any later version.
219.18 +*
219.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
219.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
219.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
219.22 +* License for more details.
219.23 +*
219.24 +* You should have received a copy of the GNU General Public License
219.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
219.26 +***********************************************************************/
219.27 +
219.28 +#include "glpenv.h"
219.29 +#include "glplib.h"
219.30 +
219.31 +/***********************************************************************
219.32 +* NAME
219.33 +*
219.34 +* xlset - expand integer to long integer
219.35 +*
219.36 +* SYNOPSIS
219.37 +*
219.38 +* #include "glplib.h"
219.39 +* glp_long xlset(int x);
219.40 +*
219.41 +* RETURNS
219.42 +*
219.43 +* The routine xlset returns x expanded to long integer. */
219.44 +
219.45 +glp_long xlset(int x)
219.46 +{ glp_long t;
219.47 + t.lo = x, t.hi = (x >= 0 ? 0 : -1);
219.48 + return t;
219.49 +}
219.50 +
219.51 +/***********************************************************************
219.52 +* NAME
219.53 +*
219.54 +* xlneg - negate long integer
219.55 +*
219.56 +* SYNOPSIS
219.57 +*
219.58 +* #include "glplib.h"
219.59 +* glp_long xlneg(glp_long x);
219.60 +*
219.61 +* RETURNS
219.62 +*
219.63 +* The routine xlneg returns the difference 0 - x. */
219.64 +
219.65 +glp_long xlneg(glp_long x)
219.66 +{ if (x.lo)
219.67 + x.lo = - x.lo, x.hi = ~x.hi;
219.68 + else
219.69 + x.hi = - x.hi;
219.70 + return x;
219.71 +}
219.72 +
219.73 +/***********************************************************************
219.74 +* NAME
219.75 +*
219.76 +* xladd - add long integers
219.77 +*
219.78 +* SYNOPSIS
219.79 +*
219.80 +* #include "glplib.h"
219.81 +* glp_long xladd(glp_long x, glp_long y);
219.82 +*
219.83 +* RETURNS
219.84 +*
219.85 +* The routine xladd returns the sum x + y. */
219.86 +
219.87 +glp_long xladd(glp_long x, glp_long y)
219.88 +{ if ((unsigned int)x.lo <= 0xFFFFFFFF - (unsigned int)y.lo)
219.89 + x.lo += y.lo, x.hi += y.hi;
219.90 + else
219.91 + x.lo += y.lo, x.hi += y.hi + 1;
219.92 + return x;
219.93 +}
219.94 +
219.95 +/***********************************************************************
219.96 +* NAME
219.97 +*
219.98 +* xlsub - subtract long integers
219.99 +*
219.100 +* SYNOPSIS
219.101 +*
219.102 +* #include "glplib.h"
219.103 +* glp_long xlsub(glp_long x, glp_long y);
219.104 +*
219.105 +* RETURNS
219.106 +*
219.107 +* The routine xlsub returns the difference x - y. */
219.108 +
219.109 +glp_long xlsub(glp_long x, glp_long y)
219.110 +{ return
219.111 + xladd(x, xlneg(y));
219.112 +}
219.113 +
219.114 +/***********************************************************************
219.115 +* NAME
219.116 +*
219.117 +* xlcmp - compare long integers
219.118 +*
219.119 +* SYNOPSIS
219.120 +*
219.121 +* #include "glplib.h"
219.122 +* int xlcmp(glp_long x, glp_long y);
219.123 +*
219.124 +* RETURNS
219.125 +*
219.126 +* The routine xlcmp returns the sign of the difference x - y. */
219.127 +
219.128 +int xlcmp(glp_long x, glp_long y)
219.129 +{ if (x.hi >= 0 && y.hi < 0) return +1;
219.130 + if (x.hi < 0 && y.hi >= 0) return -1;
219.131 + if ((unsigned int)x.hi < (unsigned int)y.hi) return -1;
219.132 + if ((unsigned int)x.hi > (unsigned int)y.hi) return +1;
219.133 + if ((unsigned int)x.lo < (unsigned int)y.lo) return -1;
219.134 + if ((unsigned int)x.lo > (unsigned int)y.lo) return +1;
219.135 + return 0;
219.136 +}
219.137 +
219.138 +/***********************************************************************
219.139 +* NAME
219.140 +*
219.141 +* xlmul - multiply long integers
219.142 +*
219.143 +* SYNOPSIS
219.144 +*
219.145 +* #include "glplib.h"
219.146 +* glp_long xlmul(glp_long x, glp_long y);
219.147 +*
219.148 +* RETURNS
219.149 +*
219.150 +* The routine xlmul returns the product x * y. */
219.151 +
219.152 +glp_long xlmul(glp_long x, glp_long y)
219.153 +{ unsigned short xx[8], yy[4];
219.154 + xx[4] = (unsigned short)x.lo;
219.155 + xx[5] = (unsigned short)(x.lo >> 16);
219.156 + xx[6] = (unsigned short)x.hi;
219.157 + xx[7] = (unsigned short)(x.hi >> 16);
219.158 + yy[0] = (unsigned short)y.lo;
219.159 + yy[1] = (unsigned short)(y.lo >> 16);
219.160 + yy[2] = (unsigned short)y.hi;
219.161 + yy[3] = (unsigned short)(y.hi >> 16);
219.162 + bigmul(4, 4, xx, yy);
219.163 + x.lo = (unsigned int)xx[0] | ((unsigned int)xx[1] << 16);
219.164 + x.hi = (unsigned int)xx[2] | ((unsigned int)xx[3] << 16);
219.165 + return x;
219.166 +}
219.167 +
219.168 +/***********************************************************************
219.169 +* NAME
219.170 +*
219.171 +* xldiv - divide long integers
219.172 +*
219.173 +* SYNOPSIS
219.174 +*
219.175 +* #include "glplib.h"
219.176 +* glp_ldiv xldiv(glp_long x, glp_long y);
219.177 +*
219.178 +* RETURNS
219.179 +*
219.180 +* The routine xldiv returns a structure of type glp_ldiv containing
219.181 +* members quot (the quotient) and rem (the remainder), both of type
219.182 +* glp_long. */
219.183 +
219.184 +glp_ldiv xldiv(glp_long x, glp_long y)
219.185 +{ glp_ldiv t;
219.186 + int m, sx, sy;
219.187 + unsigned short xx[8], yy[4];
219.188 + /* sx := sign(x) */
219.189 + sx = (x.hi < 0);
219.190 + /* sy := sign(y) */
219.191 + sy = (y.hi < 0);
219.192 + /* x := |x| */
219.193 + if (sx) x = xlneg(x);
219.194 + /* y := |y| */
219.195 + if (sy) y = xlneg(y);
219.196 + /* compute x div y and x mod y */
219.197 + xx[0] = (unsigned short)x.lo;
219.198 + xx[1] = (unsigned short)(x.lo >> 16);
219.199 + xx[2] = (unsigned short)x.hi;
219.200 + xx[3] = (unsigned short)(x.hi >> 16);
219.201 + yy[0] = (unsigned short)y.lo;
219.202 + yy[1] = (unsigned short)(y.lo >> 16);
219.203 + yy[2] = (unsigned short)y.hi;
219.204 + yy[3] = (unsigned short)(y.hi >> 16);
219.205 + if (yy[3])
219.206 + m = 4;
219.207 + else if (yy[2])
219.208 + m = 3;
219.209 + else if (yy[1])
219.210 + m = 2;
219.211 + else if (yy[0])
219.212 + m = 1;
219.213 + else
219.214 + xerror("xldiv: divide by zero\n");
219.215 + bigdiv(4 - m, m, xx, yy);
219.216 + /* remainder in x[0], x[1], ..., x[m-1] */
219.217 + t.rem.lo = (unsigned int)xx[0], t.rem.hi = 0;
219.218 + if (m >= 2) t.rem.lo |= (unsigned int)xx[1] << 16;
219.219 + if (m >= 3) t.rem.hi = (unsigned int)xx[2];
219.220 + if (m >= 4) t.rem.hi |= (unsigned int)xx[3] << 16;
219.221 + if (sx) t.rem = xlneg(t.rem);
219.222 + /* quotient in x[m], x[m+1], ..., x[4] */
219.223 + t.quot.lo = (unsigned int)xx[m], t.quot.hi = 0;
219.224 + if (m <= 3) t.quot.lo |= (unsigned int)xx[m+1] << 16;
219.225 + if (m <= 2) t.quot.hi = (unsigned int)xx[m+2];
219.226 + if (m <= 1) t.quot.hi |= (unsigned int)xx[m+3] << 16;
219.227 + if (sx ^ sy) t.quot = xlneg(t.quot);
219.228 + return t;
219.229 +}
219.230 +
219.231 +/***********************************************************************
219.232 +* NAME
219.233 +*
219.234 +* xltod - convert long integer to double
219.235 +*
219.236 +* SYNOPSIS
219.237 +*
219.238 +* #include "glplib.h"
219.239 +* double xltod(glp_long x);
219.240 +*
219.241 +* RETURNS
219.242 +*
219.243 +* The routine xltod returns x converted to double. */
219.244 +
219.245 +double xltod(glp_long x)
219.246 +{ double s, z;
219.247 + if (x.hi >= 0)
219.248 + s = +1.0;
219.249 + else
219.250 + s = -1.0, x = xlneg(x);
219.251 + if (x.hi >= 0)
219.252 + z = 4294967296.0 * (double)x.hi + (double)(unsigned int)x.lo;
219.253 + else
219.254 + { xassert(x.hi == 0x80000000 && x.lo == 0x00000000);
219.255 + z = 9223372036854775808.0; /* 2^63 */
219.256 + }
219.257 + return s * z;
219.258 +}
219.259 +
219.260 +char *xltoa(glp_long x, char *s)
219.261 +{ /* convert long integer to character string */
219.262 + static const char *d = "0123456789";
219.263 + glp_ldiv t;
219.264 + int neg, len;
219.265 + if (x.hi >= 0)
219.266 + neg = 0;
219.267 + else
219.268 + neg = 1, x = xlneg(x);
219.269 + if (x.hi >= 0)
219.270 + { len = 0;
219.271 + while (!(x.hi == 0 && x.lo == 0))
219.272 + { t = xldiv(x, xlset(10));
219.273 + xassert(0 <= t.rem.lo && t.rem.lo <= 9);
219.274 + s[len++] = d[t.rem.lo];
219.275 + x = t.quot;
219.276 + }
219.277 + if (len == 0) s[len++] = d[0];
219.278 + if (neg) s[len++] = '-';
219.279 + s[len] = '\0';
219.280 + strrev(s);
219.281 + }
219.282 + else
219.283 + strcpy(s, "-9223372036854775808"); /* -2^63 */
219.284 + return s;
219.285 +}
219.286 +
219.287 +/**********************************************************************/
219.288 +
219.289 +#if 0
219.290 +#include "glprng.h"
219.291 +
219.292 +#define N_TEST 1000000
219.293 +/* number of tests */
219.294 +
219.295 +static glp_long myrand(RNG *rand)
219.296 +{ glp_long x;
219.297 + int k;
219.298 + k = rng_unif_rand(rand, 4);
219.299 + xassert(0 <= k && k <= 3);
219.300 + x.lo = rng_unif_rand(rand, 65536);
219.301 + if (k == 1 || k == 3)
219.302 + { x.lo <<= 16;
219.303 + x.lo += rng_unif_rand(rand, 65536);
219.304 + }
219.305 + if (k <= 1)
219.306 + x.hi = 0;
219.307 + else
219.308 + x.hi = rng_unif_rand(rand, 65536);
219.309 + if (k == 3)
219.310 + { x.hi <<= 16;
219.311 + x.hi += rng_unif_rand(rand, 65536);
219.312 + }
219.313 + if (rng_unif_rand(rand, 2)) x = xlneg(x);
219.314 + return x;
219.315 +}
219.316 +
219.317 +int main(void)
219.318 +{ RNG *rand;
219.319 + glp_long x, y;
219.320 + glp_ldiv z;
219.321 + int test;
219.322 + rand = rng_create_rand();
219.323 + for (test = 1; test <= N_TEST; test++)
219.324 + { x = myrand(rand);
219.325 + y = myrand(rand);
219.326 + if (y.lo == 0 && y.hi == 0) y.lo = 1;
219.327 + /* z.quot := x div y, z.rem := x mod y */
219.328 + z = xldiv(x, y);
219.329 + /* x must be equal to y * z.quot + z.rem */
219.330 + xassert(xlcmp(x, xladd(xlmul(y, z.quot), z.rem)) == 0);
219.331 + }
219.332 + xprintf("%d tests successfully passed\n", N_TEST);
219.333 + rng_delete_rand(rand);
219.334 + return 0;
219.335 +}
219.336 +#endif
219.337 +
219.338 +/* eof */
220.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
220.2 +++ b/src/glplib03.c Mon Dec 06 13:09:21 2010 +0100
220.3 @@ -0,0 +1,692 @@
220.4 +/* glplib03.c (miscellaneous library routines) */
220.5 +
220.6 +/***********************************************************************
220.7 +* This code is part of GLPK (GNU Linear Programming Kit).
220.8 +*
220.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
220.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
220.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
220.12 +* E-mail: <mao@gnu.org>.
220.13 +*
220.14 +* GLPK is free software: you can redistribute it and/or modify it
220.15 +* under the terms of the GNU General Public License as published by
220.16 +* the Free Software Foundation, either version 3 of the License, or
220.17 +* (at your option) any later version.
220.18 +*
220.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
220.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
220.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
220.22 +* License for more details.
220.23 +*
220.24 +* You should have received a copy of the GNU General Public License
220.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
220.26 +***********************************************************************/
220.27 +
220.28 +#include "glpenv.h"
220.29 +#include "glplib.h"
220.30 +
220.31 +/***********************************************************************
220.32 +* NAME
220.33 +*
220.34 +* str2int - convert character string to value of int type
220.35 +*
220.36 +* SYNOPSIS
220.37 +*
220.38 +* #include "glplib.h"
220.39 +* int str2int(const char *str, int *val);
220.40 +*
220.41 +* DESCRIPTION
220.42 +*
220.43 +* The routine str2int converts the character string str to a value of
220.44 +* integer type and stores the value into location, which the parameter
220.45 +* val points to (in the case of error content of this location is not
220.46 +* changed).
220.47 +*
220.48 +* RETURNS
220.49 +*
220.50 +* The routine returns one of the following error codes:
220.51 +*
220.52 +* 0 - no error;
220.53 +* 1 - value out of range;
220.54 +* 2 - character string is syntactically incorrect. */
220.55 +
220.56 +int str2int(const char *str, int *_val)
220.57 +{ int d, k, s, val = 0;
220.58 + /* scan optional sign */
220.59 + if (str[0] == '+')
220.60 + s = +1, k = 1;
220.61 + else if (str[0] == '-')
220.62 + s = -1, k = 1;
220.63 + else
220.64 + s = +1, k = 0;
220.65 + /* check for the first digit */
220.66 + if (!isdigit((unsigned char)str[k])) return 2;
220.67 + /* scan digits */
220.68 + while (isdigit((unsigned char)str[k]))
220.69 + { d = str[k++] - '0';
220.70 + if (s > 0)
220.71 + { if (val > INT_MAX / 10) return 1;
220.72 + val *= 10;
220.73 + if (val > INT_MAX - d) return 1;
220.74 + val += d;
220.75 + }
220.76 + else
220.77 + { if (val < INT_MIN / 10) return 1;
220.78 + val *= 10;
220.79 + if (val < INT_MIN + d) return 1;
220.80 + val -= d;
220.81 + }
220.82 + }
220.83 + /* check for terminator */
220.84 + if (str[k] != '\0') return 2;
220.85 + /* conversion has been done */
220.86 + *_val = val;
220.87 + return 0;
220.88 +}
220.89 +
220.90 +/***********************************************************************
220.91 +* NAME
220.92 +*
220.93 +* str2num - convert character string to value of double type
220.94 +*
220.95 +* SYNOPSIS
220.96 +*
220.97 +* #include "glplib.h"
220.98 +* int str2num(const char *str, double *val);
220.99 +*
220.100 +* DESCRIPTION
220.101 +*
220.102 +* The routine str2num converts the character string str to a value of
220.103 +* double type and stores the value into location, which the parameter
220.104 +* val points to (in the case of error content of this location is not
220.105 +* changed).
220.106 +*
220.107 +* RETURNS
220.108 +*
220.109 +* The routine returns one of the following error codes:
220.110 +*
220.111 +* 0 - no error;
220.112 +* 1 - value out of range;
220.113 +* 2 - character string is syntactically incorrect. */
220.114 +
220.115 +int str2num(const char *str, double *_val)
220.116 +{ int k;
220.117 + double val;
220.118 + /* scan optional sign */
220.119 + k = (str[0] == '+' || str[0] == '-' ? 1 : 0);
220.120 + /* check for decimal point */
220.121 + if (str[k] == '.')
220.122 + { k++;
220.123 + /* a digit should follow it */
220.124 + if (!isdigit((unsigned char)str[k])) return 2;
220.125 + k++;
220.126 + goto frac;
220.127 + }
220.128 + /* integer part should start with a digit */
220.129 + if (!isdigit((unsigned char)str[k])) return 2;
220.130 + /* scan integer part */
220.131 + while (isdigit((unsigned char)str[k])) k++;
220.132 + /* check for decimal point */
220.133 + if (str[k] == '.') k++;
220.134 +frac: /* scan optional fraction part */
220.135 + while (isdigit((unsigned char)str[k])) k++;
220.136 + /* check for decimal exponent */
220.137 + if (str[k] == 'E' || str[k] == 'e')
220.138 + { k++;
220.139 + /* scan optional sign */
220.140 + if (str[k] == '+' || str[k] == '-') k++;
220.141 + /* a digit should follow E, E+ or E- */
220.142 + if (!isdigit((unsigned char)str[k])) return 2;
220.143 + }
220.144 + /* scan optional exponent part */
220.145 + while (isdigit((unsigned char)str[k])) k++;
220.146 + /* check for terminator */
220.147 + if (str[k] != '\0') return 2;
220.148 + /* perform conversion */
220.149 + { char *endptr;
220.150 + val = strtod(str, &endptr);
220.151 + if (*endptr != '\0') return 2;
220.152 + }
220.153 + /* check for overflow */
220.154 + if (!(-DBL_MAX <= val && val <= +DBL_MAX)) return 1;
220.155 + /* check for underflow */
220.156 + if (-DBL_MIN < val && val < +DBL_MIN) val = 0.0;
220.157 + /* conversion has been done */
220.158 + *_val = val;
220.159 + return 0;
220.160 +}
220.161 +
220.162 +/***********************************************************************
220.163 +* NAME
220.164 +*
220.165 +* strspx - remove all spaces from character string
220.166 +*
220.167 +* SYNOPSIS
220.168 +*
220.169 +* #include "glplib.h"
220.170 +* char *strspx(char *str);
220.171 +*
220.172 +* DESCRIPTION
220.173 +*
220.174 +* The routine strspx removes all spaces from the character string str.
220.175 +*
220.176 +* RETURNS
220.177 +*
220.178 +* The routine returns a pointer to the character string.
220.179 +*
220.180 +* EXAMPLES
220.181 +*
220.182 +* strspx(" Errare humanum est ") => "Errarehumanumest"
220.183 +*
220.184 +* strspx(" ") => "" */
220.185 +
220.186 +char *strspx(char *str)
220.187 +{ char *s, *t;
220.188 + for (s = t = str; *s; s++) if (*s != ' ') *t++ = *s;
220.189 + *t = '\0';
220.190 + return str;
220.191 +}
220.192 +
220.193 +/***********************************************************************
220.194 +* NAME
220.195 +*
220.196 +* strtrim - remove trailing spaces from character string
220.197 +*
220.198 +* SYNOPSIS
220.199 +*
220.200 +* #include "glplib.h"
220.201 +* char *strtrim(char *str);
220.202 +*
220.203 +* DESCRIPTION
220.204 +*
220.205 +* The routine strtrim removes trailing spaces from the character
220.206 +* string str.
220.207 +*
220.208 +* RETURNS
220.209 +*
220.210 +* The routine returns a pointer to the character string.
220.211 +*
220.212 +* EXAMPLES
220.213 +*
220.214 +* strtrim("Errare humanum est ") => "Errare humanum est"
220.215 +*
220.216 +* strtrim(" ") => "" */
220.217 +
220.218 +char *strtrim(char *str)
220.219 +{ char *t;
220.220 + for (t = strrchr(str, '\0') - 1; t >= str; t--)
220.221 + { if (*t != ' ') break;
220.222 + *t = '\0';
220.223 + }
220.224 + return str;
220.225 +}
220.226 +
220.227 +/***********************************************************************
220.228 +* NAME
220.229 +*
220.230 +* strrev - reverse character string
220.231 +*
220.232 +* SYNOPSIS
220.233 +*
220.234 +* #include "glplib.h"
220.235 +* char *strrev(char *s);
220.236 +*
220.237 +* DESCRIPTION
220.238 +*
220.239 +* The routine strrev changes characters in a character string s to the
220.240 +* reverse order, except the terminating null character.
220.241 +*
220.242 +* RETURNS
220.243 +*
220.244 +* The routine returns the pointer s.
220.245 +*
220.246 +* EXAMPLES
220.247 +*
220.248 +* strrev("") => ""
220.249 +*
220.250 +* strrev("Today is Monday") => "yadnoM si yadoT" */
220.251 +
220.252 +char *strrev(char *s)
220.253 +{ int i, j;
220.254 + char t;
220.255 + for (i = 0, j = strlen(s)-1; i < j; i++, j--)
220.256 + t = s[i], s[i] = s[j], s[j] = t;
220.257 + return s;
220.258 +}
220.259 +
220.260 +/***********************************************************************
220.261 +* NAME
220.262 +*
220.263 +* gcd - find greatest common divisor of two integers
220.264 +*
220.265 +* SYNOPSIS
220.266 +*
220.267 +* #include "glplib.h"
220.268 +* int gcd(int x, int y);
220.269 +*
220.270 +* RETURNS
220.271 +*
220.272 +* The routine gcd returns gcd(x, y), the greatest common divisor of
220.273 +* the two positive integers given.
220.274 +*
220.275 +* ALGORITHM
220.276 +*
220.277 +* The routine gcd is based on Euclid's algorithm.
220.278 +*
220.279 +* REFERENCES
220.280 +*
220.281 +* Don Knuth, The Art of Computer Programming, Vol.2: Seminumerical
220.282 +* Algorithms, 3rd Edition, Addison-Wesley, 1997. Section 4.5.2: The
220.283 +* Greatest Common Divisor, pp. 333-56. */
220.284 +
220.285 +int gcd(int x, int y)
220.286 +{ int r;
220.287 + xassert(x > 0 && y > 0);
220.288 + while (y > 0)
220.289 + r = x % y, x = y, y = r;
220.290 + return x;
220.291 +}
220.292 +
220.293 +/***********************************************************************
220.294 +* NAME
220.295 +*
220.296 +* gcdn - find greatest common divisor of n integers
220.297 +*
220.298 +* SYNOPSIS
220.299 +*
220.300 +* #include "glplib.h"
220.301 +* int gcdn(int n, int x[]);
220.302 +*
220.303 +* RETURNS
220.304 +*
220.305 +* The routine gcdn returns gcd(x[1], x[2], ..., x[n]), the greatest
220.306 +* common divisor of n positive integers given, n > 0.
220.307 +*
220.308 +* BACKGROUND
220.309 +*
220.310 +* The routine gcdn is based on the following identity:
220.311 +*
220.312 +* gcd(x, y, z) = gcd(gcd(x, y), z).
220.313 +*
220.314 +* REFERENCES
220.315 +*
220.316 +* Don Knuth, The Art of Computer Programming, Vol.2: Seminumerical
220.317 +* Algorithms, 3rd Edition, Addison-Wesley, 1997. Section 4.5.2: The
220.318 +* Greatest Common Divisor, pp. 333-56. */
220.319 +
220.320 +int gcdn(int n, int x[])
220.321 +{ int d, j;
220.322 + xassert(n > 0);
220.323 + for (j = 1; j <= n; j++)
220.324 + { xassert(x[j] > 0);
220.325 + if (j == 1)
220.326 + d = x[1];
220.327 + else
220.328 + d = gcd(d, x[j]);
220.329 + if (d == 1) break;
220.330 + }
220.331 + return d;
220.332 +}
220.333 +
220.334 +/***********************************************************************
220.335 +* NAME
220.336 +*
220.337 +* lcm - find least common multiple of two integers
220.338 +*
220.339 +* SYNOPSIS
220.340 +*
220.341 +* #include "glplib.h"
220.342 +* int lcm(int x, int y);
220.343 +*
220.344 +* RETURNS
220.345 +*
220.346 +* The routine lcm returns lcm(x, y), the least common multiple of the
220.347 +* two positive integers given. In case of integer overflow the routine
220.348 +* returns zero.
220.349 +*
220.350 +* BACKGROUND
220.351 +*
220.352 +* The routine lcm is based on the following identity:
220.353 +*
220.354 +* lcm(x, y) = (x * y) / gcd(x, y) = x * [y / gcd(x, y)],
220.355 +*
220.356 +* where gcd(x, y) is the greatest common divisor of x and y. */
220.357 +
220.358 +int lcm(int x, int y)
220.359 +{ xassert(x > 0);
220.360 + xassert(y > 0);
220.361 + y /= gcd(x, y);
220.362 + if (x > INT_MAX / y) return 0;
220.363 + return x * y;
220.364 +}
220.365 +
220.366 +/***********************************************************************
220.367 +* NAME
220.368 +*
220.369 +* lcmn - find least common multiple of n integers
220.370 +*
220.371 +* SYNOPSIS
220.372 +*
220.373 +* #include "glplib.h"
220.374 +* int lcmn(int n, int x[]);
220.375 +*
220.376 +* RETURNS
220.377 +*
220.378 +* The routine lcmn returns lcm(x[1], x[2], ..., x[n]), the least
220.379 +* common multiple of n positive integers given, n > 0. In case of
220.380 +* integer overflow the routine returns zero.
220.381 +*
220.382 +* BACKGROUND
220.383 +*
220.384 +* The routine lcmn is based on the following identity:
220.385 +*
220.386 +* lcmn(x, y, z) = lcm(lcm(x, y), z),
220.387 +*
220.388 +* where lcm(x, y) is the least common multiple of x and y. */
220.389 +
220.390 +int lcmn(int n, int x[])
220.391 +{ int m, j;
220.392 + xassert(n > 0);
220.393 + for (j = 1; j <= n; j++)
220.394 + { xassert(x[j] > 0);
220.395 + if (j == 1)
220.396 + m = x[1];
220.397 + else
220.398 + m = lcm(m, x[j]);
220.399 + if (m == 0) break;
220.400 + }
220.401 + return m;
220.402 +}
220.403 +
220.404 +/***********************************************************************
220.405 +* NAME
220.406 +*
220.407 +* round2n - round floating-point number to nearest power of two
220.408 +*
220.409 +* SYNOPSIS
220.410 +*
220.411 +* #include "glplib.h"
220.412 +* double round2n(double x);
220.413 +*
220.414 +* RETURNS
220.415 +*
220.416 +* Given a positive floating-point value x the routine round2n returns
220.417 +* 2^n such that |x - 2^n| is minimal.
220.418 +*
220.419 +* EXAMPLES
220.420 +*
220.421 +* round2n(10.1) = 2^3 = 8
220.422 +* round2n(15.3) = 2^4 = 16
220.423 +* round2n(0.01) = 2^(-7) = 0.0078125
220.424 +*
220.425 +* BACKGROUND
220.426 +*
220.427 +* Let x = f * 2^e, where 0.5 <= f < 1 is a normalized fractional part,
220.428 +* e is an integer exponent. Then, obviously, 0.5 * 2^e <= x < 2^e, so
220.429 +* if x - 0.5 * 2^e <= 2^e - x, we choose 0.5 * 2^e = 2^(e-1), and 2^e
220.430 +* otherwise. The latter condition can be written as 2 * x <= 1.5 * 2^e
220.431 +* or 2 * f * 2^e <= 1.5 * 2^e or, finally, f <= 0.75. */
220.432 +
220.433 +double round2n(double x)
220.434 +{ int e;
220.435 + double f;
220.436 + xassert(x > 0.0);
220.437 + f = frexp(x, &e);
220.438 + return ldexp(1.0, f <= 0.75 ? e-1 : e);
220.439 +}
220.440 +
220.441 +/***********************************************************************
220.442 +* NAME
220.443 +*
220.444 +* fp2rat - convert floating-point number to rational number
220.445 +*
220.446 +* SYNOPSIS
220.447 +*
220.448 +* #include "glplib.h"
220.449 +* int fp2rat(double x, double eps, double *p, double *q);
220.450 +*
220.451 +* DESCRIPTION
220.452 +*
220.453 +* Given a floating-point number 0 <= x < 1 the routine fp2rat finds
220.454 +* its "best" rational approximation p / q, where p >= 0 and q > 0 are
220.455 +* integer numbers, such that |x - p / q| <= eps.
220.456 +*
220.457 +* RETURNS
220.458 +*
220.459 +* The routine fp2rat returns the number of iterations used to achieve
220.460 +* the specified precision eps.
220.461 +*
220.462 +* EXAMPLES
220.463 +*
220.464 +* For x = sqrt(2) - 1 = 0.414213562373095 and eps = 1e-6 the routine
220.465 +* gives p = 408 and q = 985, where 408 / 985 = 0.414213197969543.
220.466 +*
220.467 +* BACKGROUND
220.468 +*
220.469 +* It is well known that every positive real number x can be expressed
220.470 +* as the following continued fraction:
220.471 +*
220.472 +* x = b[0] + a[1]
220.473 +* ------------------------
220.474 +* b[1] + a[2]
220.475 +* -----------------
220.476 +* b[2] + a[3]
220.477 +* ----------
220.478 +* b[3] + ...
220.479 +*
220.480 +* where:
220.481 +*
220.482 +* a[k] = 1, k = 0, 1, 2, ...
220.483 +*
220.484 +* b[k] = floor(x[k]), k = 0, 1, 2, ...
220.485 +*
220.486 +* x[0] = x,
220.487 +*
220.488 +* x[k] = 1 / frac(x[k-1]), k = 1, 2, 3, ...
220.489 +*
220.490 +* To find the "best" rational approximation of x the routine computes
220.491 +* partial fractions f[k] by dropping after k terms as follows:
220.492 +*
220.493 +* f[k] = A[k] / B[k],
220.494 +*
220.495 +* where:
220.496 +*
220.497 +* A[-1] = 1, A[0] = b[0], B[-1] = 0, B[0] = 1,
220.498 +*
220.499 +* A[k] = b[k] * A[k-1] + a[k] * A[k-2],
220.500 +*
220.501 +* B[k] = b[k] * B[k-1] + a[k] * B[k-2].
220.502 +*
220.503 +* Once the condition
220.504 +*
220.505 +* |x - f[k]| <= eps
220.506 +*
220.507 +* has been satisfied, the routine reports p = A[k] and q = B[k] as the
220.508 +* final answer.
220.509 +*
220.510 +* In the table below here is some statistics obtained for one million
220.511 +* random numbers uniformly distributed in the range [0, 1).
220.512 +*
220.513 +* eps max p mean p max q mean q max k mean k
220.514 +* -------------------------------------------------------------
220.515 +* 1e-1 8 1.6 9 3.2 3 1.4
220.516 +* 1e-2 98 6.2 99 12.4 5 2.4
220.517 +* 1e-3 997 20.7 998 41.5 8 3.4
220.518 +* 1e-4 9959 66.6 9960 133.5 10 4.4
220.519 +* 1e-5 97403 211.7 97404 424.2 13 5.3
220.520 +* 1e-6 479669 669.9 479670 1342.9 15 6.3
220.521 +* 1e-7 1579030 2127.3 3962146 4257.8 16 7.3
220.522 +* 1e-8 26188823 6749.4 26188824 13503.4 19 8.2
220.523 +*
220.524 +* REFERENCES
220.525 +*
220.526 +* W. B. Jones and W. J. Thron, "Continued Fractions: Analytic Theory
220.527 +* and Applications," Encyclopedia on Mathematics and Its Applications,
220.528 +* Addison-Wesley, 1980. */
220.529 +
220.530 +int fp2rat(double x, double eps, double *p, double *q)
220.531 +{ int k;
220.532 + double xk, Akm1, Ak, Bkm1, Bk, ak, bk, fk, temp;
220.533 + if (!(0.0 <= x && x < 1.0))
220.534 + xerror("fp2rat: x = %g; number out of range\n", x);
220.535 + for (k = 0; ; k++)
220.536 + { xassert(k <= 100);
220.537 + if (k == 0)
220.538 + { /* x[0] = x */
220.539 + xk = x;
220.540 + /* A[-1] = 1 */
220.541 + Akm1 = 1.0;
220.542 + /* A[0] = b[0] = floor(x[0]) = 0 */
220.543 + Ak = 0.0;
220.544 + /* B[-1] = 0 */
220.545 + Bkm1 = 0.0;
220.546 + /* B[0] = 1 */
220.547 + Bk = 1.0;
220.548 + }
220.549 + else
220.550 + { /* x[k] = 1 / frac(x[k-1]) */
220.551 + temp = xk - floor(xk);
220.552 + xassert(temp != 0.0);
220.553 + xk = 1.0 / temp;
220.554 + /* a[k] = 1 */
220.555 + ak = 1.0;
220.556 + /* b[k] = floor(x[k]) */
220.557 + bk = floor(xk);
220.558 + /* A[k] = b[k] * A[k-1] + a[k] * A[k-2] */
220.559 + temp = bk * Ak + ak * Akm1;
220.560 + Akm1 = Ak, Ak = temp;
220.561 + /* B[k] = b[k] * B[k-1] + a[k] * B[k-2] */
220.562 + temp = bk * Bk + ak * Bkm1;
220.563 + Bkm1 = Bk, Bk = temp;
220.564 + }
220.565 + /* f[k] = A[k] / B[k] */
220.566 + fk = Ak / Bk;
220.567 +#if 0
220.568 + print("%.*g / %.*g = %.*g", DBL_DIG, Ak, DBL_DIG, Bk, DBL_DIG,
220.569 + fk);
220.570 +#endif
220.571 + if (fabs(x - fk) <= eps) break;
220.572 + }
220.573 + *p = Ak;
220.574 + *q = Bk;
220.575 + return k;
220.576 +}
220.577 +
220.578 +/***********************************************************************
220.579 +* NAME
220.580 +*
220.581 +* jday - convert calendar date to Julian day number
220.582 +*
220.583 +* SYNOPSIS
220.584 +*
220.585 +* #include "glplib.h"
220.586 +* int jday(int d, int m, int y);
220.587 +*
220.588 +* DESCRIPTION
220.589 +*
220.590 +* The routine jday converts a calendar date, Gregorian calendar, to
220.591 +* corresponding Julian day number j.
220.592 +*
220.593 +* From the given day d, month m, and year y, the Julian day number j
220.594 +* is computed without using tables.
220.595 +*
220.596 +* The routine is valid for 1 <= y <= 4000.
220.597 +*
220.598 +* RETURNS
220.599 +*
220.600 +* The routine jday returns the Julian day number, or negative value if
220.601 +* the specified date is incorrect.
220.602 +*
220.603 +* REFERENCES
220.604 +*
220.605 +* R. G. Tantzen, Algorithm 199: conversions between calendar date and
220.606 +* Julian day number, Communications of the ACM, vol. 6, no. 8, p. 444,
220.607 +* Aug. 1963. */
220.608 +
220.609 +int jday(int d, int m, int y)
220.610 +{ int c, ya, j, dd;
220.611 + if (!(1 <= d && d <= 31 && 1 <= m && m <= 12 && 1 <= y &&
220.612 + y <= 4000))
220.613 + { j = -1;
220.614 + goto done;
220.615 + }
220.616 + if (m >= 3) m -= 3; else m += 9, y--;
220.617 + c = y / 100;
220.618 + ya = y - 100 * c;
220.619 + j = (146097 * c) / 4 + (1461 * ya) / 4 + (153 * m + 2) / 5 + d +
220.620 + 1721119;
220.621 + jdate(j, &dd, NULL, NULL);
220.622 + if (d != dd) j = -1;
220.623 +done: return j;
220.624 +}
220.625 +
220.626 +/***********************************************************************
220.627 +* NAME
220.628 +*
220.629 +* jdate - convert Julian day number to calendar date
220.630 +*
220.631 +* SYNOPSIS
220.632 +*
220.633 +* #include "glplib.h"
220.634 +* void jdate(int j, int *d, int *m, int *y);
220.635 +*
220.636 +* DESCRIPTION
220.637 +*
220.638 +* The routine jdate converts a Julian day number j to corresponding
220.639 +* calendar date, Gregorian calendar.
220.640 +*
220.641 +* The day d, month m, and year y are computed without using tables and
220.642 +* stored in corresponding locations.
220.643 +*
220.644 +* The routine is valid for 1721426 <= j <= 3182395.
220.645 +*
220.646 +* RETURNS
220.647 +*
220.648 +* If the conversion is successful, the routine returns zero, otherwise
220.649 +* non-zero.
220.650 +*
220.651 +* REFERENCES
220.652 +*
220.653 +* R. G. Tantzen, Algorithm 199: conversions between calendar date and
220.654 +* Julian day number, Communications of the ACM, vol. 6, no. 8, p. 444,
220.655 +* Aug. 1963. */
220.656 +
220.657 +int jdate(int j, int *_d, int *_m, int *_y)
220.658 +{ int d, m, y, ret = 0;
220.659 + if (!(1721426 <= j && j <= 3182395))
220.660 + { ret = 1;
220.661 + goto done;
220.662 + }
220.663 + j -= 1721119;
220.664 + y = (4 * j - 1) / 146097;
220.665 + j = (4 * j - 1) % 146097;
220.666 + d = j / 4;
220.667 + j = (4 * d + 3) / 1461;
220.668 + d = (4 * d + 3) % 1461;
220.669 + d = (d + 4) / 4;
220.670 + m = (5 * d - 3) / 153;
220.671 + d = (5 * d - 3) % 153;
220.672 + d = (d + 5) / 5;
220.673 + y = 100 * y + j;
220.674 + if (m <= 9) m += 3; else m -= 9, y++;
220.675 + if (_d != NULL) *_d = d;
220.676 + if (_m != NULL) *_m = m;
220.677 + if (_y != NULL) *_y = y;
220.678 +done: return ret;
220.679 +}
220.680 +
220.681 +#if 0
220.682 +int main(void)
220.683 +{ int jbeg, jend, j, d, m, y;
220.684 + jbeg = jday(1, 1, 1);
220.685 + jend = jday(31, 12, 4000);
220.686 + for (j = jbeg; j <= jend; j++)
220.687 + { xassert(jdate(j, &d, &m, &y) == 0);
220.688 + xassert(jday(d, m, y) == j);
220.689 + }
220.690 + xprintf("Routines jday and jdate work correctly.\n");
220.691 + return 0;
220.692 +}
220.693 +#endif
220.694 +
220.695 +/* eof */
221.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
221.2 +++ b/src/glplpf.c Mon Dec 06 13:09:21 2010 +0100
221.3 @@ -0,0 +1,978 @@
221.4 +/* glplpf.c (LP basis factorization, Schur complement version) */
221.5 +
221.6 +/***********************************************************************
221.7 +* This code is part of GLPK (GNU Linear Programming Kit).
221.8 +*
221.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
221.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
221.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
221.12 +* E-mail: <mao@gnu.org>.
221.13 +*
221.14 +* GLPK is free software: you can redistribute it and/or modify it
221.15 +* under the terms of the GNU General Public License as published by
221.16 +* the Free Software Foundation, either version 3 of the License, or
221.17 +* (at your option) any later version.
221.18 +*
221.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
221.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
221.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
221.22 +* License for more details.
221.23 +*
221.24 +* You should have received a copy of the GNU General Public License
221.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
221.26 +***********************************************************************/
221.27 +
221.28 +#include "glplpf.h"
221.29 +#include "glpenv.h"
221.30 +#define xfault xerror
221.31 +
221.32 +#define _GLPLPF_DEBUG 0
221.33 +
221.34 +/* CAUTION: DO NOT CHANGE THE LIMIT BELOW */
221.35 +
221.36 +#define M_MAX 100000000 /* = 100*10^6 */
221.37 +/* maximal order of the basis matrix */
221.38 +
221.39 +/***********************************************************************
221.40 +* NAME
221.41 +*
221.42 +* lpf_create_it - create LP basis factorization
221.43 +*
221.44 +* SYNOPSIS
221.45 +*
221.46 +* #include "glplpf.h"
221.47 +* LPF *lpf_create_it(void);
221.48 +*
221.49 +* DESCRIPTION
221.50 +*
221.51 +* The routine lpf_create_it creates a program object, which represents
221.52 +* a factorization of LP basis.
221.53 +*
221.54 +* RETURNS
221.55 +*
221.56 +* The routine lpf_create_it returns a pointer to the object created. */
221.57 +
221.58 +LPF *lpf_create_it(void)
221.59 +{ LPF *lpf;
221.60 +#if _GLPLPF_DEBUG
221.61 + xprintf("lpf_create_it: warning: debug mode enabled\n");
221.62 +#endif
221.63 + lpf = xmalloc(sizeof(LPF));
221.64 + lpf->valid = 0;
221.65 + lpf->m0_max = lpf->m0 = 0;
221.66 + lpf->luf = luf_create_it();
221.67 + lpf->m = 0;
221.68 + lpf->B = NULL;
221.69 + lpf->n_max = 50;
221.70 + lpf->n = 0;
221.71 + lpf->R_ptr = lpf->R_len = NULL;
221.72 + lpf->S_ptr = lpf->S_len = NULL;
221.73 + lpf->scf = NULL;
221.74 + lpf->P_row = lpf->P_col = NULL;
221.75 + lpf->Q_row = lpf->Q_col = NULL;
221.76 + lpf->v_size = 1000;
221.77 + lpf->v_ptr = 0;
221.78 + lpf->v_ind = NULL;
221.79 + lpf->v_val = NULL;
221.80 + lpf->work1 = lpf->work2 = NULL;
221.81 + return lpf;
221.82 +}
221.83 +
221.84 +/***********************************************************************
221.85 +* NAME
221.86 +*
221.87 +* lpf_factorize - compute LP basis factorization
221.88 +*
221.89 +* SYNOPSIS
221.90 +*
221.91 +* #include "glplpf.h"
221.92 +* int lpf_factorize(LPF *lpf, int m, const int bh[], int (*col)
221.93 +* (void *info, int j, int ind[], double val[]), void *info);
221.94 +*
221.95 +* DESCRIPTION
221.96 +*
221.97 +* The routine lpf_factorize computes the factorization of the basis
221.98 +* matrix B specified by the routine col.
221.99 +*
221.100 +* The parameter lpf specified the basis factorization data structure
221.101 +* created with the routine lpf_create_it.
221.102 +*
221.103 +* The parameter m specifies the order of B, m > 0.
221.104 +*
221.105 +* The array bh specifies the basis header: bh[j], 1 <= j <= m, is the
221.106 +* number of j-th column of B in some original matrix. The array bh is
221.107 +* optional and can be specified as NULL.
221.108 +*
221.109 +* The formal routine col specifies the matrix B to be factorized. To
221.110 +* obtain j-th column of A the routine lpf_factorize calls the routine
221.111 +* col with the parameter j (1 <= j <= n). In response the routine col
221.112 +* should store row indices and numerical values of non-zero elements
221.113 +* of j-th column of B to locations ind[1,...,len] and val[1,...,len],
221.114 +* respectively, where len is the number of non-zeros in j-th column
221.115 +* returned on exit. Neither zero nor duplicate elements are allowed.
221.116 +*
221.117 +* The parameter info is a transit pointer passed to the routine col.
221.118 +*
221.119 +* RETURNS
221.120 +*
221.121 +* 0 The factorization has been successfully computed.
221.122 +*
221.123 +* LPF_ESING
221.124 +* The specified matrix is singular within the working precision.
221.125 +*
221.126 +* LPF_ECOND
221.127 +* The specified matrix is ill-conditioned.
221.128 +*
221.129 +* For more details see comments to the routine luf_factorize. */
221.130 +
221.131 +int lpf_factorize(LPF *lpf, int m, const int bh[], int (*col)
221.132 + (void *info, int j, int ind[], double val[]), void *info)
221.133 +{ int k, ret;
221.134 +#if _GLPLPF_DEBUG
221.135 + int i, j, len, *ind;
221.136 + double *B, *val;
221.137 +#endif
221.138 + xassert(bh == bh);
221.139 + if (m < 1)
221.140 + xfault("lpf_factorize: m = %d; invalid parameter\n", m);
221.141 + if (m > M_MAX)
221.142 + xfault("lpf_factorize: m = %d; matrix too big\n", m);
221.143 + lpf->m0 = lpf->m = m;
221.144 + /* invalidate the factorization */
221.145 + lpf->valid = 0;
221.146 + /* allocate/reallocate arrays, if necessary */
221.147 + if (lpf->R_ptr == NULL)
221.148 + lpf->R_ptr = xcalloc(1+lpf->n_max, sizeof(int));
221.149 + if (lpf->R_len == NULL)
221.150 + lpf->R_len = xcalloc(1+lpf->n_max, sizeof(int));
221.151 + if (lpf->S_ptr == NULL)
221.152 + lpf->S_ptr = xcalloc(1+lpf->n_max, sizeof(int));
221.153 + if (lpf->S_len == NULL)
221.154 + lpf->S_len = xcalloc(1+lpf->n_max, sizeof(int));
221.155 + if (lpf->scf == NULL)
221.156 + lpf->scf = scf_create_it(lpf->n_max);
221.157 + if (lpf->v_ind == NULL)
221.158 + lpf->v_ind = xcalloc(1+lpf->v_size, sizeof(int));
221.159 + if (lpf->v_val == NULL)
221.160 + lpf->v_val = xcalloc(1+lpf->v_size, sizeof(double));
221.161 + if (lpf->m0_max < m)
221.162 + { if (lpf->P_row != NULL) xfree(lpf->P_row);
221.163 + if (lpf->P_col != NULL) xfree(lpf->P_col);
221.164 + if (lpf->Q_row != NULL) xfree(lpf->Q_row);
221.165 + if (lpf->Q_col != NULL) xfree(lpf->Q_col);
221.166 + if (lpf->work1 != NULL) xfree(lpf->work1);
221.167 + if (lpf->work2 != NULL) xfree(lpf->work2);
221.168 + lpf->m0_max = m + 100;
221.169 + lpf->P_row = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
221.170 + lpf->P_col = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
221.171 + lpf->Q_row = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
221.172 + lpf->Q_col = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
221.173 + lpf->work1 = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(double));
221.174 + lpf->work2 = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(double));
221.175 + }
221.176 + /* try to factorize the basis matrix */
221.177 + switch (luf_factorize(lpf->luf, m, col, info))
221.178 + { case 0:
221.179 + break;
221.180 + case LUF_ESING:
221.181 + ret = LPF_ESING;
221.182 + goto done;
221.183 + case LUF_ECOND:
221.184 + ret = LPF_ECOND;
221.185 + goto done;
221.186 + default:
221.187 + xassert(lpf != lpf);
221.188 + }
221.189 + /* the basis matrix has been successfully factorized */
221.190 + lpf->valid = 1;
221.191 +#if _GLPLPF_DEBUG
221.192 + /* store the basis matrix for debugging */
221.193 + if (lpf->B != NULL) xfree(lpf->B);
221.194 + xassert(m <= 32767);
221.195 + lpf->B = B = xcalloc(1+m*m, sizeof(double));
221.196 + ind = xcalloc(1+m, sizeof(int));
221.197 + val = xcalloc(1+m, sizeof(double));
221.198 + for (k = 1; k <= m * m; k++)
221.199 + B[k] = 0.0;
221.200 + for (j = 1; j <= m; j++)
221.201 + { len = col(info, j, ind, val);
221.202 + xassert(0 <= len && len <= m);
221.203 + for (k = 1; k <= len; k++)
221.204 + { i = ind[k];
221.205 + xassert(1 <= i && i <= m);
221.206 + xassert(B[(i - 1) * m + j] == 0.0);
221.207 + xassert(val[k] != 0.0);
221.208 + B[(i - 1) * m + j] = val[k];
221.209 + }
221.210 + }
221.211 + xfree(ind);
221.212 + xfree(val);
221.213 +#endif
221.214 + /* B = B0, so there are no additional rows/columns */
221.215 + lpf->n = 0;
221.216 + /* reset the Schur complement factorization */
221.217 + scf_reset_it(lpf->scf);
221.218 + /* P := Q := I */
221.219 + for (k = 1; k <= m; k++)
221.220 + { lpf->P_row[k] = lpf->P_col[k] = k;
221.221 + lpf->Q_row[k] = lpf->Q_col[k] = k;
221.222 + }
221.223 + /* make all SVA locations free */
221.224 + lpf->v_ptr = 1;
221.225 + ret = 0;
221.226 +done: /* return to the calling program */
221.227 + return ret;
221.228 +}
221.229 +
221.230 +/***********************************************************************
221.231 +* The routine r_prod computes the product y := y + alpha * R * x,
221.232 +* where x is a n-vector, alpha is a scalar, y is a m0-vector.
221.233 +*
221.234 +* Since matrix R is available by columns, the product is computed as
221.235 +* a linear combination:
221.236 +*
221.237 +* y := y + alpha * (R[1] * x[1] + ... + R[n] * x[n]),
221.238 +*
221.239 +* where R[j] is j-th column of R. */
221.240 +
221.241 +static void r_prod(LPF *lpf, double y[], double a, const double x[])
221.242 +{ int n = lpf->n;
221.243 + int *R_ptr = lpf->R_ptr;
221.244 + int *R_len = lpf->R_len;
221.245 + int *v_ind = lpf->v_ind;
221.246 + double *v_val = lpf->v_val;
221.247 + int j, beg, end, ptr;
221.248 + double t;
221.249 + for (j = 1; j <= n; j++)
221.250 + { if (x[j] == 0.0) continue;
221.251 + /* y := y + alpha * R[j] * x[j] */
221.252 + t = a * x[j];
221.253 + beg = R_ptr[j];
221.254 + end = beg + R_len[j];
221.255 + for (ptr = beg; ptr < end; ptr++)
221.256 + y[v_ind[ptr]] += t * v_val[ptr];
221.257 + }
221.258 + return;
221.259 +}
221.260 +
221.261 +/***********************************************************************
221.262 +* The routine rt_prod computes the product y := y + alpha * R' * x,
221.263 +* where R' is a matrix transposed to R, x is a m0-vector, alpha is a
221.264 +* scalar, y is a n-vector.
221.265 +*
221.266 +* Since matrix R is available by columns, the product components are
221.267 +* computed as inner products:
221.268 +*
221.269 +* y[j] := y[j] + alpha * (j-th column of R) * x
221.270 +*
221.271 +* for j = 1, 2, ..., n. */
221.272 +
221.273 +static void rt_prod(LPF *lpf, double y[], double a, const double x[])
221.274 +{ int n = lpf->n;
221.275 + int *R_ptr = lpf->R_ptr;
221.276 + int *R_len = lpf->R_len;
221.277 + int *v_ind = lpf->v_ind;
221.278 + double *v_val = lpf->v_val;
221.279 + int j, beg, end, ptr;
221.280 + double t;
221.281 + for (j = 1; j <= n; j++)
221.282 + { /* t := (j-th column of R) * x */
221.283 + t = 0.0;
221.284 + beg = R_ptr[j];
221.285 + end = beg + R_len[j];
221.286 + for (ptr = beg; ptr < end; ptr++)
221.287 + t += v_val[ptr] * x[v_ind[ptr]];
221.288 + /* y[j] := y[j] + alpha * t */
221.289 + y[j] += a * t;
221.290 + }
221.291 + return;
221.292 +}
221.293 +
221.294 +/***********************************************************************
221.295 +* The routine s_prod computes the product y := y + alpha * S * x,
221.296 +* where x is a m0-vector, alpha is a scalar, y is a n-vector.
221.297 +*
221.298 +* Since matrix S is available by rows, the product components are
221.299 +* computed as inner products:
221.300 +*
221.301 +* y[i] = y[i] + alpha * (i-th row of S) * x
221.302 +*
221.303 +* for i = 1, 2, ..., n. */
221.304 +
221.305 +static void s_prod(LPF *lpf, double y[], double a, const double x[])
221.306 +{ int n = lpf->n;
221.307 + int *S_ptr = lpf->S_ptr;
221.308 + int *S_len = lpf->S_len;
221.309 + int *v_ind = lpf->v_ind;
221.310 + double *v_val = lpf->v_val;
221.311 + int i, beg, end, ptr;
221.312 + double t;
221.313 + for (i = 1; i <= n; i++)
221.314 + { /* t := (i-th row of S) * x */
221.315 + t = 0.0;
221.316 + beg = S_ptr[i];
221.317 + end = beg + S_len[i];
221.318 + for (ptr = beg; ptr < end; ptr++)
221.319 + t += v_val[ptr] * x[v_ind[ptr]];
221.320 + /* y[i] := y[i] + alpha * t */
221.321 + y[i] += a * t;
221.322 + }
221.323 + return;
221.324 +}
221.325 +
221.326 +/***********************************************************************
221.327 +* The routine st_prod computes the product y := y + alpha * S' * x,
221.328 +* where S' is a matrix transposed to S, x is a n-vector, alpha is a
221.329 +* scalar, y is m0-vector.
221.330 +*
221.331 +* Since matrix R is available by rows, the product is computed as a
221.332 +* linear combination:
221.333 +*
221.334 +* y := y + alpha * (S'[1] * x[1] + ... + S'[n] * x[n]),
221.335 +*
221.336 +* where S'[i] is i-th row of S. */
221.337 +
221.338 +static void st_prod(LPF *lpf, double y[], double a, const double x[])
221.339 +{ int n = lpf->n;
221.340 + int *S_ptr = lpf->S_ptr;
221.341 + int *S_len = lpf->S_len;
221.342 + int *v_ind = lpf->v_ind;
221.343 + double *v_val = lpf->v_val;
221.344 + int i, beg, end, ptr;
221.345 + double t;
221.346 + for (i = 1; i <= n; i++)
221.347 + { if (x[i] == 0.0) continue;
221.348 + /* y := y + alpha * S'[i] * x[i] */
221.349 + t = a * x[i];
221.350 + beg = S_ptr[i];
221.351 + end = beg + S_len[i];
221.352 + for (ptr = beg; ptr < end; ptr++)
221.353 + y[v_ind[ptr]] += t * v_val[ptr];
221.354 + }
221.355 + return;
221.356 +}
221.357 +
221.358 +#if _GLPLPF_DEBUG
221.359 +/***********************************************************************
221.360 +* The routine check_error computes the maximal relative error between
221.361 +* left- and right-hand sides for the system B * x = b (if tr is zero)
221.362 +* or B' * x = b (if tr is non-zero), where B' is a matrix transposed
221.363 +* to B. (This routine is intended for debugging only.) */
221.364 +
221.365 +static void check_error(LPF *lpf, int tr, const double x[],
221.366 + const double b[])
221.367 +{ int m = lpf->m;
221.368 + double *B = lpf->B;
221.369 + int i, j;
221.370 + double d, dmax = 0.0, s, t, tmax;
221.371 + for (i = 1; i <= m; i++)
221.372 + { s = 0.0;
221.373 + tmax = 1.0;
221.374 + for (j = 1; j <= m; j++)
221.375 + { if (!tr)
221.376 + t = B[m * (i - 1) + j] * x[j];
221.377 + else
221.378 + t = B[m * (j - 1) + i] * x[j];
221.379 + if (tmax < fabs(t)) tmax = fabs(t);
221.380 + s += t;
221.381 + }
221.382 + d = fabs(s - b[i]) / tmax;
221.383 + if (dmax < d) dmax = d;
221.384 + }
221.385 + if (dmax > 1e-8)
221.386 + xprintf("%s: dmax = %g; relative error too large\n",
221.387 + !tr ? "lpf_ftran" : "lpf_btran", dmax);
221.388 + return;
221.389 +}
221.390 +#endif
221.391 +
221.392 +/***********************************************************************
221.393 +* NAME
221.394 +*
221.395 +* lpf_ftran - perform forward transformation (solve system B*x = b)
221.396 +*
221.397 +* SYNOPSIS
221.398 +*
221.399 +* #include "glplpf.h"
221.400 +* void lpf_ftran(LPF *lpf, double x[]);
221.401 +*
221.402 +* DESCRIPTION
221.403 +*
221.404 +* The routine lpf_ftran performs forward transformation, i.e. solves
221.405 +* the system B*x = b, where B is the basis matrix, x is the vector of
221.406 +* unknowns to be computed, b is the vector of right-hand sides.
221.407 +*
221.408 +* On entry elements of the vector b should be stored in dense format
221.409 +* in locations x[1], ..., x[m], where m is the number of rows. On exit
221.410 +* the routine stores elements of the vector x in the same locations.
221.411 +*
221.412 +* BACKGROUND
221.413 +*
221.414 +* Solution of the system B * x = b can be obtained by solving the
221.415 +* following augmented system:
221.416 +*
221.417 +* ( B F^) ( x ) ( b )
221.418 +* ( ) ( ) = ( )
221.419 +* ( G^ H^) ( y ) ( 0 )
221.420 +*
221.421 +* which, using the main equality, can be written as follows:
221.422 +*
221.423 +* ( L0 0 ) ( U0 R ) ( x ) ( b )
221.424 +* P ( ) ( ) Q ( ) = ( )
221.425 +* ( S I ) ( 0 C ) ( y ) ( 0 )
221.426 +*
221.427 +* therefore,
221.428 +*
221.429 +* ( x ) ( U0 R )-1 ( L0 0 )-1 ( b )
221.430 +* ( ) = Q' ( ) ( ) P' ( )
221.431 +* ( y ) ( 0 C ) ( S I ) ( 0 )
221.432 +*
221.433 +* Thus, computing the solution includes the following steps:
221.434 +*
221.435 +* 1. Compute
221.436 +*
221.437 +* ( f ) ( b )
221.438 +* ( ) = P' ( )
221.439 +* ( g ) ( 0 )
221.440 +*
221.441 +* 2. Solve the system
221.442 +*
221.443 +* ( f1 ) ( L0 0 )-1 ( f ) ( L0 0 ) ( f1 ) ( f )
221.444 +* ( ) = ( ) ( ) => ( ) ( ) = ( )
221.445 +* ( g1 ) ( S I ) ( g ) ( S I ) ( g1 ) ( g )
221.446 +*
221.447 +* from which it follows that:
221.448 +*
221.449 +* { L0 * f1 = f f1 = inv(L0) * f
221.450 +* { =>
221.451 +* { S * f1 + g1 = g g1 = g - S * f1
221.452 +*
221.453 +* 3. Solve the system
221.454 +*
221.455 +* ( f2 ) ( U0 R )-1 ( f1 ) ( U0 R ) ( f2 ) ( f1 )
221.456 +* ( ) = ( ) ( ) => ( ) ( ) = ( )
221.457 +* ( g2 ) ( 0 C ) ( g1 ) ( 0 C ) ( g2 ) ( g1 )
221.458 +*
221.459 +* from which it follows that:
221.460 +*
221.461 +* { U0 * f2 + R * g2 = f1 f2 = inv(U0) * (f1 - R * g2)
221.462 +* { =>
221.463 +* { C * g2 = g1 g2 = inv(C) * g1
221.464 +*
221.465 +* 4. Compute
221.466 +*
221.467 +* ( x ) ( f2 )
221.468 +* ( ) = Q' ( )
221.469 +* ( y ) ( g2 ) */
221.470 +
221.471 +void lpf_ftran(LPF *lpf, double x[])
221.472 +{ int m0 = lpf->m0;
221.473 + int m = lpf->m;
221.474 + int n = lpf->n;
221.475 + int *P_col = lpf->P_col;
221.476 + int *Q_col = lpf->Q_col;
221.477 + double *fg = lpf->work1;
221.478 + double *f = fg;
221.479 + double *g = fg + m0;
221.480 + int i, ii;
221.481 +#if _GLPLPF_DEBUG
221.482 + double *b;
221.483 +#endif
221.484 + if (!lpf->valid)
221.485 + xfault("lpf_ftran: the factorization is not valid\n");
221.486 + xassert(0 <= m && m <= m0 + n);
221.487 +#if _GLPLPF_DEBUG
221.488 + /* save the right-hand side vector */
221.489 + b = xcalloc(1+m, sizeof(double));
221.490 + for (i = 1; i <= m; i++) b[i] = x[i];
221.491 +#endif
221.492 + /* (f g) := inv(P) * (b 0) */
221.493 + for (i = 1; i <= m0 + n; i++)
221.494 + fg[i] = ((ii = P_col[i]) <= m ? x[ii] : 0.0);
221.495 + /* f1 := inv(L0) * f */
221.496 + luf_f_solve(lpf->luf, 0, f);
221.497 + /* g1 := g - S * f1 */
221.498 + s_prod(lpf, g, -1.0, f);
221.499 + /* g2 := inv(C) * g1 */
221.500 + scf_solve_it(lpf->scf, 0, g);
221.501 + /* f2 := inv(U0) * (f1 - R * g2) */
221.502 + r_prod(lpf, f, -1.0, g);
221.503 + luf_v_solve(lpf->luf, 0, f);
221.504 + /* (x y) := inv(Q) * (f2 g2) */
221.505 + for (i = 1; i <= m; i++)
221.506 + x[i] = fg[Q_col[i]];
221.507 +#if _GLPLPF_DEBUG
221.508 + /* check relative error in solution */
221.509 + check_error(lpf, 0, x, b);
221.510 + xfree(b);
221.511 +#endif
221.512 + return;
221.513 +}
221.514 +
221.515 +/***********************************************************************
221.516 +* NAME
221.517 +*
221.518 +* lpf_btran - perform backward transformation (solve system B'*x = b)
221.519 +*
221.520 +* SYNOPSIS
221.521 +*
221.522 +* #include "glplpf.h"
221.523 +* void lpf_btran(LPF *lpf, double x[]);
221.524 +*
221.525 +* DESCRIPTION
221.526 +*
221.527 +* The routine lpf_btran performs backward transformation, i.e. solves
221.528 +* the system B'*x = b, where B' is a matrix transposed to the basis
221.529 +* matrix B, x is the vector of unknowns to be computed, b is the vector
221.530 +* of right-hand sides.
221.531 +*
221.532 +* On entry elements of the vector b should be stored in dense format
221.533 +* in locations x[1], ..., x[m], where m is the number of rows. On exit
221.534 +* the routine stores elements of the vector x in the same locations.
221.535 +*
221.536 +* BACKGROUND
221.537 +*
221.538 +* Solution of the system B' * x = b, where B' is a matrix transposed
221.539 +* to B, can be obtained by solving the following augmented system:
221.540 +*
221.541 +* ( B F^)T ( x ) ( b )
221.542 +* ( ) ( ) = ( )
221.543 +* ( G^ H^) ( y ) ( 0 )
221.544 +*
221.545 +* which, using the main equality, can be written as follows:
221.546 +*
221.547 +* T ( U0 R )T ( L0 0 )T T ( x ) ( b )
221.548 +* Q ( ) ( ) P ( ) = ( )
221.549 +* ( 0 C ) ( S I ) ( y ) ( 0 )
221.550 +*
221.551 +* or, equivalently, as follows:
221.552 +*
221.553 +* ( U'0 0 ) ( L'0 S') ( x ) ( b )
221.554 +* Q' ( ) ( ) P' ( ) = ( )
221.555 +* ( R' C') ( 0 I ) ( y ) ( 0 )
221.556 +*
221.557 +* therefore,
221.558 +*
221.559 +* ( x ) ( L'0 S')-1 ( U'0 0 )-1 ( b )
221.560 +* ( ) = P ( ) ( ) Q ( )
221.561 +* ( y ) ( 0 I ) ( R' C') ( 0 )
221.562 +*
221.563 +* Thus, computing the solution includes the following steps:
221.564 +*
221.565 +* 1. Compute
221.566 +*
221.567 +* ( f ) ( b )
221.568 +* ( ) = Q ( )
221.569 +* ( g ) ( 0 )
221.570 +*
221.571 +* 2. Solve the system
221.572 +*
221.573 +* ( f1 ) ( U'0 0 )-1 ( f ) ( U'0 0 ) ( f1 ) ( f )
221.574 +* ( ) = ( ) ( ) => ( ) ( ) = ( )
221.575 +* ( g1 ) ( R' C') ( g ) ( R' C') ( g1 ) ( g )
221.576 +*
221.577 +* from which it follows that:
221.578 +*
221.579 +* { U'0 * f1 = f f1 = inv(U'0) * f
221.580 +* { =>
221.581 +* { R' * f1 + C' * g1 = g g1 = inv(C') * (g - R' * f1)
221.582 +*
221.583 +* 3. Solve the system
221.584 +*
221.585 +* ( f2 ) ( L'0 S')-1 ( f1 ) ( L'0 S') ( f2 ) ( f1 )
221.586 +* ( ) = ( ) ( ) => ( ) ( ) = ( )
221.587 +* ( g2 ) ( 0 I ) ( g1 ) ( 0 I ) ( g2 ) ( g1 )
221.588 +*
221.589 +* from which it follows that:
221.590 +*
221.591 +* { L'0 * f2 + S' * g2 = f1
221.592 +* { => f2 = inv(L'0) * ( f1 - S' * g2)
221.593 +* { g2 = g1
221.594 +*
221.595 +* 4. Compute
221.596 +*
221.597 +* ( x ) ( f2 )
221.598 +* ( ) = P ( )
221.599 +* ( y ) ( g2 ) */
221.600 +
221.601 +void lpf_btran(LPF *lpf, double x[])
221.602 +{ int m0 = lpf->m0;
221.603 + int m = lpf->m;
221.604 + int n = lpf->n;
221.605 + int *P_row = lpf->P_row;
221.606 + int *Q_row = lpf->Q_row;
221.607 + double *fg = lpf->work1;
221.608 + double *f = fg;
221.609 + double *g = fg + m0;
221.610 + int i, ii;
221.611 +#if _GLPLPF_DEBUG
221.612 + double *b;
221.613 +#endif
221.614 + if (!lpf->valid)
221.615 + xfault("lpf_btran: the factorization is not valid\n");
221.616 + xassert(0 <= m && m <= m0 + n);
221.617 +#if _GLPLPF_DEBUG
221.618 + /* save the right-hand side vector */
221.619 + b = xcalloc(1+m, sizeof(double));
221.620 + for (i = 1; i <= m; i++) b[i] = x[i];
221.621 +#endif
221.622 + /* (f g) := Q * (b 0) */
221.623 + for (i = 1; i <= m0 + n; i++)
221.624 + fg[i] = ((ii = Q_row[i]) <= m ? x[ii] : 0.0);
221.625 + /* f1 := inv(U'0) * f */
221.626 + luf_v_solve(lpf->luf, 1, f);
221.627 + /* g1 := inv(C') * (g - R' * f1) */
221.628 + rt_prod(lpf, g, -1.0, f);
221.629 + scf_solve_it(lpf->scf, 1, g);
221.630 + /* g2 := g1 */
221.631 + g = g;
221.632 + /* f2 := inv(L'0) * (f1 - S' * g2) */
221.633 + st_prod(lpf, f, -1.0, g);
221.634 + luf_f_solve(lpf->luf, 1, f);
221.635 + /* (x y) := P * (f2 g2) */
221.636 + for (i = 1; i <= m; i++)
221.637 + x[i] = fg[P_row[i]];
221.638 +#if _GLPLPF_DEBUG
221.639 + /* check relative error in solution */
221.640 + check_error(lpf, 1, x, b);
221.641 + xfree(b);
221.642 +#endif
221.643 + return;
221.644 +}
221.645 +
221.646 +/***********************************************************************
221.647 +* The routine enlarge_sva enlarges the Sparse Vector Area to new_size
221.648 +* locations by reallocating the arrays v_ind and v_val. */
221.649 +
221.650 +static void enlarge_sva(LPF *lpf, int new_size)
221.651 +{ int v_size = lpf->v_size;
221.652 + int used = lpf->v_ptr - 1;
221.653 + int *v_ind = lpf->v_ind;
221.654 + double *v_val = lpf->v_val;
221.655 + xassert(v_size < new_size);
221.656 + while (v_size < new_size) v_size += v_size;
221.657 + lpf->v_size = v_size;
221.658 + lpf->v_ind = xcalloc(1+v_size, sizeof(int));
221.659 + lpf->v_val = xcalloc(1+v_size, sizeof(double));
221.660 + xassert(used >= 0);
221.661 + memcpy(&lpf->v_ind[1], &v_ind[1], used * sizeof(int));
221.662 + memcpy(&lpf->v_val[1], &v_val[1], used * sizeof(double));
221.663 + xfree(v_ind);
221.664 + xfree(v_val);
221.665 + return;
221.666 +}
221.667 +
221.668 +/***********************************************************************
221.669 +* NAME
221.670 +*
221.671 +* lpf_update_it - update LP basis factorization
221.672 +*
221.673 +* SYNOPSIS
221.674 +*
221.675 +* #include "glplpf.h"
221.676 +* int lpf_update_it(LPF *lpf, int j, int bh, int len, const int ind[],
221.677 +* const double val[]);
221.678 +*
221.679 +* DESCRIPTION
221.680 +*
221.681 +* The routine lpf_update_it updates the factorization of the basis
221.682 +* matrix B after replacing its j-th column by a new vector.
221.683 +*
221.684 +* The parameter j specifies the number of column of B, which has been
221.685 +* replaced, 1 <= j <= m, where m is the order of B.
221.686 +*
221.687 +* The parameter bh specifies the basis header entry for the new column
221.688 +* of B, which is the number of the new column in some original matrix.
221.689 +* This parameter is optional and can be specified as 0.
221.690 +*
221.691 +* Row indices and numerical values of non-zero elements of the new
221.692 +* column of B should be placed in locations ind[1], ..., ind[len] and
221.693 +* val[1], ..., val[len], resp., where len is the number of non-zeros
221.694 +* in the column. Neither zero nor duplicate elements are allowed.
221.695 +*
221.696 +* RETURNS
221.697 +*
221.698 +* 0 The factorization has been successfully updated.
221.699 +*
221.700 +* LPF_ESING
221.701 +* New basis B is singular within the working precision.
221.702 +*
221.703 +* LPF_ELIMIT
221.704 +* Maximal number of additional rows and columns has been reached.
221.705 +*
221.706 +* BACKGROUND
221.707 +*
221.708 +* Let j-th column of the current basis matrix B have to be replaced by
221.709 +* a new column a. This replacement is equivalent to removing the old
221.710 +* j-th column by fixing it at zero and introducing the new column as
221.711 +* follows:
221.712 +*
221.713 +* ( B F^| a )
221.714 +* ( B F^) ( | )
221.715 +* ( ) ---> ( G^ H^| 0 )
221.716 +* ( G^ H^) (-------+---)
221.717 +* ( e'j 0 | 0 )
221.718 +*
221.719 +* where ej is a unit vector with 1 in j-th position which used to fix
221.720 +* the old j-th column of B (at zero). Then using the main equality we
221.721 +* have:
221.722 +*
221.723 +* ( B F^| a ) ( B0 F | f )
221.724 +* ( | ) ( P 0 ) ( | ) ( Q 0 )
221.725 +* ( G^ H^| 0 ) = ( ) ( G H | g ) ( ) =
221.726 +* (-------+---) ( 0 1 ) (-------+---) ( 0 1 )
221.727 +* ( e'j 0 | 0 ) ( v' w'| 0 )
221.728 +*
221.729 +* [ ( B0 F )| ( f ) ] [ ( B0 F ) | ( f ) ]
221.730 +* [ P ( )| P ( ) ] ( Q 0 ) [ P ( ) Q| P ( ) ]
221.731 +* = [ ( G H )| ( g ) ] ( ) = [ ( G H ) | ( g ) ]
221.732 +* [------------+-------- ] ( 0 1 ) [-------------+---------]
221.733 +* [ ( v' w')| 0 ] [ ( v' w') Q| 0 ]
221.734 +*
221.735 +* where:
221.736 +*
221.737 +* ( a ) ( f ) ( f ) ( a )
221.738 +* ( ) = P ( ) => ( ) = P' * ( )
221.739 +* ( 0 ) ( g ) ( g ) ( 0 )
221.740 +*
221.741 +* ( ej ) ( v ) ( v ) ( ej )
221.742 +* ( e'j 0 ) = ( v' w' ) Q => ( ) = Q' ( ) => ( ) = Q ( )
221.743 +* ( 0 ) ( w ) ( w ) ( 0 )
221.744 +*
221.745 +* On the other hand:
221.746 +*
221.747 +* ( B0| F f )
221.748 +* ( P 0 ) (---+------) ( Q 0 ) ( B0 new F )
221.749 +* ( ) ( G | H g ) ( ) = new P ( ) new Q
221.750 +* ( 0 1 ) ( | ) ( 0 1 ) ( new G new H )
221.751 +* ( v'| w' 0 )
221.752 +*
221.753 +* where:
221.754 +* ( G ) ( H g )
221.755 +* new F = ( F f ), new G = ( ), new H = ( ),
221.756 +* ( v') ( w' 0 )
221.757 +*
221.758 +* ( P 0 ) ( Q 0 )
221.759 +* new P = ( ) , new Q = ( ) .
221.760 +* ( 0 1 ) ( 0 1 )
221.761 +*
221.762 +* The factorization structure for the new augmented matrix remains the
221.763 +* same, therefore:
221.764 +*
221.765 +* ( B0 new F ) ( L0 0 ) ( U0 new R )
221.766 +* new P ( ) new Q = ( ) ( )
221.767 +* ( new G new H ) ( new S I ) ( 0 new C )
221.768 +*
221.769 +* where:
221.770 +*
221.771 +* new F = L0 * new R =>
221.772 +*
221.773 +* new R = inv(L0) * new F = inv(L0) * (F f) = ( R inv(L0)*f )
221.774 +*
221.775 +* new G = new S * U0 =>
221.776 +*
221.777 +* ( G ) ( S )
221.778 +* new S = new G * inv(U0) = ( ) * inv(U0) = ( )
221.779 +* ( v') ( v'*inv(U0) )
221.780 +*
221.781 +* new H = new S * new R + new C =>
221.782 +*
221.783 +* new C = new H - new S * new R =
221.784 +*
221.785 +* ( H g ) ( S )
221.786 +* = ( ) - ( ) * ( R inv(L0)*f ) =
221.787 +* ( w' 0 ) ( v'*inv(U0) )
221.788 +*
221.789 +* ( H - S*R g - S*inv(L0)*f ) ( C x )
221.790 +* = ( ) = ( )
221.791 +* ( w'- v'*inv(U0)*R -v'*inv(U0)*inv(L0)*f) ( y' z )
221.792 +*
221.793 +* Note that new C is resulted by expanding old C with new column x,
221.794 +* row y', and diagonal element z, where:
221.795 +*
221.796 +* x = g - S * inv(L0) * f = g - S * (new column of R)
221.797 +*
221.798 +* y = w - R'* inv(U'0)* v = w - R'* (new row of S)
221.799 +*
221.800 +* z = - (new row of S) * (new column of R)
221.801 +*
221.802 +* Finally, to replace old B by new B we have to permute j-th and last
221.803 +* (just added) columns of the matrix
221.804 +*
221.805 +* ( B F^| a )
221.806 +* ( | )
221.807 +* ( G^ H^| 0 )
221.808 +* (-------+---)
221.809 +* ( e'j 0 | 0 )
221.810 +*
221.811 +* and to keep the main equality do the same for matrix Q. */
221.812 +
221.813 +int lpf_update_it(LPF *lpf, int j, int bh, int len, const int ind[],
221.814 + const double val[])
221.815 +{ int m0 = lpf->m0;
221.816 + int m = lpf->m;
221.817 +#if _GLPLPF_DEBUG
221.818 + double *B = lpf->B;
221.819 +#endif
221.820 + int n = lpf->n;
221.821 + int *R_ptr = lpf->R_ptr;
221.822 + int *R_len = lpf->R_len;
221.823 + int *S_ptr = lpf->S_ptr;
221.824 + int *S_len = lpf->S_len;
221.825 + int *P_row = lpf->P_row;
221.826 + int *P_col = lpf->P_col;
221.827 + int *Q_row = lpf->Q_row;
221.828 + int *Q_col = lpf->Q_col;
221.829 + int v_ptr = lpf->v_ptr;
221.830 + int *v_ind = lpf->v_ind;
221.831 + double *v_val = lpf->v_val;
221.832 + double *a = lpf->work2; /* new column */
221.833 + double *fg = lpf->work1, *f = fg, *g = fg + m0;
221.834 + double *vw = lpf->work2, *v = vw, *w = vw + m0;
221.835 + double *x = g, *y = w, z;
221.836 + int i, ii, k, ret;
221.837 + xassert(bh == bh);
221.838 + if (!lpf->valid)
221.839 + xfault("lpf_update_it: the factorization is not valid\n");
221.840 + if (!(1 <= j && j <= m))
221.841 + xfault("lpf_update_it: j = %d; column number out of range\n",
221.842 + j);
221.843 + xassert(0 <= m && m <= m0 + n);
221.844 + /* check if the basis factorization can be expanded */
221.845 + if (n == lpf->n_max)
221.846 + { lpf->valid = 0;
221.847 + ret = LPF_ELIMIT;
221.848 + goto done;
221.849 + }
221.850 + /* convert new j-th column of B to dense format */
221.851 + for (i = 1; i <= m; i++)
221.852 + a[i] = 0.0;
221.853 + for (k = 1; k <= len; k++)
221.854 + { i = ind[k];
221.855 + if (!(1 <= i && i <= m))
221.856 + xfault("lpf_update_it: ind[%d] = %d; row number out of rang"
221.857 + "e\n", k, i);
221.858 + if (a[i] != 0.0)
221.859 + xfault("lpf_update_it: ind[%d] = %d; duplicate row index no"
221.860 + "t allowed\n", k, i);
221.861 + if (val[k] == 0.0)
221.862 + xfault("lpf_update_it: val[%d] = %g; zero element not allow"
221.863 + "ed\n", k, val[k]);
221.864 + a[i] = val[k];
221.865 + }
221.866 +#if _GLPLPF_DEBUG
221.867 + /* change column in the basis matrix for debugging */
221.868 + for (i = 1; i <= m; i++)
221.869 + B[(i - 1) * m + j] = a[i];
221.870 +#endif
221.871 + /* (f g) := inv(P) * (a 0) */
221.872 + for (i = 1; i <= m0+n; i++)
221.873 + fg[i] = ((ii = P_col[i]) <= m ? a[ii] : 0.0);
221.874 + /* (v w) := Q * (ej 0) */
221.875 + for (i = 1; i <= m0+n; i++) vw[i] = 0.0;
221.876 + vw[Q_col[j]] = 1.0;
221.877 + /* f1 := inv(L0) * f (new column of R) */
221.878 + luf_f_solve(lpf->luf, 0, f);
221.879 + /* v1 := inv(U'0) * v (new row of S) */
221.880 + luf_v_solve(lpf->luf, 1, v);
221.881 + /* we need at most 2 * m0 available locations in the SVA to store
221.882 + new column of matrix R and new row of matrix S */
221.883 + if (lpf->v_size < v_ptr + m0 + m0)
221.884 + { enlarge_sva(lpf, v_ptr + m0 + m0);
221.885 + v_ind = lpf->v_ind;
221.886 + v_val = lpf->v_val;
221.887 + }
221.888 + /* store new column of R */
221.889 + R_ptr[n+1] = v_ptr;
221.890 + for (i = 1; i <= m0; i++)
221.891 + { if (f[i] != 0.0)
221.892 + v_ind[v_ptr] = i, v_val[v_ptr] = f[i], v_ptr++;
221.893 + }
221.894 + R_len[n+1] = v_ptr - lpf->v_ptr;
221.895 + lpf->v_ptr = v_ptr;
221.896 + /* store new row of S */
221.897 + S_ptr[n+1] = v_ptr;
221.898 + for (i = 1; i <= m0; i++)
221.899 + { if (v[i] != 0.0)
221.900 + v_ind[v_ptr] = i, v_val[v_ptr] = v[i], v_ptr++;
221.901 + }
221.902 + S_len[n+1] = v_ptr - lpf->v_ptr;
221.903 + lpf->v_ptr = v_ptr;
221.904 + /* x := g - S * f1 (new column of C) */
221.905 + s_prod(lpf, x, -1.0, f);
221.906 + /* y := w - R' * v1 (new row of C) */
221.907 + rt_prod(lpf, y, -1.0, v);
221.908 + /* z := - v1 * f1 (new diagonal element of C) */
221.909 + z = 0.0;
221.910 + for (i = 1; i <= m0; i++) z -= v[i] * f[i];
221.911 + /* update factorization of new matrix C */
221.912 + switch (scf_update_exp(lpf->scf, x, y, z))
221.913 + { case 0:
221.914 + break;
221.915 + case SCF_ESING:
221.916 + lpf->valid = 0;
221.917 + ret = LPF_ESING;
221.918 + goto done;
221.919 + case SCF_ELIMIT:
221.920 + xassert(lpf != lpf);
221.921 + default:
221.922 + xassert(lpf != lpf);
221.923 + }
221.924 + /* expand matrix P */
221.925 + P_row[m0+n+1] = P_col[m0+n+1] = m0+n+1;
221.926 + /* expand matrix Q */
221.927 + Q_row[m0+n+1] = Q_col[m0+n+1] = m0+n+1;
221.928 + /* permute j-th and last (just added) column of matrix Q */
221.929 + i = Q_col[j], ii = Q_col[m0+n+1];
221.930 + Q_row[i] = m0+n+1, Q_col[m0+n+1] = i;
221.931 + Q_row[ii] = j, Q_col[j] = ii;
221.932 + /* increase the number of additional rows and columns */
221.933 + lpf->n++;
221.934 + xassert(lpf->n <= lpf->n_max);
221.935 + /* the factorization has been successfully updated */
221.936 + ret = 0;
221.937 +done: /* return to the calling program */
221.938 + return ret;
221.939 +}
221.940 +
221.941 +/***********************************************************************
221.942 +* NAME
221.943 +*
221.944 +* lpf_delete_it - delete LP basis factorization
221.945 +*
221.946 +* SYNOPSIS
221.947 +*
221.948 +* #include "glplpf.h"
221.949 +* void lpf_delete_it(LPF *lpf)
221.950 +*
221.951 +* DESCRIPTION
221.952 +*
221.953 +* The routine lpf_delete_it deletes LP basis factorization specified
221.954 +* by the parameter lpf and frees all memory allocated to this program
221.955 +* object. */
221.956 +
221.957 +void lpf_delete_it(LPF *lpf)
221.958 +{ luf_delete_it(lpf->luf);
221.959 +#if _GLPLPF_DEBUG
221.960 + if (lpf->B != NULL) xfree(lpf->B);
221.961 +#else
221.962 + xassert(lpf->B == NULL);
221.963 +#endif
221.964 + if (lpf->R_ptr != NULL) xfree(lpf->R_ptr);
221.965 + if (lpf->R_len != NULL) xfree(lpf->R_len);
221.966 + if (lpf->S_ptr != NULL) xfree(lpf->S_ptr);
221.967 + if (lpf->S_len != NULL) xfree(lpf->S_len);
221.968 + if (lpf->scf != NULL) scf_delete_it(lpf->scf);
221.969 + if (lpf->P_row != NULL) xfree(lpf->P_row);
221.970 + if (lpf->P_col != NULL) xfree(lpf->P_col);
221.971 + if (lpf->Q_row != NULL) xfree(lpf->Q_row);
221.972 + if (lpf->Q_col != NULL) xfree(lpf->Q_col);
221.973 + if (lpf->v_ind != NULL) xfree(lpf->v_ind);
221.974 + if (lpf->v_val != NULL) xfree(lpf->v_val);
221.975 + if (lpf->work1 != NULL) xfree(lpf->work1);
221.976 + if (lpf->work2 != NULL) xfree(lpf->work2);
221.977 + xfree(lpf);
221.978 + return;
221.979 +}
221.980 +
221.981 +/* eof */
222.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
222.2 +++ b/src/glplpf.h Mon Dec 06 13:09:21 2010 +0100
222.3 @@ -0,0 +1,194 @@
222.4 +/* glplpf.h (LP basis factorization, Schur complement version) */
222.5 +
222.6 +/***********************************************************************
222.7 +* This code is part of GLPK (GNU Linear Programming Kit).
222.8 +*
222.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
222.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
222.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
222.12 +* E-mail: <mao@gnu.org>.
222.13 +*
222.14 +* GLPK is free software: you can redistribute it and/or modify it
222.15 +* under the terms of the GNU General Public License as published by
222.16 +* the Free Software Foundation, either version 3 of the License, or
222.17 +* (at your option) any later version.
222.18 +*
222.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
222.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
222.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
222.22 +* License for more details.
222.23 +*
222.24 +* You should have received a copy of the GNU General Public License
222.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
222.26 +***********************************************************************/
222.27 +
222.28 +#ifndef GLPLPF_H
222.29 +#define GLPLPF_H
222.30 +
222.31 +#include "glpscf.h"
222.32 +#include "glpluf.h"
222.33 +
222.34 +/***********************************************************************
222.35 +* The structure LPF defines the factorization of the basis mxm matrix
222.36 +* B, where m is the number of rows in corresponding problem instance.
222.37 +*
222.38 +* This factorization is the following septet:
222.39 +*
222.40 +* [B] = (L0, U0, R, S, C, P, Q), (1)
222.41 +*
222.42 +* and is based on the following main equality:
222.43 +*
222.44 +* ( B F^) ( B0 F ) ( L0 0 ) ( U0 R )
222.45 +* ( ) = P ( ) Q = P ( ) ( ) Q, (2)
222.46 +* ( G^ H^) ( G H ) ( S I ) ( 0 C )
222.47 +*
222.48 +* where:
222.49 +*
222.50 +* B is the current basis matrix (not stored);
222.51 +*
222.52 +* F^, G^, H^ are some additional matrices (not stored);
222.53 +*
222.54 +* B0 is some initial basis matrix (not stored);
222.55 +*
222.56 +* F, G, H are some additional matrices (not stored);
222.57 +*
222.58 +* P, Q are permutation matrices (stored in both row- and column-like
222.59 +* formats);
222.60 +*
222.61 +* L0, U0 are some matrices that defines a factorization of the initial
222.62 +* basis matrix B0 = L0 * U0 (stored in an invertable form);
222.63 +*
222.64 +* R is a matrix defined from L0 * R = F, so R = inv(L0) * F (stored in
222.65 +* a column-wise sparse format);
222.66 +*
222.67 +* S is a matrix defined from S * U0 = G, so S = G * inv(U0) (stored in
222.68 +* a row-wise sparse format);
222.69 +*
222.70 +* C is the Schur complement for matrix (B0 F G H). It is defined from
222.71 +* S * R + C = H, so C = H - S * R = H - G * inv(U0) * inv(L0) * F =
222.72 +* = H - G * inv(B0) * F. Matrix C is stored in an invertable form.
222.73 +*
222.74 +* REFERENCES
222.75 +*
222.76 +* 1. M.A.Saunders, "LUSOL: A basis package for constrained optimiza-
222.77 +* tion," SCCM, Stanford University, 2006.
222.78 +*
222.79 +* 2. M.A.Saunders, "Notes 5: Basis Updates," CME 318, Stanford Univer-
222.80 +* sity, Spring 2006.
222.81 +*
222.82 +* 3. M.A.Saunders, "Notes 6: LUSOL---a Basis Factorization Package,"
222.83 +* ibid. */
222.84 +
222.85 +typedef struct LPF LPF;
222.86 +
222.87 +struct LPF
222.88 +{ /* LP basis factorization */
222.89 + int valid;
222.90 + /* the factorization is valid only if this flag is set */
222.91 + /*--------------------------------------------------------------*/
222.92 + /* initial basis matrix B0 */
222.93 + int m0_max;
222.94 + /* maximal value of m0 (increased automatically, if necessary) */
222.95 + int m0;
222.96 + /* the order of B0 */
222.97 + LUF *luf;
222.98 + /* LU-factorization of B0 */
222.99 + /*--------------------------------------------------------------*/
222.100 + /* current basis matrix B */
222.101 + int m;
222.102 + /* the order of B */
222.103 + double *B; /* double B[1+m*m]; */
222.104 + /* B in dense format stored by rows and used only for debugging;
222.105 + normally this array is not allocated */
222.106 + /*--------------------------------------------------------------*/
222.107 + /* augmented matrix (B0 F G H) of the order m0+n */
222.108 + int n_max;
222.109 + /* maximal number of additional rows and columns */
222.110 + int n;
222.111 + /* current number of additional rows and columns */
222.112 + /*--------------------------------------------------------------*/
222.113 + /* m0xn matrix R in column-wise format */
222.114 + int *R_ptr; /* int R_ptr[1+n_max]; */
222.115 + /* R_ptr[j], 1 <= j <= n, is a pointer to j-th column */
222.116 + int *R_len; /* int R_len[1+n_max]; */
222.117 + /* R_len[j], 1 <= j <= n, is the length of j-th column */
222.118 + /*--------------------------------------------------------------*/
222.119 + /* nxm0 matrix S in row-wise format */
222.120 + int *S_ptr; /* int S_ptr[1+n_max]; */
222.121 + /* S_ptr[i], 1 <= i <= n, is a pointer to i-th row */
222.122 + int *S_len; /* int S_len[1+n_max]; */
222.123 + /* S_len[i], 1 <= i <= n, is the length of i-th row */
222.124 + /*--------------------------------------------------------------*/
222.125 + /* Schur complement C of the order n */
222.126 + SCF *scf; /* SCF scf[1:n_max]; */
222.127 + /* factorization of the Schur complement */
222.128 + /*--------------------------------------------------------------*/
222.129 + /* matrix P of the order m0+n */
222.130 + int *P_row; /* int P_row[1+m0_max+n_max]; */
222.131 + /* P_row[i] = j means that P[i,j] = 1 */
222.132 + int *P_col; /* int P_col[1+m0_max+n_max]; */
222.133 + /* P_col[j] = i means that P[i,j] = 1 */
222.134 + /*--------------------------------------------------------------*/
222.135 + /* matrix Q of the order m0+n */
222.136 + int *Q_row; /* int Q_row[1+m0_max+n_max]; */
222.137 + /* Q_row[i] = j means that Q[i,j] = 1 */
222.138 + int *Q_col; /* int Q_col[1+m0_max+n_max]; */
222.139 + /* Q_col[j] = i means that Q[i,j] = 1 */
222.140 + /*--------------------------------------------------------------*/
222.141 + /* Sparse Vector Area (SVA) is a set of locations intended to
222.142 + store sparse vectors which represent columns of matrix R and
222.143 + rows of matrix S; each location is a doublet (ind, val), where
222.144 + ind is an index, val is a numerical value of a sparse vector
222.145 + element; in the whole each sparse vector is a set of adjacent
222.146 + locations defined by a pointer to its first element and its
222.147 + length, i.e. the number of its elements */
222.148 + int v_size;
222.149 + /* the SVA size, in locations; locations are numbered by integers
222.150 + 1, 2, ..., v_size, and location 0 is not used */
222.151 + int v_ptr;
222.152 + /* pointer to the first available location */
222.153 + int *v_ind; /* int v_ind[1+v_size]; */
222.154 + /* v_ind[k], 1 <= k <= v_size, is the index field of location k */
222.155 + double *v_val; /* double v_val[1+v_size]; */
222.156 + /* v_val[k], 1 <= k <= v_size, is the value field of location k */
222.157 + /*--------------------------------------------------------------*/
222.158 + double *work1; /* double work1[1+m0+n_max]; */
222.159 + /* working array */
222.160 + double *work2; /* double work2[1+m0+n_max]; */
222.161 + /* working array */
222.162 +};
222.163 +
222.164 +/* return codes: */
222.165 +#define LPF_ESING 1 /* singular matrix */
222.166 +#define LPF_ECOND 2 /* ill-conditioned matrix */
222.167 +#define LPF_ELIMIT 3 /* update limit reached */
222.168 +
222.169 +#define lpf_create_it _glp_lpf_create_it
222.170 +LPF *lpf_create_it(void);
222.171 +/* create LP basis factorization */
222.172 +
222.173 +#define lpf_factorize _glp_lpf_factorize
222.174 +int lpf_factorize(LPF *lpf, int m, const int bh[], int (*col)
222.175 + (void *info, int j, int ind[], double val[]), void *info);
222.176 +/* compute LP basis factorization */
222.177 +
222.178 +#define lpf_ftran _glp_lpf_ftran
222.179 +void lpf_ftran(LPF *lpf, double x[]);
222.180 +/* perform forward transformation (solve system B*x = b) */
222.181 +
222.182 +#define lpf_btran _glp_lpf_btran
222.183 +void lpf_btran(LPF *lpf, double x[]);
222.184 +/* perform backward transformation (solve system B'*x = b) */
222.185 +
222.186 +#define lpf_update_it _glp_lpf_update_it
222.187 +int lpf_update_it(LPF *lpf, int j, int bh, int len, const int ind[],
222.188 + const double val[]);
222.189 +/* update LP basis factorization */
222.190 +
222.191 +#define lpf_delete_it _glp_lpf_delete_it
222.192 +void lpf_delete_it(LPF *lpf);
222.193 +/* delete LP basis factorization */
222.194 +
222.195 +#endif
222.196 +
222.197 +/* eof */
223.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
223.2 +++ b/src/glplpx01.c Mon Dec 06 13:09:21 2010 +0100
223.3 @@ -0,0 +1,1542 @@
223.4 +/* glplpx01.c (obsolete API routines) */
223.5 +
223.6 +/***********************************************************************
223.7 +* This code is part of GLPK (GNU Linear Programming Kit).
223.8 +*
223.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
223.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
223.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
223.12 +* E-mail: <mao@gnu.org>.
223.13 +*
223.14 +* GLPK is free software: you can redistribute it and/or modify it
223.15 +* under the terms of the GNU General Public License as published by
223.16 +* the Free Software Foundation, either version 3 of the License, or
223.17 +* (at your option) any later version.
223.18 +*
223.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
223.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
223.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
223.22 +* License for more details.
223.23 +*
223.24 +* You should have received a copy of the GNU General Public License
223.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
223.26 +***********************************************************************/
223.27 +
223.28 +#include "glpapi.h"
223.29 +
223.30 +struct LPXCPS
223.31 +{ /* control parameters and statistics */
223.32 + int msg_lev;
223.33 + /* level of messages output by the solver:
223.34 + 0 - no output
223.35 + 1 - error messages only
223.36 + 2 - normal output
223.37 + 3 - full output (includes informational messages) */
223.38 + int scale;
223.39 + /* scaling option:
223.40 + 0 - no scaling
223.41 + 1 - equilibration scaling
223.42 + 2 - geometric mean scaling
223.43 + 3 - geometric mean scaling, then equilibration scaling */
223.44 + int dual;
223.45 + /* dual simplex option:
223.46 + 0 - use primal simplex
223.47 + 1 - use dual simplex */
223.48 + int price;
223.49 + /* pricing option (for both primal and dual simplex):
223.50 + 0 - textbook pricing
223.51 + 1 - steepest edge pricing */
223.52 + double relax;
223.53 + /* relaxation parameter used in the ratio test; if it is zero,
223.54 + the textbook ratio test is used; if it is non-zero (should be
223.55 + positive), Harris' two-pass ratio test is used; in the latter
223.56 + case on the first pass basic variables (in the case of primal
223.57 + simplex) or reduced costs of non-basic variables (in the case
223.58 + of dual simplex) are allowed to slightly violate their bounds,
223.59 + but not more than (relax * tol_bnd) or (relax * tol_dj) (thus,
223.60 + relax is a percentage of tol_bnd or tol_dj) */
223.61 + double tol_bnd;
223.62 + /* relative tolerance used to check if the current basic solution
223.63 + is primal feasible */
223.64 + double tol_dj;
223.65 + /* absolute tolerance used to check if the current basic solution
223.66 + is dual feasible */
223.67 + double tol_piv;
223.68 + /* relative tolerance used to choose eligible pivotal elements of
223.69 + the simplex table in the ratio test */
223.70 + int round;
223.71 + /* solution rounding option:
223.72 + 0 - report all computed values and reduced costs "as is"
223.73 + 1 - if possible (allowed by the tolerances), replace computed
223.74 + values and reduced costs which are close to zero by exact
223.75 + zeros */
223.76 + double obj_ll;
223.77 + /* lower limit of the objective function; if on the phase II the
223.78 + objective function reaches this limit and continues decreasing,
223.79 + the solver stops the search */
223.80 + double obj_ul;
223.81 + /* upper limit of the objective function; if on the phase II the
223.82 + objective function reaches this limit and continues increasing,
223.83 + the solver stops the search */
223.84 + int it_lim;
223.85 + /* simplex iterations limit; if this value is positive, it is
223.86 + decreased by one each time when one simplex iteration has been
223.87 + performed, and reaching zero value signals the solver to stop
223.88 + the search; negative value means no iterations limit */
223.89 + double tm_lim;
223.90 + /* searching time limit, in seconds; if this value is positive,
223.91 + it is decreased each time when one simplex iteration has been
223.92 + performed by the amount of time spent for the iteration, and
223.93 + reaching zero value signals the solver to stop the search;
223.94 + negative value means no time limit */
223.95 + int out_frq;
223.96 + /* output frequency, in iterations; this parameter specifies how
223.97 + frequently the solver sends information about the solution to
223.98 + the standard output */
223.99 + double out_dly;
223.100 + /* output delay, in seconds; this parameter specifies how long
223.101 + the solver should delay sending information about the solution
223.102 + to the standard output; zero value means no delay */
223.103 + int branch; /* MIP */
223.104 + /* branching heuristic:
223.105 + 0 - branch on first variable
223.106 + 1 - branch on last variable
223.107 + 2 - branch using heuristic by Driebeck and Tomlin
223.108 + 3 - branch on most fractional variable */
223.109 + int btrack; /* MIP */
223.110 + /* backtracking heuristic:
223.111 + 0 - select most recent node (depth first search)
223.112 + 1 - select earliest node (breadth first search)
223.113 + 2 - select node using the best projection heuristic
223.114 + 3 - select node with best local bound */
223.115 + double tol_int; /* MIP */
223.116 + /* absolute tolerance used to check if the current basic solution
223.117 + is integer feasible */
223.118 + double tol_obj; /* MIP */
223.119 + /* relative tolerance used to check if the value of the objective
223.120 + function is not better than in the best known integer feasible
223.121 + solution */
223.122 + int mps_info; /* lpx_write_mps */
223.123 + /* if this flag is set, the routine lpx_write_mps outputs several
223.124 + comment cards that contains some information about the problem;
223.125 + otherwise the routine outputs no comment cards */
223.126 + int mps_obj; /* lpx_write_mps */
223.127 + /* this parameter tells the routine lpx_write_mps how to output
223.128 + the objective function row:
223.129 + 0 - never output objective function row
223.130 + 1 - always output objective function row
223.131 + 2 - output objective function row if and only if the problem
223.132 + has no free rows */
223.133 + int mps_orig; /* lpx_write_mps */
223.134 + /* if this flag is set, the routine lpx_write_mps uses original
223.135 + row and column symbolic names; otherwise the routine generates
223.136 + plain names using ordinal numbers of rows and columns */
223.137 + int mps_wide; /* lpx_write_mps */
223.138 + /* if this flag is set, the routine lpx_write_mps uses all data
223.139 + fields; otherwise the routine keeps fields 5 and 6 empty */
223.140 + int mps_free; /* lpx_write_mps */
223.141 + /* if this flag is set, the routine lpx_write_mps omits column
223.142 + and vector names everytime if possible (free style); otherwise
223.143 + the routine never omits these names (pedantic style) */
223.144 + int mps_skip; /* lpx_write_mps */
223.145 + /* if this flag is set, the routine lpx_write_mps skips empty
223.146 + columns (i.e. which has no constraint coefficients); otherwise
223.147 + the routine outputs all columns */
223.148 + int lpt_orig; /* lpx_write_lpt */
223.149 + /* if this flag is set, the routine lpx_write_lpt uses original
223.150 + row and column symbolic names; otherwise the routine generates
223.151 + plain names using ordinal numbers of rows and columns */
223.152 + int presol; /* lpx_simplex */
223.153 + /* LP presolver option:
223.154 + 0 - do not use LP presolver
223.155 + 1 - use LP presolver */
223.156 + int binarize; /* lpx_intopt */
223.157 + /* if this flag is set, the routine lpx_intopt replaces integer
223.158 + columns by binary ones */
223.159 + int use_cuts; /* lpx_intopt */
223.160 + /* if this flag is set, the routine lpx_intopt tries generating
223.161 + cutting planes:
223.162 + LPX_C_COVER - mixed cover cuts
223.163 + LPX_C_CLIQUE - clique cuts
223.164 + LPX_C_GOMORY - Gomory's mixed integer cuts
223.165 + LPX_C_ALL - all cuts */
223.166 + double mip_gap; /* MIP */
223.167 + /* relative MIP gap tolerance */
223.168 +};
223.169 +
223.170 +LPX *lpx_create_prob(void)
223.171 +{ /* create problem object */
223.172 + return glp_create_prob();
223.173 +}
223.174 +
223.175 +void lpx_set_prob_name(LPX *lp, const char *name)
223.176 +{ /* assign (change) problem name */
223.177 + glp_set_prob_name(lp, name);
223.178 + return;
223.179 +}
223.180 +
223.181 +void lpx_set_obj_name(LPX *lp, const char *name)
223.182 +{ /* assign (change) objective function name */
223.183 + glp_set_obj_name(lp, name);
223.184 + return;
223.185 +}
223.186 +
223.187 +void lpx_set_obj_dir(LPX *lp, int dir)
223.188 +{ /* set (change) optimization direction flag */
223.189 + glp_set_obj_dir(lp, dir - LPX_MIN + GLP_MIN);
223.190 + return;
223.191 +}
223.192 +
223.193 +int lpx_add_rows(LPX *lp, int nrs)
223.194 +{ /* add new rows to problem object */
223.195 + return glp_add_rows(lp, nrs);
223.196 +}
223.197 +
223.198 +int lpx_add_cols(LPX *lp, int ncs)
223.199 +{ /* add new columns to problem object */
223.200 + return glp_add_cols(lp, ncs);
223.201 +}
223.202 +
223.203 +void lpx_set_row_name(LPX *lp, int i, const char *name)
223.204 +{ /* assign (change) row name */
223.205 + glp_set_row_name(lp, i, name);
223.206 + return;
223.207 +}
223.208 +
223.209 +void lpx_set_col_name(LPX *lp, int j, const char *name)
223.210 +{ /* assign (change) column name */
223.211 + glp_set_col_name(lp, j, name);
223.212 + return;
223.213 +}
223.214 +
223.215 +void lpx_set_row_bnds(LPX *lp, int i, int type, double lb, double ub)
223.216 +{ /* set (change) row bounds */
223.217 + glp_set_row_bnds(lp, i, type - LPX_FR + GLP_FR, lb, ub);
223.218 + return;
223.219 +}
223.220 +
223.221 +void lpx_set_col_bnds(LPX *lp, int j, int type, double lb, double ub)
223.222 +{ /* set (change) column bounds */
223.223 + glp_set_col_bnds(lp, j, type - LPX_FR + GLP_FR, lb, ub);
223.224 + return;
223.225 +}
223.226 +
223.227 +void lpx_set_obj_coef(glp_prob *lp, int j, double coef)
223.228 +{ /* set (change) obj. coefficient or constant term */
223.229 + glp_set_obj_coef(lp, j, coef);
223.230 + return;
223.231 +}
223.232 +
223.233 +void lpx_set_mat_row(LPX *lp, int i, int len, const int ind[],
223.234 + const double val[])
223.235 +{ /* set (replace) row of the constraint matrix */
223.236 + glp_set_mat_row(lp, i, len, ind, val);
223.237 + return;
223.238 +}
223.239 +
223.240 +void lpx_set_mat_col(LPX *lp, int j, int len, const int ind[],
223.241 + const double val[])
223.242 +{ /* set (replace) column of the constraint matrix */
223.243 + glp_set_mat_col(lp, j, len, ind, val);
223.244 + return;
223.245 +}
223.246 +
223.247 +void lpx_load_matrix(LPX *lp, int ne, const int ia[], const int ja[],
223.248 + const double ar[])
223.249 +{ /* load (replace) the whole constraint matrix */
223.250 + glp_load_matrix(lp, ne, ia, ja, ar);
223.251 + return;
223.252 +}
223.253 +
223.254 +void lpx_del_rows(LPX *lp, int nrs, const int num[])
223.255 +{ /* delete specified rows from problem object */
223.256 + glp_del_rows(lp, nrs, num);
223.257 + return;
223.258 +}
223.259 +
223.260 +void lpx_del_cols(LPX *lp, int ncs, const int num[])
223.261 +{ /* delete specified columns from problem object */
223.262 + glp_del_cols(lp, ncs, num);
223.263 + return;
223.264 +}
223.265 +
223.266 +void lpx_delete_prob(LPX *lp)
223.267 +{ /* delete problem object */
223.268 + glp_delete_prob(lp);
223.269 + return;
223.270 +}
223.271 +
223.272 +const char *lpx_get_prob_name(LPX *lp)
223.273 +{ /* retrieve problem name */
223.274 + return glp_get_prob_name(lp);
223.275 +}
223.276 +
223.277 +const char *lpx_get_obj_name(LPX *lp)
223.278 +{ /* retrieve objective function name */
223.279 + return glp_get_obj_name(lp);
223.280 +}
223.281 +
223.282 +int lpx_get_obj_dir(LPX *lp)
223.283 +{ /* retrieve optimization direction flag */
223.284 + return glp_get_obj_dir(lp) - GLP_MIN + LPX_MIN;
223.285 +}
223.286 +
223.287 +int lpx_get_num_rows(LPX *lp)
223.288 +{ /* retrieve number of rows */
223.289 + return glp_get_num_rows(lp);
223.290 +}
223.291 +
223.292 +int lpx_get_num_cols(LPX *lp)
223.293 +{ /* retrieve number of columns */
223.294 + return glp_get_num_cols(lp);
223.295 +}
223.296 +
223.297 +const char *lpx_get_row_name(LPX *lp, int i)
223.298 +{ /* retrieve row name */
223.299 + return glp_get_row_name(lp, i);
223.300 +}
223.301 +
223.302 +const char *lpx_get_col_name(LPX *lp, int j)
223.303 +{ /* retrieve column name */
223.304 + return glp_get_col_name(lp, j);
223.305 +}
223.306 +
223.307 +int lpx_get_row_type(LPX *lp, int i)
223.308 +{ /* retrieve row type */
223.309 + return glp_get_row_type(lp, i) - GLP_FR + LPX_FR;
223.310 +}
223.311 +
223.312 +double lpx_get_row_lb(glp_prob *lp, int i)
223.313 +{ /* retrieve row lower bound */
223.314 + double lb;
223.315 + lb = glp_get_row_lb(lp, i);
223.316 + if (lb == -DBL_MAX) lb = 0.0;
223.317 + return lb;
223.318 +}
223.319 +
223.320 +double lpx_get_row_ub(glp_prob *lp, int i)
223.321 +{ /* retrieve row upper bound */
223.322 + double ub;
223.323 + ub = glp_get_row_ub(lp, i);
223.324 + if (ub == +DBL_MAX) ub = 0.0;
223.325 + return ub;
223.326 +}
223.327 +
223.328 +void lpx_get_row_bnds(glp_prob *lp, int i, int *typx, double *lb,
223.329 + double *ub)
223.330 +{ /* retrieve row bounds */
223.331 + if (typx != NULL) *typx = lpx_get_row_type(lp, i);
223.332 + if (lb != NULL) *lb = lpx_get_row_lb(lp, i);
223.333 + if (ub != NULL) *ub = lpx_get_row_ub(lp, i);
223.334 + return;
223.335 +}
223.336 +
223.337 +int lpx_get_col_type(LPX *lp, int j)
223.338 +{ /* retrieve column type */
223.339 + return glp_get_col_type(lp, j) - GLP_FR + LPX_FR;
223.340 +}
223.341 +
223.342 +double lpx_get_col_lb(glp_prob *lp, int j)
223.343 +{ /* retrieve column lower bound */
223.344 + double lb;
223.345 + lb = glp_get_col_lb(lp, j);
223.346 + if (lb == -DBL_MAX) lb = 0.0;
223.347 + return lb;
223.348 +}
223.349 +
223.350 +double lpx_get_col_ub(glp_prob *lp, int j)
223.351 +{ /* retrieve column upper bound */
223.352 + double ub;
223.353 + ub = glp_get_col_ub(lp, j);
223.354 + if (ub == +DBL_MAX) ub = 0.0;
223.355 + return ub;
223.356 +}
223.357 +
223.358 +void lpx_get_col_bnds(glp_prob *lp, int j, int *typx, double *lb,
223.359 + double *ub)
223.360 +{ /* retrieve column bounds */
223.361 + if (typx != NULL) *typx = lpx_get_col_type(lp, j);
223.362 + if (lb != NULL) *lb = lpx_get_col_lb(lp, j);
223.363 + if (ub != NULL) *ub = lpx_get_col_ub(lp, j);
223.364 + return;
223.365 +}
223.366 +
223.367 +double lpx_get_obj_coef(LPX *lp, int j)
223.368 +{ /* retrieve obj. coefficient or constant term */
223.369 + return glp_get_obj_coef(lp, j);
223.370 +}
223.371 +
223.372 +int lpx_get_num_nz(LPX *lp)
223.373 +{ /* retrieve number of constraint coefficients */
223.374 + return glp_get_num_nz(lp);
223.375 +}
223.376 +
223.377 +int lpx_get_mat_row(LPX *lp, int i, int ind[], double val[])
223.378 +{ /* retrieve row of the constraint matrix */
223.379 + return glp_get_mat_row(lp, i, ind, val);
223.380 +}
223.381 +
223.382 +int lpx_get_mat_col(LPX *lp, int j, int ind[], double val[])
223.383 +{ /* retrieve column of the constraint matrix */
223.384 + return glp_get_mat_col(lp, j, ind, val);
223.385 +}
223.386 +
223.387 +void lpx_create_index(LPX *lp)
223.388 +{ /* create the name index */
223.389 + glp_create_index(lp);
223.390 + return;
223.391 +}
223.392 +
223.393 +int lpx_find_row(LPX *lp, const char *name)
223.394 +{ /* find row by its name */
223.395 + return glp_find_row(lp, name);
223.396 +}
223.397 +
223.398 +int lpx_find_col(LPX *lp, const char *name)
223.399 +{ /* find column by its name */
223.400 + return glp_find_col(lp, name);
223.401 +}
223.402 +
223.403 +void lpx_delete_index(LPX *lp)
223.404 +{ /* delete the name index */
223.405 + glp_delete_index(lp);
223.406 + return;
223.407 +}
223.408 +
223.409 +void lpx_scale_prob(LPX *lp)
223.410 +{ /* scale problem data */
223.411 + switch (lpx_get_int_parm(lp, LPX_K_SCALE))
223.412 + { case 0:
223.413 + /* no scaling */
223.414 + glp_unscale_prob(lp);
223.415 + break;
223.416 + case 1:
223.417 + /* equilibration scaling */
223.418 + glp_scale_prob(lp, GLP_SF_EQ);
223.419 + break;
223.420 + case 2:
223.421 + /* geometric mean scaling */
223.422 + glp_scale_prob(lp, GLP_SF_GM);
223.423 + break;
223.424 + case 3:
223.425 + /* geometric mean scaling, then equilibration scaling */
223.426 + glp_scale_prob(lp, GLP_SF_GM | GLP_SF_EQ);
223.427 + break;
223.428 + default:
223.429 + xassert(lp != lp);
223.430 + }
223.431 + return;
223.432 +}
223.433 +
223.434 +void lpx_unscale_prob(LPX *lp)
223.435 +{ /* unscale problem data */
223.436 + glp_unscale_prob(lp);
223.437 + return;
223.438 +}
223.439 +
223.440 +void lpx_set_row_stat(LPX *lp, int i, int stat)
223.441 +{ /* set (change) row status */
223.442 + glp_set_row_stat(lp, i, stat - LPX_BS + GLP_BS);
223.443 + return;
223.444 +}
223.445 +
223.446 +void lpx_set_col_stat(LPX *lp, int j, int stat)
223.447 +{ /* set (change) column status */
223.448 + glp_set_col_stat(lp, j, stat - LPX_BS + GLP_BS);
223.449 + return;
223.450 +}
223.451 +
223.452 +void lpx_std_basis(LPX *lp)
223.453 +{ /* construct standard initial LP basis */
223.454 + glp_std_basis(lp);
223.455 + return;
223.456 +}
223.457 +
223.458 +void lpx_adv_basis(LPX *lp)
223.459 +{ /* construct advanced initial LP basis */
223.460 + glp_adv_basis(lp, 0);
223.461 + return;
223.462 +}
223.463 +
223.464 +void lpx_cpx_basis(LPX *lp)
223.465 +{ /* construct Bixby's initial LP basis */
223.466 + glp_cpx_basis(lp);
223.467 + return;
223.468 +}
223.469 +
223.470 +static void fill_smcp(LPX *lp, glp_smcp *parm)
223.471 +{ glp_init_smcp(parm);
223.472 + switch (lpx_get_int_parm(lp, LPX_K_MSGLEV))
223.473 + { case 0: parm->msg_lev = GLP_MSG_OFF; break;
223.474 + case 1: parm->msg_lev = GLP_MSG_ERR; break;
223.475 + case 2: parm->msg_lev = GLP_MSG_ON; break;
223.476 + case 3: parm->msg_lev = GLP_MSG_ALL; break;
223.477 + default: xassert(lp != lp);
223.478 + }
223.479 + switch (lpx_get_int_parm(lp, LPX_K_DUAL))
223.480 + { case 0: parm->meth = GLP_PRIMAL; break;
223.481 + case 1: parm->meth = GLP_DUAL; break;
223.482 + default: xassert(lp != lp);
223.483 + }
223.484 + switch (lpx_get_int_parm(lp, LPX_K_PRICE))
223.485 + { case 0: parm->pricing = GLP_PT_STD; break;
223.486 + case 1: parm->pricing = GLP_PT_PSE; break;
223.487 + default: xassert(lp != lp);
223.488 + }
223.489 + if (lpx_get_real_parm(lp, LPX_K_RELAX) == 0.0)
223.490 + parm->r_test = GLP_RT_STD;
223.491 + else
223.492 + parm->r_test = GLP_RT_HAR;
223.493 + parm->tol_bnd = lpx_get_real_parm(lp, LPX_K_TOLBND);
223.494 + parm->tol_dj = lpx_get_real_parm(lp, LPX_K_TOLDJ);
223.495 + parm->tol_piv = lpx_get_real_parm(lp, LPX_K_TOLPIV);
223.496 + parm->obj_ll = lpx_get_real_parm(lp, LPX_K_OBJLL);
223.497 + parm->obj_ul = lpx_get_real_parm(lp, LPX_K_OBJUL);
223.498 + if (lpx_get_int_parm(lp, LPX_K_ITLIM) < 0)
223.499 + parm->it_lim = INT_MAX;
223.500 + else
223.501 + parm->it_lim = lpx_get_int_parm(lp, LPX_K_ITLIM);
223.502 + if (lpx_get_real_parm(lp, LPX_K_TMLIM) < 0.0)
223.503 + parm->tm_lim = INT_MAX;
223.504 + else
223.505 + parm->tm_lim =
223.506 + (int)(1000.0 * lpx_get_real_parm(lp, LPX_K_TMLIM));
223.507 + parm->out_frq = lpx_get_int_parm(lp, LPX_K_OUTFRQ);
223.508 + parm->out_dly =
223.509 + (int)(1000.0 * lpx_get_real_parm(lp, LPX_K_OUTDLY));
223.510 + switch (lpx_get_int_parm(lp, LPX_K_PRESOL))
223.511 + { case 0: parm->presolve = GLP_OFF; break;
223.512 + case 1: parm->presolve = GLP_ON; break;
223.513 + default: xassert(lp != lp);
223.514 + }
223.515 + return;
223.516 +}
223.517 +
223.518 +int lpx_simplex(LPX *lp)
223.519 +{ /* easy-to-use driver to the simplex method */
223.520 + glp_smcp parm;
223.521 + int ret;
223.522 + fill_smcp(lp, &parm);
223.523 + ret = glp_simplex(lp, &parm);
223.524 + switch (ret)
223.525 + { case 0: ret = LPX_E_OK; break;
223.526 + case GLP_EBADB:
223.527 + case GLP_ESING:
223.528 + case GLP_ECOND:
223.529 + case GLP_EBOUND: ret = LPX_E_FAULT; break;
223.530 + case GLP_EFAIL: ret = LPX_E_SING; break;
223.531 + case GLP_EOBJLL: ret = LPX_E_OBJLL; break;
223.532 + case GLP_EOBJUL: ret = LPX_E_OBJUL; break;
223.533 + case GLP_EITLIM: ret = LPX_E_ITLIM; break;
223.534 + case GLP_ETMLIM: ret = LPX_E_TMLIM; break;
223.535 + case GLP_ENOPFS: ret = LPX_E_NOPFS; break;
223.536 + case GLP_ENODFS: ret = LPX_E_NODFS; break;
223.537 + default: xassert(ret != ret);
223.538 + }
223.539 + return ret;
223.540 +}
223.541 +
223.542 +int lpx_exact(LPX *lp)
223.543 +{ /* easy-to-use driver to the exact simplex method */
223.544 + glp_smcp parm;
223.545 + int ret;
223.546 + fill_smcp(lp, &parm);
223.547 + ret = glp_exact(lp, &parm);
223.548 + switch (ret)
223.549 + { case 0: ret = LPX_E_OK; break;
223.550 + case GLP_EBADB:
223.551 + case GLP_ESING:
223.552 + case GLP_EBOUND:
223.553 + case GLP_EFAIL: ret = LPX_E_FAULT; break;
223.554 + case GLP_EITLIM: ret = LPX_E_ITLIM; break;
223.555 + case GLP_ETMLIM: ret = LPX_E_TMLIM; break;
223.556 + default: xassert(ret != ret);
223.557 + }
223.558 + return ret;
223.559 +}
223.560 +
223.561 +int lpx_get_status(glp_prob *lp)
223.562 +{ /* retrieve generic status of basic solution */
223.563 + int status;
223.564 + switch (glp_get_status(lp))
223.565 + { case GLP_OPT: status = LPX_OPT; break;
223.566 + case GLP_FEAS: status = LPX_FEAS; break;
223.567 + case GLP_INFEAS: status = LPX_INFEAS; break;
223.568 + case GLP_NOFEAS: status = LPX_NOFEAS; break;
223.569 + case GLP_UNBND: status = LPX_UNBND; break;
223.570 + case GLP_UNDEF: status = LPX_UNDEF; break;
223.571 + default: xassert(lp != lp);
223.572 + }
223.573 + return status;
223.574 +}
223.575 +
223.576 +int lpx_get_prim_stat(glp_prob *lp)
223.577 +{ /* retrieve status of primal basic solution */
223.578 + return glp_get_prim_stat(lp) - GLP_UNDEF + LPX_P_UNDEF;
223.579 +}
223.580 +
223.581 +int lpx_get_dual_stat(glp_prob *lp)
223.582 +{ /* retrieve status of dual basic solution */
223.583 + return glp_get_dual_stat(lp) - GLP_UNDEF + LPX_D_UNDEF;
223.584 +}
223.585 +
223.586 +double lpx_get_obj_val(LPX *lp)
223.587 +{ /* retrieve objective value (basic solution) */
223.588 + return glp_get_obj_val(lp);
223.589 +}
223.590 +
223.591 +int lpx_get_row_stat(LPX *lp, int i)
223.592 +{ /* retrieve row status (basic solution) */
223.593 + return glp_get_row_stat(lp, i) - GLP_BS + LPX_BS;
223.594 +}
223.595 +
223.596 +double lpx_get_row_prim(LPX *lp, int i)
223.597 +{ /* retrieve row primal value (basic solution) */
223.598 + return glp_get_row_prim(lp, i);
223.599 +}
223.600 +
223.601 +double lpx_get_row_dual(LPX *lp, int i)
223.602 +{ /* retrieve row dual value (basic solution) */
223.603 + return glp_get_row_dual(lp, i);
223.604 +}
223.605 +
223.606 +void lpx_get_row_info(glp_prob *lp, int i, int *tagx, double *vx,
223.607 + double *dx)
223.608 +{ /* obtain row solution information */
223.609 + if (tagx != NULL) *tagx = lpx_get_row_stat(lp, i);
223.610 + if (vx != NULL) *vx = lpx_get_row_prim(lp, i);
223.611 + if (dx != NULL) *dx = lpx_get_row_dual(lp, i);
223.612 + return;
223.613 +}
223.614 +
223.615 +int lpx_get_col_stat(LPX *lp, int j)
223.616 +{ /* retrieve column status (basic solution) */
223.617 + return glp_get_col_stat(lp, j) - GLP_BS + LPX_BS;
223.618 +}
223.619 +
223.620 +double lpx_get_col_prim(LPX *lp, int j)
223.621 +{ /* retrieve column primal value (basic solution) */
223.622 + return glp_get_col_prim(lp, j);
223.623 +}
223.624 +
223.625 +double lpx_get_col_dual(glp_prob *lp, int j)
223.626 +{ /* retrieve column dual value (basic solution) */
223.627 + return glp_get_col_dual(lp, j);
223.628 +}
223.629 +
223.630 +void lpx_get_col_info(glp_prob *lp, int j, int *tagx, double *vx,
223.631 + double *dx)
223.632 +{ /* obtain column solution information */
223.633 + if (tagx != NULL) *tagx = lpx_get_col_stat(lp, j);
223.634 + if (vx != NULL) *vx = lpx_get_col_prim(lp, j);
223.635 + if (dx != NULL) *dx = lpx_get_col_dual(lp, j);
223.636 + return;
223.637 +}
223.638 +
223.639 +int lpx_get_ray_info(LPX *lp)
223.640 +{ /* determine what causes primal unboundness */
223.641 + return glp_get_unbnd_ray(lp);
223.642 +}
223.643 +
223.644 +void lpx_check_kkt(LPX *lp, int scaled, LPXKKT *kkt)
223.645 +{ /* check Karush-Kuhn-Tucker conditions */
223.646 + int ae_ind, re_ind;
223.647 + double ae_max, re_max;
223.648 + xassert(scaled == scaled);
223.649 + _glp_check_kkt(lp, GLP_SOL, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
223.650 + &re_ind);
223.651 + kkt->pe_ae_max = ae_max;
223.652 + kkt->pe_ae_row = ae_ind;
223.653 + kkt->pe_re_max = re_max;
223.654 + kkt->pe_re_row = re_ind;
223.655 + if (re_max <= 1e-9)
223.656 + kkt->pe_quality = 'H';
223.657 + else if (re_max <= 1e-6)
223.658 + kkt->pe_quality = 'M';
223.659 + else if (re_max <= 1e-3)
223.660 + kkt->pe_quality = 'L';
223.661 + else
223.662 + kkt->pe_quality = '?';
223.663 + _glp_check_kkt(lp, GLP_SOL, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
223.664 + &re_ind);
223.665 + kkt->pb_ae_max = ae_max;
223.666 + kkt->pb_ae_ind = ae_ind;
223.667 + kkt->pb_re_max = re_max;
223.668 + kkt->pb_re_ind = re_ind;
223.669 + if (re_max <= 1e-9)
223.670 + kkt->pb_quality = 'H';
223.671 + else if (re_max <= 1e-6)
223.672 + kkt->pb_quality = 'M';
223.673 + else if (re_max <= 1e-3)
223.674 + kkt->pb_quality = 'L';
223.675 + else
223.676 + kkt->pb_quality = '?';
223.677 + _glp_check_kkt(lp, GLP_SOL, GLP_KKT_DE, &ae_max, &ae_ind, &re_max,
223.678 + &re_ind);
223.679 + kkt->de_ae_max = ae_max;
223.680 + if (ae_ind == 0)
223.681 + kkt->de_ae_col = 0;
223.682 + else
223.683 + kkt->de_ae_col = ae_ind - lp->m;
223.684 + kkt->de_re_max = re_max;
223.685 + if (re_ind == 0)
223.686 + kkt->de_re_col = 0;
223.687 + else
223.688 + kkt->de_re_col = ae_ind - lp->m;
223.689 + if (re_max <= 1e-9)
223.690 + kkt->de_quality = 'H';
223.691 + else if (re_max <= 1e-6)
223.692 + kkt->de_quality = 'M';
223.693 + else if (re_max <= 1e-3)
223.694 + kkt->de_quality = 'L';
223.695 + else
223.696 + kkt->de_quality = '?';
223.697 + _glp_check_kkt(lp, GLP_SOL, GLP_KKT_DB, &ae_max, &ae_ind, &re_max,
223.698 + &re_ind);
223.699 + kkt->db_ae_max = ae_max;
223.700 + kkt->db_ae_ind = ae_ind;
223.701 + kkt->db_re_max = re_max;
223.702 + kkt->db_re_ind = re_ind;
223.703 + if (re_max <= 1e-9)
223.704 + kkt->db_quality = 'H';
223.705 + else if (re_max <= 1e-6)
223.706 + kkt->db_quality = 'M';
223.707 + else if (re_max <= 1e-3)
223.708 + kkt->db_quality = 'L';
223.709 + else
223.710 + kkt->db_quality = '?';
223.711 + kkt->cs_ae_max = 0.0, kkt->cs_ae_ind = 0;
223.712 + kkt->cs_re_max = 0.0, kkt->cs_re_ind = 0;
223.713 + kkt->cs_quality = 'H';
223.714 + return;
223.715 +}
223.716 +
223.717 +int lpx_warm_up(LPX *lp)
223.718 +{ /* "warm up" LP basis */
223.719 + int ret;
223.720 + ret = glp_warm_up(lp);
223.721 + if (ret == 0)
223.722 + ret = LPX_E_OK;
223.723 + else if (ret == GLP_EBADB)
223.724 + ret = LPX_E_BADB;
223.725 + else if (ret == GLP_ESING)
223.726 + ret = LPX_E_SING;
223.727 + else if (ret == GLP_ECOND)
223.728 + ret = LPX_E_SING;
223.729 + else
223.730 + xassert(ret != ret);
223.731 + return ret;
223.732 +}
223.733 +
223.734 +int lpx_eval_tab_row(LPX *lp, int k, int ind[], double val[])
223.735 +{ /* compute row of the simplex tableau */
223.736 + return glp_eval_tab_row(lp, k, ind, val);
223.737 +}
223.738 +
223.739 +int lpx_eval_tab_col(LPX *lp, int k, int ind[], double val[])
223.740 +{ /* compute column of the simplex tableau */
223.741 + return glp_eval_tab_col(lp, k, ind, val);
223.742 +}
223.743 +
223.744 +int lpx_transform_row(LPX *lp, int len, int ind[], double val[])
223.745 +{ /* transform explicitly specified row */
223.746 + return glp_transform_row(lp, len, ind, val);
223.747 +}
223.748 +
223.749 +int lpx_transform_col(LPX *lp, int len, int ind[], double val[])
223.750 +{ /* transform explicitly specified column */
223.751 + return glp_transform_col(lp, len, ind, val);
223.752 +}
223.753 +
223.754 +int lpx_prim_ratio_test(LPX *lp, int len, const int ind[],
223.755 + const double val[], int how, double tol)
223.756 +{ /* perform primal ratio test */
223.757 + int piv;
223.758 + piv = glp_prim_rtest(lp, len, ind, val, how, tol);
223.759 + xassert(0 <= piv && piv <= len);
223.760 + return piv == 0 ? 0 : ind[piv];
223.761 +}
223.762 +
223.763 +int lpx_dual_ratio_test(LPX *lp, int len, const int ind[],
223.764 + const double val[], int how, double tol)
223.765 +{ /* perform dual ratio test */
223.766 + int piv;
223.767 + piv = glp_dual_rtest(lp, len, ind, val, how, tol);
223.768 + xassert(0 <= piv && piv <= len);
223.769 + return piv == 0 ? 0 : ind[piv];
223.770 +}
223.771 +
223.772 +int lpx_interior(LPX *lp)
223.773 +{ /* easy-to-use driver to the interior-point method */
223.774 + int ret;
223.775 + ret = glp_interior(lp, NULL);
223.776 + switch (ret)
223.777 + { case 0: ret = LPX_E_OK; break;
223.778 + case GLP_EFAIL: ret = LPX_E_FAULT; break;
223.779 + case GLP_ENOFEAS: ret = LPX_E_NOFEAS; break;
223.780 + case GLP_ENOCVG: ret = LPX_E_NOCONV; break;
223.781 + case GLP_EITLIM: ret = LPX_E_ITLIM; break;
223.782 + case GLP_EINSTAB: ret = LPX_E_INSTAB; break;
223.783 + default: xassert(ret != ret);
223.784 + }
223.785 + return ret;
223.786 +}
223.787 +
223.788 +int lpx_ipt_status(glp_prob *lp)
223.789 +{ /* retrieve status of interior-point solution */
223.790 + int status;
223.791 + switch (glp_ipt_status(lp))
223.792 + { case GLP_UNDEF: status = LPX_T_UNDEF; break;
223.793 + case GLP_OPT: status = LPX_T_OPT; break;
223.794 + default: xassert(lp != lp);
223.795 + }
223.796 + return status;
223.797 +}
223.798 +
223.799 +double lpx_ipt_obj_val(LPX *lp)
223.800 +{ /* retrieve objective value (interior point) */
223.801 + return glp_ipt_obj_val(lp);
223.802 +}
223.803 +
223.804 +double lpx_ipt_row_prim(LPX *lp, int i)
223.805 +{ /* retrieve row primal value (interior point) */
223.806 + return glp_ipt_row_prim(lp, i);
223.807 +}
223.808 +
223.809 +double lpx_ipt_row_dual(LPX *lp, int i)
223.810 +{ /* retrieve row dual value (interior point) */
223.811 + return glp_ipt_row_dual(lp, i);
223.812 +}
223.813 +
223.814 +double lpx_ipt_col_prim(LPX *lp, int j)
223.815 +{ /* retrieve column primal value (interior point) */
223.816 + return glp_ipt_col_prim(lp, j);
223.817 +}
223.818 +
223.819 +double lpx_ipt_col_dual(LPX *lp, int j)
223.820 +{ /* retrieve column dual value (interior point) */
223.821 + return glp_ipt_col_dual(lp, j);
223.822 +}
223.823 +
223.824 +void lpx_set_class(LPX *lp, int klass)
223.825 +{ /* set problem class */
223.826 + xassert(lp == lp);
223.827 + if (!(klass == LPX_LP || klass == LPX_MIP))
223.828 + xerror("lpx_set_class: invalid problem class\n");
223.829 + return;
223.830 +}
223.831 +
223.832 +int lpx_get_class(LPX *lp)
223.833 +{ /* determine problem klass */
223.834 + return glp_get_num_int(lp) == 0 ? LPX_LP : LPX_MIP;
223.835 +}
223.836 +
223.837 +void lpx_set_col_kind(LPX *lp, int j, int kind)
223.838 +{ /* set (change) column kind */
223.839 + glp_set_col_kind(lp, j, kind - LPX_CV + GLP_CV);
223.840 + return;
223.841 +}
223.842 +
223.843 +int lpx_get_col_kind(LPX *lp, int j)
223.844 +{ /* retrieve column kind */
223.845 + return glp_get_col_kind(lp, j) == GLP_CV ? LPX_CV : LPX_IV;
223.846 +}
223.847 +
223.848 +int lpx_get_num_int(LPX *lp)
223.849 +{ /* retrieve number of integer columns */
223.850 + return glp_get_num_int(lp);
223.851 +}
223.852 +
223.853 +int lpx_get_num_bin(LPX *lp)
223.854 +{ /* retrieve number of binary columns */
223.855 + return glp_get_num_bin(lp);
223.856 +}
223.857 +
223.858 +static int solve_mip(LPX *lp, int presolve)
223.859 +{ glp_iocp parm;
223.860 + int ret;
223.861 + glp_init_iocp(&parm);
223.862 + switch (lpx_get_int_parm(lp, LPX_K_MSGLEV))
223.863 + { case 0: parm.msg_lev = GLP_MSG_OFF; break;
223.864 + case 1: parm.msg_lev = GLP_MSG_ERR; break;
223.865 + case 2: parm.msg_lev = GLP_MSG_ON; break;
223.866 + case 3: parm.msg_lev = GLP_MSG_ALL; break;
223.867 + default: xassert(lp != lp);
223.868 + }
223.869 + switch (lpx_get_int_parm(lp, LPX_K_BRANCH))
223.870 + { case 0: parm.br_tech = GLP_BR_FFV; break;
223.871 + case 1: parm.br_tech = GLP_BR_LFV; break;
223.872 + case 2: parm.br_tech = GLP_BR_DTH; break;
223.873 + case 3: parm.br_tech = GLP_BR_MFV; break;
223.874 + default: xassert(lp != lp);
223.875 + }
223.876 + switch (lpx_get_int_parm(lp, LPX_K_BTRACK))
223.877 + { case 0: parm.bt_tech = GLP_BT_DFS; break;
223.878 + case 1: parm.bt_tech = GLP_BT_BFS; break;
223.879 + case 2: parm.bt_tech = GLP_BT_BPH; break;
223.880 + case 3: parm.bt_tech = GLP_BT_BLB; break;
223.881 + default: xassert(lp != lp);
223.882 + }
223.883 + parm.tol_int = lpx_get_real_parm(lp, LPX_K_TOLINT);
223.884 + parm.tol_obj = lpx_get_real_parm(lp, LPX_K_TOLOBJ);
223.885 + if (lpx_get_real_parm(lp, LPX_K_TMLIM) < 0.0 ||
223.886 + lpx_get_real_parm(lp, LPX_K_TMLIM) > 1e6)
223.887 + parm.tm_lim = INT_MAX;
223.888 + else
223.889 + parm.tm_lim =
223.890 + (int)(1000.0 * lpx_get_real_parm(lp, LPX_K_TMLIM));
223.891 + parm.mip_gap = lpx_get_real_parm(lp, LPX_K_MIPGAP);
223.892 + if (lpx_get_int_parm(lp, LPX_K_USECUTS) & LPX_C_GOMORY)
223.893 + parm.gmi_cuts = GLP_ON;
223.894 + else
223.895 + parm.gmi_cuts = GLP_OFF;
223.896 + if (lpx_get_int_parm(lp, LPX_K_USECUTS) & LPX_C_MIR)
223.897 + parm.mir_cuts = GLP_ON;
223.898 + else
223.899 + parm.mir_cuts = GLP_OFF;
223.900 + if (lpx_get_int_parm(lp, LPX_K_USECUTS) & LPX_C_COVER)
223.901 + parm.cov_cuts = GLP_ON;
223.902 + else
223.903 + parm.cov_cuts = GLP_OFF;
223.904 + if (lpx_get_int_parm(lp, LPX_K_USECUTS) & LPX_C_CLIQUE)
223.905 + parm.clq_cuts = GLP_ON;
223.906 + else
223.907 + parm.clq_cuts = GLP_OFF;
223.908 + parm.presolve = presolve;
223.909 + if (lpx_get_int_parm(lp, LPX_K_BINARIZE))
223.910 + parm.binarize = GLP_ON;
223.911 + ret = glp_intopt(lp, &parm);
223.912 + switch (ret)
223.913 + { case 0: ret = LPX_E_OK; break;
223.914 + case GLP_ENOPFS: ret = LPX_E_NOPFS; break;
223.915 + case GLP_ENODFS: ret = LPX_E_NODFS; break;
223.916 + case GLP_EBOUND:
223.917 + case GLP_EROOT: ret = LPX_E_FAULT; break;
223.918 + case GLP_EFAIL: ret = LPX_E_SING; break;
223.919 + case GLP_EMIPGAP: ret = LPX_E_MIPGAP; break;
223.920 + case GLP_ETMLIM: ret = LPX_E_TMLIM; break;
223.921 + default: xassert(ret != ret);
223.922 + }
223.923 + return ret;
223.924 +}
223.925 +
223.926 +int lpx_integer(LPX *lp)
223.927 +{ /* easy-to-use driver to the branch-and-bound method */
223.928 + return solve_mip(lp, GLP_OFF);
223.929 +}
223.930 +
223.931 +int lpx_intopt(LPX *lp)
223.932 +{ /* easy-to-use driver to the branch-and-bound method */
223.933 + return solve_mip(lp, GLP_ON);
223.934 +}
223.935 +
223.936 +int lpx_mip_status(glp_prob *lp)
223.937 +{ /* retrieve status of MIP solution */
223.938 + int status;
223.939 + switch (glp_mip_status(lp))
223.940 + { case GLP_UNDEF: status = LPX_I_UNDEF; break;
223.941 + case GLP_OPT: status = LPX_I_OPT; break;
223.942 + case GLP_FEAS: status = LPX_I_FEAS; break;
223.943 + case GLP_NOFEAS: status = LPX_I_NOFEAS; break;
223.944 + default: xassert(lp != lp);
223.945 + }
223.946 + return status;
223.947 +}
223.948 +
223.949 +double lpx_mip_obj_val(LPX *lp)
223.950 +{ /* retrieve objective value (MIP solution) */
223.951 + return glp_mip_obj_val(lp);
223.952 +}
223.953 +
223.954 +double lpx_mip_row_val(LPX *lp, int i)
223.955 +{ /* retrieve row value (MIP solution) */
223.956 + return glp_mip_row_val(lp, i);
223.957 +}
223.958 +
223.959 +double lpx_mip_col_val(LPX *lp, int j)
223.960 +{ /* retrieve column value (MIP solution) */
223.961 + return glp_mip_col_val(lp, j);
223.962 +}
223.963 +
223.964 +void lpx_check_int(LPX *lp, LPXKKT *kkt)
223.965 +{ /* check integer feasibility conditions */
223.966 + int ae_ind, re_ind;
223.967 + double ae_max, re_max;
223.968 + _glp_check_kkt(lp, GLP_MIP, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
223.969 + &re_ind);
223.970 + kkt->pe_ae_max = ae_max;
223.971 + kkt->pe_ae_row = ae_ind;
223.972 + kkt->pe_re_max = re_max;
223.973 + kkt->pe_re_row = re_ind;
223.974 + if (re_max <= 1e-9)
223.975 + kkt->pe_quality = 'H';
223.976 + else if (re_max <= 1e-6)
223.977 + kkt->pe_quality = 'M';
223.978 + else if (re_max <= 1e-3)
223.979 + kkt->pe_quality = 'L';
223.980 + else
223.981 + kkt->pe_quality = '?';
223.982 + _glp_check_kkt(lp, GLP_MIP, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
223.983 + &re_ind);
223.984 + kkt->pb_ae_max = ae_max;
223.985 + kkt->pb_ae_ind = ae_ind;
223.986 + kkt->pb_re_max = re_max;
223.987 + kkt->pb_re_ind = re_ind;
223.988 + if (re_max <= 1e-9)
223.989 + kkt->pb_quality = 'H';
223.990 + else if (re_max <= 1e-6)
223.991 + kkt->pb_quality = 'M';
223.992 + else if (re_max <= 1e-3)
223.993 + kkt->pb_quality = 'L';
223.994 + else
223.995 + kkt->pb_quality = '?';
223.996 + return;
223.997 +}
223.998 +
223.999 +#if 1 /* 17/XI-2009 */
223.1000 +static void reset_parms(LPX *lp)
223.1001 +{ /* reset control parameters to default values */
223.1002 + struct LPXCPS *cps = lp->parms;
223.1003 + xassert(cps != NULL);
223.1004 + cps->msg_lev = 3;
223.1005 + cps->scale = 1;
223.1006 + cps->dual = 0;
223.1007 + cps->price = 1;
223.1008 + cps->relax = 0.07;
223.1009 + cps->tol_bnd = 1e-7;
223.1010 + cps->tol_dj = 1e-7;
223.1011 + cps->tol_piv = 1e-9;
223.1012 + cps->round = 0;
223.1013 + cps->obj_ll = -DBL_MAX;
223.1014 + cps->obj_ul = +DBL_MAX;
223.1015 + cps->it_lim = -1;
223.1016 +#if 0 /* 02/XII-2010 */
223.1017 + lp->it_cnt = 0;
223.1018 +#endif
223.1019 + cps->tm_lim = -1.0;
223.1020 + cps->out_frq = 200;
223.1021 + cps->out_dly = 0.0;
223.1022 + cps->branch = 2;
223.1023 + cps->btrack = 3;
223.1024 + cps->tol_int = 1e-5;
223.1025 + cps->tol_obj = 1e-7;
223.1026 + cps->mps_info = 1;
223.1027 + cps->mps_obj = 2;
223.1028 + cps->mps_orig = 0;
223.1029 + cps->mps_wide = 1;
223.1030 + cps->mps_free = 0;
223.1031 + cps->mps_skip = 0;
223.1032 + cps->lpt_orig = 0;
223.1033 + cps->presol = 0;
223.1034 + cps->binarize = 0;
223.1035 + cps->use_cuts = 0;
223.1036 + cps->mip_gap = 0.0;
223.1037 + return;
223.1038 +}
223.1039 +#endif
223.1040 +
223.1041 +#if 1 /* 17/XI-2009 */
223.1042 +static struct LPXCPS *access_parms(LPX *lp)
223.1043 +{ /* allocate and initialize control parameters, if necessary */
223.1044 + if (lp->parms == NULL)
223.1045 + { lp->parms = xmalloc(sizeof(struct LPXCPS));
223.1046 + reset_parms(lp);
223.1047 + }
223.1048 + return lp->parms;
223.1049 +}
223.1050 +#endif
223.1051 +
223.1052 +#if 1 /* 17/XI-2009 */
223.1053 +void lpx_reset_parms(LPX *lp)
223.1054 +{ /* reset control parameters to default values */
223.1055 + access_parms(lp);
223.1056 + reset_parms(lp);
223.1057 + return;
223.1058 +}
223.1059 +#endif
223.1060 +
223.1061 +void lpx_set_int_parm(LPX *lp, int parm, int val)
223.1062 +{ /* set (change) integer control parameter */
223.1063 +#if 0 /* 17/XI-2009 */
223.1064 + struct LPXCPS *cps = lp->cps;
223.1065 +#else
223.1066 + struct LPXCPS *cps = access_parms(lp);
223.1067 +#endif
223.1068 + switch (parm)
223.1069 + { case LPX_K_MSGLEV:
223.1070 + if (!(0 <= val && val <= 3))
223.1071 + xerror("lpx_set_int_parm: MSGLEV = %d; invalid value\n",
223.1072 + val);
223.1073 + cps->msg_lev = val;
223.1074 + break;
223.1075 + case LPX_K_SCALE:
223.1076 + if (!(0 <= val && val <= 3))
223.1077 + xerror("lpx_set_int_parm: SCALE = %d; invalid value\n",
223.1078 + val);
223.1079 + cps->scale = val;
223.1080 + break;
223.1081 + case LPX_K_DUAL:
223.1082 + if (!(val == 0 || val == 1))
223.1083 + xerror("lpx_set_int_parm: DUAL = %d; invalid value\n",
223.1084 + val);
223.1085 + cps->dual = val;
223.1086 + break;
223.1087 + case LPX_K_PRICE:
223.1088 + if (!(val == 0 || val == 1))
223.1089 + xerror("lpx_set_int_parm: PRICE = %d; invalid value\n",
223.1090 + val);
223.1091 + cps->price = val;
223.1092 + break;
223.1093 + case LPX_K_ROUND:
223.1094 + if (!(val == 0 || val == 1))
223.1095 + xerror("lpx_set_int_parm: ROUND = %d; invalid value\n",
223.1096 + val);
223.1097 + cps->round = val;
223.1098 + break;
223.1099 + case LPX_K_ITLIM:
223.1100 + cps->it_lim = val;
223.1101 + break;
223.1102 + case LPX_K_ITCNT:
223.1103 + lp->it_cnt = val;
223.1104 + break;
223.1105 + case LPX_K_OUTFRQ:
223.1106 + if (!(val > 0))
223.1107 + xerror("lpx_set_int_parm: OUTFRQ = %d; invalid value\n",
223.1108 + val);
223.1109 + cps->out_frq = val;
223.1110 + break;
223.1111 + case LPX_K_BRANCH:
223.1112 + if (!(val == 0 || val == 1 || val == 2 || val == 3))
223.1113 + xerror("lpx_set_int_parm: BRANCH = %d; invalid value\n",
223.1114 + val);
223.1115 + cps->branch = val;
223.1116 + break;
223.1117 + case LPX_K_BTRACK:
223.1118 + if (!(val == 0 || val == 1 || val == 2 || val == 3))
223.1119 + xerror("lpx_set_int_parm: BTRACK = %d; invalid value\n",
223.1120 + val);
223.1121 + cps->btrack = val;
223.1122 + break;
223.1123 + case LPX_K_MPSINFO:
223.1124 + if (!(val == 0 || val == 1))
223.1125 + xerror("lpx_set_int_parm: MPSINFO = %d; invalid value\n",
223.1126 + val);
223.1127 + cps->mps_info = val;
223.1128 + break;
223.1129 + case LPX_K_MPSOBJ:
223.1130 + if (!(val == 0 || val == 1 || val == 2))
223.1131 + xerror("lpx_set_int_parm: MPSOBJ = %d; invalid value\n",
223.1132 + val);
223.1133 + cps->mps_obj = val;
223.1134 + break;
223.1135 + case LPX_K_MPSORIG:
223.1136 + if (!(val == 0 || val == 1))
223.1137 + xerror("lpx_set_int_parm: MPSORIG = %d; invalid value\n",
223.1138 + val);
223.1139 + cps->mps_orig = val;
223.1140 + break;
223.1141 + case LPX_K_MPSWIDE:
223.1142 + if (!(val == 0 || val == 1))
223.1143 + xerror("lpx_set_int_parm: MPSWIDE = %d; invalid value\n",
223.1144 + val);
223.1145 + cps->mps_wide = val;
223.1146 + break;
223.1147 + case LPX_K_MPSFREE:
223.1148 + if (!(val == 0 || val == 1))
223.1149 + xerror("lpx_set_int_parm: MPSFREE = %d; invalid value\n",
223.1150 + val);
223.1151 + cps->mps_free = val;
223.1152 + break;
223.1153 + case LPX_K_MPSSKIP:
223.1154 + if (!(val == 0 || val == 1))
223.1155 + xerror("lpx_set_int_parm: MPSSKIP = %d; invalid value\n",
223.1156 + val);
223.1157 + cps->mps_skip = val;
223.1158 + break;
223.1159 + case LPX_K_LPTORIG:
223.1160 + if (!(val == 0 || val == 1))
223.1161 + xerror("lpx_set_int_parm: LPTORIG = %d; invalid value\n",
223.1162 + val);
223.1163 + cps->lpt_orig = val;
223.1164 + break;
223.1165 + case LPX_K_PRESOL:
223.1166 + if (!(val == 0 || val == 1))
223.1167 + xerror("lpx_set_int_parm: PRESOL = %d; invalid value\n",
223.1168 + val);
223.1169 + cps->presol = val;
223.1170 + break;
223.1171 + case LPX_K_BINARIZE:
223.1172 + if (!(val == 0 || val == 1))
223.1173 + xerror("lpx_set_int_parm: BINARIZE = %d; invalid value\n"
223.1174 + , val);
223.1175 + cps->binarize = val;
223.1176 + break;
223.1177 + case LPX_K_USECUTS:
223.1178 + if (val & ~LPX_C_ALL)
223.1179 + xerror("lpx_set_int_parm: USECUTS = 0x%X; invalid value\n",
223.1180 + val);
223.1181 + cps->use_cuts = val;
223.1182 + break;
223.1183 + case LPX_K_BFTYPE:
223.1184 +#if 0
223.1185 + if (!(1 <= val && val <= 3))
223.1186 + xerror("lpx_set_int_parm: BFTYPE = %d; invalid value\n",
223.1187 + val);
223.1188 + cps->bf_type = val;
223.1189 +#else
223.1190 + { glp_bfcp parm;
223.1191 + glp_get_bfcp(lp, &parm);
223.1192 + switch (val)
223.1193 + { case 1:
223.1194 + parm.type = GLP_BF_FT; break;
223.1195 + case 2:
223.1196 + parm.type = GLP_BF_BG; break;
223.1197 + case 3:
223.1198 + parm.type = GLP_BF_GR; break;
223.1199 + default:
223.1200 + xerror("lpx_set_int_parm: BFTYPE = %d; invalid val"
223.1201 + "ue\n", val);
223.1202 + }
223.1203 + glp_set_bfcp(lp, &parm);
223.1204 + }
223.1205 +#endif
223.1206 + break;
223.1207 + default:
223.1208 + xerror("lpx_set_int_parm: parm = %d; invalid parameter\n",
223.1209 + parm);
223.1210 + }
223.1211 + return;
223.1212 +}
223.1213 +
223.1214 +int lpx_get_int_parm(LPX *lp, int parm)
223.1215 +{ /* query integer control parameter */
223.1216 +#if 0 /* 17/XI-2009 */
223.1217 + struct LPXCPS *cps = lp->cps;
223.1218 +#else
223.1219 + struct LPXCPS *cps = access_parms(lp);
223.1220 +#endif
223.1221 + int val = 0;
223.1222 + switch (parm)
223.1223 + { case LPX_K_MSGLEV:
223.1224 + val = cps->msg_lev; break;
223.1225 + case LPX_K_SCALE:
223.1226 + val = cps->scale; break;
223.1227 + case LPX_K_DUAL:
223.1228 + val = cps->dual; break;
223.1229 + case LPX_K_PRICE:
223.1230 + val = cps->price; break;
223.1231 + case LPX_K_ROUND:
223.1232 + val = cps->round; break;
223.1233 + case LPX_K_ITLIM:
223.1234 + val = cps->it_lim; break;
223.1235 + case LPX_K_ITCNT:
223.1236 + val = lp->it_cnt; break;
223.1237 + case LPX_K_OUTFRQ:
223.1238 + val = cps->out_frq; break;
223.1239 + case LPX_K_BRANCH:
223.1240 + val = cps->branch; break;
223.1241 + case LPX_K_BTRACK:
223.1242 + val = cps->btrack; break;
223.1243 + case LPX_K_MPSINFO:
223.1244 + val = cps->mps_info; break;
223.1245 + case LPX_K_MPSOBJ:
223.1246 + val = cps->mps_obj; break;
223.1247 + case LPX_K_MPSORIG:
223.1248 + val = cps->mps_orig; break;
223.1249 + case LPX_K_MPSWIDE:
223.1250 + val = cps->mps_wide; break;
223.1251 + case LPX_K_MPSFREE:
223.1252 + val = cps->mps_free; break;
223.1253 + case LPX_K_MPSSKIP:
223.1254 + val = cps->mps_skip; break;
223.1255 + case LPX_K_LPTORIG:
223.1256 + val = cps->lpt_orig; break;
223.1257 + case LPX_K_PRESOL:
223.1258 + val = cps->presol; break;
223.1259 + case LPX_K_BINARIZE:
223.1260 + val = cps->binarize; break;
223.1261 + case LPX_K_USECUTS:
223.1262 + val = cps->use_cuts; break;
223.1263 + case LPX_K_BFTYPE:
223.1264 +#if 0
223.1265 + val = cps->bf_type; break;
223.1266 +#else
223.1267 + { glp_bfcp parm;
223.1268 + glp_get_bfcp(lp, &parm);
223.1269 + switch (parm.type)
223.1270 + { case GLP_BF_FT:
223.1271 + val = 1; break;
223.1272 + case GLP_BF_BG:
223.1273 + val = 2; break;
223.1274 + case GLP_BF_GR:
223.1275 + val = 3; break;
223.1276 + default:
223.1277 + xassert(lp != lp);
223.1278 + }
223.1279 + }
223.1280 + break;
223.1281 +#endif
223.1282 + default:
223.1283 + xerror("lpx_get_int_parm: parm = %d; invalid parameter\n",
223.1284 + parm);
223.1285 + }
223.1286 + return val;
223.1287 +}
223.1288 +
223.1289 +void lpx_set_real_parm(LPX *lp, int parm, double val)
223.1290 +{ /* set (change) real control parameter */
223.1291 +#if 0 /* 17/XI-2009 */
223.1292 + struct LPXCPS *cps = lp->cps;
223.1293 +#else
223.1294 + struct LPXCPS *cps = access_parms(lp);
223.1295 +#endif
223.1296 + switch (parm)
223.1297 + { case LPX_K_RELAX:
223.1298 + if (!(0.0 <= val && val <= 1.0))
223.1299 + xerror("lpx_set_real_parm: RELAX = %g; invalid value\n",
223.1300 + val);
223.1301 + cps->relax = val;
223.1302 + break;
223.1303 + case LPX_K_TOLBND:
223.1304 + if (!(DBL_EPSILON <= val && val <= 0.001))
223.1305 + xerror("lpx_set_real_parm: TOLBND = %g; invalid value\n",
223.1306 + val);
223.1307 +#if 0
223.1308 + if (cps->tol_bnd > val)
223.1309 + { /* invalidate the basic solution */
223.1310 + lp->p_stat = LPX_P_UNDEF;
223.1311 + lp->d_stat = LPX_D_UNDEF;
223.1312 + }
223.1313 +#endif
223.1314 + cps->tol_bnd = val;
223.1315 + break;
223.1316 + case LPX_K_TOLDJ:
223.1317 + if (!(DBL_EPSILON <= val && val <= 0.001))
223.1318 + xerror("lpx_set_real_parm: TOLDJ = %g; invalid value\n",
223.1319 + val);
223.1320 +#if 0
223.1321 + if (cps->tol_dj > val)
223.1322 + { /* invalidate the basic solution */
223.1323 + lp->p_stat = LPX_P_UNDEF;
223.1324 + lp->d_stat = LPX_D_UNDEF;
223.1325 + }
223.1326 +#endif
223.1327 + cps->tol_dj = val;
223.1328 + break;
223.1329 + case LPX_K_TOLPIV:
223.1330 + if (!(DBL_EPSILON <= val && val <= 0.001))
223.1331 + xerror("lpx_set_real_parm: TOLPIV = %g; invalid value\n",
223.1332 + val);
223.1333 + cps->tol_piv = val;
223.1334 + break;
223.1335 + case LPX_K_OBJLL:
223.1336 + cps->obj_ll = val;
223.1337 + break;
223.1338 + case LPX_K_OBJUL:
223.1339 + cps->obj_ul = val;
223.1340 + break;
223.1341 + case LPX_K_TMLIM:
223.1342 + cps->tm_lim = val;
223.1343 + break;
223.1344 + case LPX_K_OUTDLY:
223.1345 + cps->out_dly = val;
223.1346 + break;
223.1347 + case LPX_K_TOLINT:
223.1348 + if (!(DBL_EPSILON <= val && val <= 0.001))
223.1349 + xerror("lpx_set_real_parm: TOLINT = %g; invalid value\n",
223.1350 + val);
223.1351 + cps->tol_int = val;
223.1352 + break;
223.1353 + case LPX_K_TOLOBJ:
223.1354 + if (!(DBL_EPSILON <= val && val <= 0.001))
223.1355 + xerror("lpx_set_real_parm: TOLOBJ = %g; invalid value\n",
223.1356 + val);
223.1357 + cps->tol_obj = val;
223.1358 + break;
223.1359 + case LPX_K_MIPGAP:
223.1360 + if (val < 0.0)
223.1361 + xerror("lpx_set_real_parm: MIPGAP = %g; invalid value\n",
223.1362 + val);
223.1363 + cps->mip_gap = val;
223.1364 + break;
223.1365 + default:
223.1366 + xerror("lpx_set_real_parm: parm = %d; invalid parameter\n",
223.1367 + parm);
223.1368 + }
223.1369 + return;
223.1370 +}
223.1371 +
223.1372 +double lpx_get_real_parm(LPX *lp, int parm)
223.1373 +{ /* query real control parameter */
223.1374 +#if 0 /* 17/XI-2009 */
223.1375 + struct LPXCPS *cps = lp->cps;
223.1376 +#else
223.1377 + struct LPXCPS *cps = access_parms(lp);
223.1378 +#endif
223.1379 + double val = 0.0;
223.1380 + switch (parm)
223.1381 + { case LPX_K_RELAX:
223.1382 + val = cps->relax;
223.1383 + break;
223.1384 + case LPX_K_TOLBND:
223.1385 + val = cps->tol_bnd;
223.1386 + break;
223.1387 + case LPX_K_TOLDJ:
223.1388 + val = cps->tol_dj;
223.1389 + break;
223.1390 + case LPX_K_TOLPIV:
223.1391 + val = cps->tol_piv;
223.1392 + break;
223.1393 + case LPX_K_OBJLL:
223.1394 + val = cps->obj_ll;
223.1395 + break;
223.1396 + case LPX_K_OBJUL:
223.1397 + val = cps->obj_ul;
223.1398 + break;
223.1399 + case LPX_K_TMLIM:
223.1400 + val = cps->tm_lim;
223.1401 + break;
223.1402 + case LPX_K_OUTDLY:
223.1403 + val = cps->out_dly;
223.1404 + break;
223.1405 + case LPX_K_TOLINT:
223.1406 + val = cps->tol_int;
223.1407 + break;
223.1408 + case LPX_K_TOLOBJ:
223.1409 + val = cps->tol_obj;
223.1410 + break;
223.1411 + case LPX_K_MIPGAP:
223.1412 + val = cps->mip_gap;
223.1413 + break;
223.1414 + default:
223.1415 + xerror("lpx_get_real_parm: parm = %d; invalid parameter\n",
223.1416 + parm);
223.1417 + }
223.1418 + return val;
223.1419 +}
223.1420 +
223.1421 +LPX *lpx_read_mps(const char *fname)
223.1422 +{ /* read problem data in fixed MPS format */
223.1423 + LPX *lp = lpx_create_prob();
223.1424 + if (glp_read_mps(lp, GLP_MPS_DECK, NULL, fname))
223.1425 + lpx_delete_prob(lp), lp = NULL;
223.1426 + return lp;
223.1427 +}
223.1428 +
223.1429 +int lpx_write_mps(LPX *lp, const char *fname)
223.1430 +{ /* write problem data in fixed MPS format */
223.1431 + return glp_write_mps(lp, GLP_MPS_DECK, NULL, fname);
223.1432 +}
223.1433 +
223.1434 +int lpx_read_bas(LPX *lp, const char *fname)
223.1435 +{ /* read LP basis in fixed MPS format */
223.1436 +#if 0 /* 13/IV-2009 */
223.1437 + return read_bas(lp, fname);
223.1438 +#else
223.1439 + xassert(lp == lp);
223.1440 + xassert(fname == fname);
223.1441 + xerror("lpx_read_bas: operation not supported\n");
223.1442 + return 0;
223.1443 +#endif
223.1444 +}
223.1445 +
223.1446 +int lpx_write_bas(LPX *lp, const char *fname)
223.1447 +{ /* write LP basis in fixed MPS format */
223.1448 +#if 0 /* 13/IV-2009 */
223.1449 + return write_bas(lp, fname);
223.1450 +#else
223.1451 + xassert(lp == lp);
223.1452 + xassert(fname == fname);
223.1453 + xerror("lpx_write_bas: operation not supported\n");
223.1454 + return 0;
223.1455 +#endif
223.1456 +}
223.1457 +
223.1458 +LPX *lpx_read_freemps(const char *fname)
223.1459 +{ /* read problem data in free MPS format */
223.1460 + LPX *lp = lpx_create_prob();
223.1461 + if (glp_read_mps(lp, GLP_MPS_FILE, NULL, fname))
223.1462 + lpx_delete_prob(lp), lp = NULL;
223.1463 + return lp;
223.1464 +}
223.1465 +
223.1466 +int lpx_write_freemps(LPX *lp, const char *fname)
223.1467 +{ /* write problem data in free MPS format */
223.1468 + return glp_write_mps(lp, GLP_MPS_FILE, NULL, fname);
223.1469 +}
223.1470 +
223.1471 +LPX *lpx_read_cpxlp(const char *fname)
223.1472 +{ /* read problem data in CPLEX LP format */
223.1473 + LPX *lp;
223.1474 + lp = lpx_create_prob();
223.1475 + if (glp_read_lp(lp, NULL, fname))
223.1476 + lpx_delete_prob(lp), lp = NULL;
223.1477 + return lp;
223.1478 +}
223.1479 +
223.1480 +int lpx_write_cpxlp(LPX *lp, const char *fname)
223.1481 +{ /* write problem data in CPLEX LP format */
223.1482 + return glp_write_lp(lp, NULL, fname);
223.1483 +}
223.1484 +
223.1485 +LPX *lpx_read_model(const char *model, const char *data, const char
223.1486 + *output)
223.1487 +{ /* read LP/MIP model written in GNU MathProg language */
223.1488 + LPX *lp = NULL;
223.1489 + glp_tran *tran;
223.1490 + /* allocate the translator workspace */
223.1491 + tran = glp_mpl_alloc_wksp();
223.1492 + /* read model section and optional data section */
223.1493 + if (glp_mpl_read_model(tran, model, data != NULL)) goto done;
223.1494 + /* read separate data section, if required */
223.1495 + if (data != NULL)
223.1496 + if (glp_mpl_read_data(tran, data)) goto done;
223.1497 + /* generate the model */
223.1498 + if (glp_mpl_generate(tran, output)) goto done;
223.1499 + /* build the problem instance from the model */
223.1500 + lp = glp_create_prob();
223.1501 + glp_mpl_build_prob(tran, lp);
223.1502 +done: /* free the translator workspace */
223.1503 + glp_mpl_free_wksp(tran);
223.1504 + /* bring the problem object to the calling program */
223.1505 + return lp;
223.1506 +}
223.1507 +
223.1508 +int lpx_print_prob(LPX *lp, const char *fname)
223.1509 +{ /* write problem data in plain text format */
223.1510 + return glp_write_lp(lp, NULL, fname);
223.1511 +}
223.1512 +
223.1513 +int lpx_print_sol(LPX *lp, const char *fname)
223.1514 +{ /* write LP problem solution in printable format */
223.1515 + return glp_print_sol(lp, fname);
223.1516 +}
223.1517 +
223.1518 +int lpx_print_sens_bnds(LPX *lp, const char *fname)
223.1519 +{ /* write bounds sensitivity information */
223.1520 + if (glp_get_status(lp) == GLP_OPT && !glp_bf_exists(lp))
223.1521 + glp_factorize(lp);
223.1522 + return glp_print_ranges(lp, 0, NULL, 0, fname);
223.1523 +}
223.1524 +
223.1525 +int lpx_print_ips(LPX *lp, const char *fname)
223.1526 +{ /* write interior point solution in printable format */
223.1527 + return glp_print_ipt(lp, fname);
223.1528 +}
223.1529 +
223.1530 +int lpx_print_mip(LPX *lp, const char *fname)
223.1531 +{ /* write MIP problem solution in printable format */
223.1532 + return glp_print_mip(lp, fname);
223.1533 +}
223.1534 +
223.1535 +int lpx_is_b_avail(glp_prob *lp)
223.1536 +{ /* check if LP basis is available */
223.1537 + return glp_bf_exists(lp);
223.1538 +}
223.1539 +
223.1540 +int lpx_main(int argc, const char *argv[])
223.1541 +{ /* stand-alone LP/MIP solver */
223.1542 + return glp_main(argc, argv);
223.1543 +}
223.1544 +
223.1545 +/* eof */
224.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
224.2 +++ b/src/glplpx02.c Mon Dec 06 13:09:21 2010 +0100
224.3 @@ -0,0 +1,264 @@
224.4 +/* glplpx02.c */
224.5 +
224.6 +/***********************************************************************
224.7 +* This code is part of GLPK (GNU Linear Programming Kit).
224.8 +*
224.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
224.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
224.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
224.12 +* E-mail: <mao@gnu.org>.
224.13 +*
224.14 +* GLPK is free software: you can redistribute it and/or modify it
224.15 +* under the terms of the GNU General Public License as published by
224.16 +* the Free Software Foundation, either version 3 of the License, or
224.17 +* (at your option) any later version.
224.18 +*
224.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
224.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
224.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
224.22 +* License for more details.
224.23 +*
224.24 +* You should have received a copy of the GNU General Public License
224.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
224.26 +***********************************************************************/
224.27 +
224.28 +#include "glpapi.h"
224.29 +
224.30 +/***********************************************************************
224.31 +* NAME
224.32 +*
224.33 +* lpx_put_solution - store basic solution components
224.34 +*
224.35 +* SYNOPSIS
224.36 +*
224.37 +* void lpx_put_solution(glp_prob *lp, int inval, const int *p_stat,
224.38 +* const int *d_stat, const double *obj_val, const int r_stat[],
224.39 +* const double r_prim[], const double r_dual[], const int c_stat[],
224.40 +* const double c_prim[], const double c_dual[])
224.41 +*
224.42 +* DESCRIPTION
224.43 +*
224.44 +* The routine lpx_put_solution stores basic solution components to the
224.45 +* specified problem object.
224.46 +*
224.47 +* The parameter inval is the basis factorization invalidity flag.
224.48 +* If this flag is clear, the current status of the basis factorization
224.49 +* remains unchanged. If this flag is set, the routine invalidates the
224.50 +* basis factorization.
224.51 +*
224.52 +* The parameter p_stat is a pointer to the status of primal basic
224.53 +* solution, which should be specified as follows:
224.54 +*
224.55 +* GLP_UNDEF - primal solution is undefined;
224.56 +* GLP_FEAS - primal solution is feasible;
224.57 +* GLP_INFEAS - primal solution is infeasible;
224.58 +* GLP_NOFEAS - no primal feasible solution exists.
224.59 +*
224.60 +* If the parameter p_stat is NULL, the current status of primal basic
224.61 +* solution remains unchanged.
224.62 +*
224.63 +* The parameter d_stat is a pointer to the status of dual basic
224.64 +* solution, which should be specified as follows:
224.65 +*
224.66 +* GLP_UNDEF - dual solution is undefined;
224.67 +* GLP_FEAS - dual solution is feasible;
224.68 +* GLP_INFEAS - dual solution is infeasible;
224.69 +* GLP_NOFEAS - no dual feasible solution exists.
224.70 +*
224.71 +* If the parameter d_stat is NULL, the current status of dual basic
224.72 +* solution remains unchanged.
224.73 +*
224.74 +* The parameter obj_val is a pointer to the objective function value.
224.75 +* If it is NULL, the current value of the objective function remains
224.76 +* unchanged.
224.77 +*
224.78 +* The array element r_stat[i], 1 <= i <= m (where m is the number of
224.79 +* rows in the problem object), specifies the status of i-th auxiliary
224.80 +* variable, which should be specified as follows:
224.81 +*
224.82 +* GLP_BS - basic variable;
224.83 +* GLP_NL - non-basic variable on lower bound;
224.84 +* GLP_NU - non-basic variable on upper bound;
224.85 +* GLP_NF - non-basic free variable;
224.86 +* GLP_NS - non-basic fixed variable.
224.87 +*
224.88 +* If the parameter r_stat is NULL, the current statuses of auxiliary
224.89 +* variables remain unchanged.
224.90 +*
224.91 +* The array element r_prim[i], 1 <= i <= m (where m is the number of
224.92 +* rows in the problem object), specifies a primal value of i-th
224.93 +* auxiliary variable. If the parameter r_prim is NULL, the current
224.94 +* primal values of auxiliary variables remain unchanged.
224.95 +*
224.96 +* The array element r_dual[i], 1 <= i <= m (where m is the number of
224.97 +* rows in the problem object), specifies a dual value (reduced cost)
224.98 +* of i-th auxiliary variable. If the parameter r_dual is NULL, the
224.99 +* current dual values of auxiliary variables remain unchanged.
224.100 +*
224.101 +* The array element c_stat[j], 1 <= j <= n (where n is the number of
224.102 +* columns in the problem object), specifies the status of j-th
224.103 +* structural variable, which should be specified as follows:
224.104 +*
224.105 +* GLP_BS - basic variable;
224.106 +* GLP_NL - non-basic variable on lower bound;
224.107 +* GLP_NU - non-basic variable on upper bound;
224.108 +* GLP_NF - non-basic free variable;
224.109 +* GLP_NS - non-basic fixed variable.
224.110 +*
224.111 +* If the parameter c_stat is NULL, the current statuses of structural
224.112 +* variables remain unchanged.
224.113 +*
224.114 +* The array element c_prim[j], 1 <= j <= n (where n is the number of
224.115 +* columns in the problem object), specifies a primal value of j-th
224.116 +* structural variable. If the parameter c_prim is NULL, the current
224.117 +* primal values of structural variables remain unchanged.
224.118 +*
224.119 +* The array element c_dual[j], 1 <= j <= n (where n is the number of
224.120 +* columns in the problem object), specifies a dual value (reduced cost)
224.121 +* of j-th structural variable. If the parameter c_dual is NULL, the
224.122 +* current dual values of structural variables remain unchanged. */
224.123 +
224.124 +void lpx_put_solution(glp_prob *lp, int inval, const int *p_stat,
224.125 + const int *d_stat, const double *obj_val, const int r_stat[],
224.126 + const double r_prim[], const double r_dual[], const int c_stat[],
224.127 + const double c_prim[], const double c_dual[])
224.128 +{ GLPROW *row;
224.129 + GLPCOL *col;
224.130 + int i, j;
224.131 + /* invalidate the basis factorization, if required */
224.132 + if (inval) lp->valid = 0;
224.133 + /* store primal status */
224.134 + if (p_stat != NULL)
224.135 + { if (!(*p_stat == GLP_UNDEF || *p_stat == GLP_FEAS ||
224.136 + *p_stat == GLP_INFEAS || *p_stat == GLP_NOFEAS))
224.137 + xerror("lpx_put_solution: p_stat = %d; invalid primal statu"
224.138 + "s\n", *p_stat);
224.139 + lp->pbs_stat = *p_stat;
224.140 + }
224.141 + /* store dual status */
224.142 + if (d_stat != NULL)
224.143 + { if (!(*d_stat == GLP_UNDEF || *d_stat == GLP_FEAS ||
224.144 + *d_stat == GLP_INFEAS || *d_stat == GLP_NOFEAS))
224.145 + xerror("lpx_put_solution: d_stat = %d; invalid dual status "
224.146 + "\n", *d_stat);
224.147 + lp->dbs_stat = *d_stat;
224.148 + }
224.149 + /* store objective function value */
224.150 + if (obj_val != NULL) lp->obj_val = *obj_val;
224.151 + /* store row solution components */
224.152 + for (i = 1; i <= lp->m; i++)
224.153 + { row = lp->row[i];
224.154 + if (r_stat != NULL)
224.155 + { if (!(r_stat[i] == GLP_BS ||
224.156 + row->type == GLP_FR && r_stat[i] == GLP_NF ||
224.157 + row->type == GLP_LO && r_stat[i] == GLP_NL ||
224.158 + row->type == GLP_UP && r_stat[i] == GLP_NU ||
224.159 + row->type == GLP_DB && r_stat[i] == GLP_NL ||
224.160 + row->type == GLP_DB && r_stat[i] == GLP_NU ||
224.161 + row->type == GLP_FX && r_stat[i] == GLP_NS))
224.162 + xerror("lpx_put_solution: r_stat[%d] = %d; invalid row s"
224.163 + "tatus\n", i, r_stat[i]);
224.164 + row->stat = r_stat[i];
224.165 + }
224.166 + if (r_prim != NULL) row->prim = r_prim[i];
224.167 + if (r_dual != NULL) row->dual = r_dual[i];
224.168 + }
224.169 + /* store column solution components */
224.170 + for (j = 1; j <= lp->n; j++)
224.171 + { col = lp->col[j];
224.172 + if (c_stat != NULL)
224.173 + { if (!(c_stat[j] == GLP_BS ||
224.174 + col->type == GLP_FR && c_stat[j] == GLP_NF ||
224.175 + col->type == GLP_LO && c_stat[j] == GLP_NL ||
224.176 + col->type == GLP_UP && c_stat[j] == GLP_NU ||
224.177 + col->type == GLP_DB && c_stat[j] == GLP_NL ||
224.178 + col->type == GLP_DB && c_stat[j] == GLP_NU ||
224.179 + col->type == GLP_FX && c_stat[j] == GLP_NS))
224.180 + xerror("lpx_put_solution: c_stat[%d] = %d; invalid colum"
224.181 + "n status\n", j, c_stat[j]);
224.182 + col->stat = c_stat[j];
224.183 + }
224.184 + if (c_prim != NULL) col->prim = c_prim[j];
224.185 + if (c_dual != NULL) col->dual = c_dual[j];
224.186 + }
224.187 + return;
224.188 +}
224.189 +
224.190 +/*----------------------------------------------------------------------
224.191 +-- lpx_put_mip_soln - store mixed integer solution components.
224.192 +--
224.193 +-- *Synopsis*
224.194 +--
224.195 +-- #include "glplpx.h"
224.196 +-- void lpx_put_mip_soln(glp_prob *lp, int i_stat, double row_mipx[],
224.197 +-- double col_mipx[]);
224.198 +--
224.199 +-- *Description*
224.200 +--
224.201 +-- The routine lpx_put_mip_soln stores solution components obtained by
224.202 +-- branch-and-bound solver into the specified problem object.
224.203 +--
224.204 +-- NOTE: This routine is intended for internal use only. */
224.205 +
224.206 +void lpx_put_mip_soln(glp_prob *lp, int i_stat, double row_mipx[],
224.207 + double col_mipx[])
224.208 +{ GLPROW *row;
224.209 + GLPCOL *col;
224.210 + int i, j;
224.211 + double sum;
224.212 + /* store mixed integer status */
224.213 +#if 0
224.214 + if (!(i_stat == LPX_I_UNDEF || i_stat == LPX_I_OPT ||
224.215 + i_stat == LPX_I_FEAS || i_stat == LPX_I_NOFEAS))
224.216 + fault("lpx_put_mip_soln: i_stat = %d; invalid mixed integer st"
224.217 + "atus", i_stat);
224.218 + lp->i_stat = i_stat;
224.219 +#else
224.220 + switch (i_stat)
224.221 + { case LPX_I_UNDEF:
224.222 + lp->mip_stat = GLP_UNDEF; break;
224.223 + case LPX_I_OPT:
224.224 + lp->mip_stat = GLP_OPT; break;
224.225 + case LPX_I_FEAS:
224.226 + lp->mip_stat = GLP_FEAS; break;
224.227 + case LPX_I_NOFEAS:
224.228 + lp->mip_stat = GLP_NOFEAS; break;
224.229 + default:
224.230 + xerror("lpx_put_mip_soln: i_stat = %d; invalid mixed intege"
224.231 + "r status\n", i_stat);
224.232 + }
224.233 +#endif
224.234 + /* store row solution components */
224.235 + if (row_mipx != NULL)
224.236 + { for (i = 1; i <= lp->m; i++)
224.237 + { row = lp->row[i];
224.238 + row->mipx = row_mipx[i];
224.239 + }
224.240 + }
224.241 + /* store column solution components */
224.242 + if (col_mipx != NULL)
224.243 + { for (j = 1; j <= lp->n; j++)
224.244 + { col = lp->col[j];
224.245 + col->mipx = col_mipx[j];
224.246 + }
224.247 + }
224.248 + /* if the solution is claimed to be integer feasible, check it */
224.249 + if (lp->mip_stat == GLP_OPT || lp->mip_stat == GLP_FEAS)
224.250 + { for (j = 1; j <= lp->n; j++)
224.251 + { col = lp->col[j];
224.252 + if (col->kind == GLP_IV && col->mipx != floor(col->mipx))
224.253 + xerror("lpx_put_mip_soln: col_mipx[%d] = %.*g; must be i"
224.254 + "ntegral\n", j, DBL_DIG, col->mipx);
224.255 + }
224.256 + }
224.257 + /* compute the objective function value */
224.258 + sum = lp->c0;
224.259 + for (j = 1; j <= lp->n; j++)
224.260 + { col = lp->col[j];
224.261 + sum += col->coef * col->mipx;
224.262 + }
224.263 + lp->mip_obj = sum;
224.264 + return;
224.265 +}
224.266 +
224.267 +/* eof */
225.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
225.2 +++ b/src/glplpx03.c Mon Dec 06 13:09:21 2010 +0100
225.3 @@ -0,0 +1,302 @@
225.4 +/* glplpx03.c (OPB format) */
225.5 +
225.6 +/***********************************************************************
225.7 +* This code is part of GLPK (GNU Linear Programming Kit).
225.8 +*
225.9 +* Author: Oscar Gustafsson <oscarg@isy.liu.se>.
225.10 +*
225.11 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
225.12 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
225.13 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
225.14 +* E-mail: <mao@gnu.org>.
225.15 +*
225.16 +* GLPK is free software: you can redistribute it and/or modify it
225.17 +* under the terms of the GNU General Public License as published by
225.18 +* the Free Software Foundation, either version 3 of the License, or
225.19 +* (at your option) any later version.
225.20 +*
225.21 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
225.22 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
225.23 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
225.24 +* License for more details.
225.25 +*
225.26 +* You should have received a copy of the GNU General Public License
225.27 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
225.28 +***********************************************************************/
225.29 +
225.30 +#define _GLPSTD_ERRNO
225.31 +#define _GLPSTD_STDIO
225.32 +#include "glpapi.h"
225.33 +#if 0 /* 24/XII-2009; by mao */
225.34 +#include "glpipp.h"
225.35 +#endif
225.36 +
225.37 +/*----------------------------------------------------------------------
225.38 +-- lpx_write_pb - write problem data in (normalized) OPB format.
225.39 +--
225.40 +-- *Synopsis*
225.41 +--
225.42 +-- #include "glplpx.h"
225.43 +-- int lpx_write_pb(LPX *lp, const char *fname, int normalized,
225.44 +-- int binarize);
225.45 +--
225.46 +-- *Description*
225.47 +--
225.48 +-- The routine lpx_write_pb writes problem data in OPB format
225.49 +-- to an output text file whose name is the character string fname.
225.50 +-- If normalized is non-zero the output will be generated in a
225.51 +-- normalized form with sequentially numbered variables, x1, x2 etc.
225.52 +-- If binarize, any integer variable will be repalzec by binary ones,
225.53 +-- see ipp_binarize
225.54 +--
225.55 +-- *Returns*
225.56 +--
225.57 +-- If the operation was successful, the routine returns zero. Otherwise
225.58 +-- the routine prints an error message and returns non-zero. */
225.59 +
225.60 +#if 1 /* 24/XII-2009; by mao (disabled, because IPP was removed) */
225.61 +int lpx_write_pb(LPX *lp, const char *fname, int normalized,
225.62 + int binarize)
225.63 +{ xassert(lp == lp);
225.64 + xassert(fname == fname);
225.65 + xassert(normalized == normalized);
225.66 + xassert(binarize == binarize);
225.67 + xprintf("lpx_write_pb: sorry, currently this operation is not ava"
225.68 + "ilable\n");
225.69 + return 1;
225.70 +}
225.71 +#else
225.72 +int lpx_write_pb(LPX *lp, const char *fname, int normalized,
225.73 + int binarize)
225.74 +{
225.75 + FILE* fp;
225.76 + int m,n,i,j,k,o,nonfree=0, obj_dir, dbl, *ndx, row_type, emptylhs=0;
225.77 + double coeff, *val, bound, constant/*=0.0*/;
225.78 + char* objconstname = "dummy_one";
225.79 + char* emptylhsname = "dummy_zero";
225.80 +
225.81 + /* Variables needed for possible binarization */
225.82 + /*LPX* tlp;*/
225.83 + IPP *ipp = NULL;
225.84 + /*tlp=lp;*/
225.85 +
225.86 + if(binarize) /* Transform integer variables to binary ones */
225.87 + {
225.88 + ipp = ipp_create_wksp();
225.89 + ipp_load_orig(ipp, lp);
225.90 + ipp_binarize(ipp);
225.91 + lp = ipp_build_prob(ipp);
225.92 + }
225.93 + fp = fopen(fname, "w");
225.94 +
225.95 + if(fp!= NULL)
225.96 + {
225.97 + xprintf(
225.98 + "lpx_write_pb: writing problem in %sOPB format to `%s'...\n",
225.99 + (normalized?"normalized ":""), fname);
225.100 +
225.101 + m = glp_get_num_rows(lp);
225.102 + n = glp_get_num_cols(lp);
225.103 + for(i=1;i<=m;i++)
225.104 + {
225.105 + switch(glp_get_row_type(lp,i))
225.106 + {
225.107 + case GLP_LO:
225.108 + case GLP_UP:
225.109 + case GLP_FX:
225.110 + {
225.111 + nonfree += 1;
225.112 + break;
225.113 + }
225.114 + case GLP_DB:
225.115 + {
225.116 + nonfree += 2;
225.117 + break;
225.118 + }
225.119 + }
225.120 + }
225.121 + constant=glp_get_obj_coef(lp,0);
225.122 + fprintf(fp,"* #variables = %d #constraints = %d\n",
225.123 + n + (constant == 0?1:0), nonfree + (constant == 0?1:0));
225.124 + /* Objective function */
225.125 + obj_dir = glp_get_obj_dir(lp);
225.126 + fprintf(fp,"min: ");
225.127 + for(i=1;i<=n;i++)
225.128 + {
225.129 + coeff = glp_get_obj_coef(lp,i);
225.130 + if(coeff != 0.0)
225.131 + {
225.132 + if(obj_dir == GLP_MAX)
225.133 + coeff=-coeff;
225.134 + if(normalized)
225.135 + fprintf(fp, " %d x%d", (int)coeff, i);
225.136 + else
225.137 + fprintf(fp, " %d*%s", (int)coeff,
225.138 + glp_get_col_name(lp,i));
225.139 +
225.140 + }
225.141 + }
225.142 + if(constant)
225.143 + {
225.144 + if(normalized)
225.145 + fprintf(fp, " %d x%d", (int)constant, n+1);
225.146 + else
225.147 + fprintf(fp, " %d*%s", (int)constant, objconstname);
225.148 + }
225.149 + fprintf(fp,";\n");
225.150 +
225.151 + if(normalized && !binarize) /* Name substitution */
225.152 + {
225.153 + fprintf(fp,"* Variable name substitution:\n");
225.154 + for(j=1;j<=n;j++)
225.155 + {
225.156 + fprintf(fp, "* x%d = %s\n", j, glp_get_col_name(lp,j));
225.157 + }
225.158 + if(constant)
225.159 + fprintf(fp, "* x%d = %s\n", n+1, objconstname);
225.160 + }
225.161 +
225.162 + ndx = xcalloc(1+n, sizeof(int));
225.163 + val = xcalloc(1+n, sizeof(double));
225.164 +
225.165 + /* Constraints */
225.166 + for(j=1;j<=m;j++)
225.167 + {
225.168 + row_type=glp_get_row_type(lp,j);
225.169 + if(row_type!=GLP_FR)
225.170 + {
225.171 + if(row_type == GLP_DB)
225.172 + {
225.173 + dbl=2;
225.174 + row_type = GLP_UP;
225.175 + }
225.176 + else
225.177 + {
225.178 + dbl=1;
225.179 + }
225.180 + k=glp_get_mat_row(lp, j, ndx, val);
225.181 + for(o=1;o<=dbl;o++)
225.182 + {
225.183 + if(o==2)
225.184 + {
225.185 + row_type = GLP_LO;
225.186 + }
225.187 + if(k==0) /* Empty LHS */
225.188 + {
225.189 + emptylhs = 1;
225.190 + if(normalized)
225.191 + {
225.192 + fprintf(fp, "0 x%d ", n+2);
225.193 + }
225.194 + else
225.195 + {
225.196 + fprintf(fp, "0*%s ", emptylhsname);
225.197 + }
225.198 + }
225.199 +
225.200 + for(i=1;i<=k;i++)
225.201 + {
225.202 + if(val[i] != 0.0)
225.203 + {
225.204 +
225.205 + if(normalized)
225.206 + {
225.207 + fprintf(fp, "%d x%d ",
225.208 + (row_type==GLP_UP)?(-(int)val[i]):((int)val[i]), ndx[i]);
225.209 + }
225.210 + else
225.211 + {
225.212 + fprintf(fp, "%d*%s ", (int)val[i],
225.213 + glp_get_col_name(lp,ndx[i]));
225.214 + }
225.215 + }
225.216 + }
225.217 + switch(row_type)
225.218 + {
225.219 + case GLP_LO:
225.220 + {
225.221 + fprintf(fp, ">=");
225.222 + bound = glp_get_row_lb(lp,j);
225.223 + break;
225.224 + }
225.225 + case GLP_UP:
225.226 + {
225.227 + if(normalized)
225.228 + {
225.229 + fprintf(fp, ">=");
225.230 + bound = -glp_get_row_ub(lp,j);
225.231 + }
225.232 + else
225.233 + {
225.234 + fprintf(fp, "<=");
225.235 + bound = glp_get_row_ub(lp,j);
225.236 + }
225.237 +
225.238 + break;
225.239 + }
225.240 + case GLP_FX:
225.241 + {
225.242 + fprintf(fp, "=");
225.243 + bound = glp_get_row_lb(lp,j);
225.244 + break;
225.245 + }
225.246 + }
225.247 + fprintf(fp," %d;\n",(int)bound);
225.248 + }
225.249 + }
225.250 + }
225.251 + xfree(ndx);
225.252 + xfree(val);
225.253 +
225.254 + if(constant)
225.255 + {
225.256 + xprintf(
225.257 + "lpx_write_pb: adding constant objective function variable\n");
225.258 +
225.259 + if(normalized)
225.260 + fprintf(fp, "1 x%d = 1;\n", n+1);
225.261 + else
225.262 + fprintf(fp, "1*%s = 1;\n", objconstname);
225.263 + }
225.264 + if(emptylhs)
225.265 + {
225.266 + xprintf(
225.267 + "lpx_write_pb: adding dummy variable for empty left-hand si"
225.268 + "de constraint\n");
225.269 +
225.270 + if(normalized)
225.271 + fprintf(fp, "1 x%d = 0;\n", n+2);
225.272 + else
225.273 + fprintf(fp, "1*%s = 0;\n", emptylhsname);
225.274 + }
225.275 +
225.276 + }
225.277 + else
225.278 + {
225.279 + xprintf("Problems opening file for writing: %s\n", fname);
225.280 + return(1);
225.281 + }
225.282 + fflush(fp);
225.283 + if (ferror(fp))
225.284 + { xprintf("lpx_write_pb: can't write to `%s' - %s\n", fname,
225.285 + strerror(errno));
225.286 + goto fail;
225.287 + }
225.288 + fclose(fp);
225.289 +
225.290 +
225.291 + if(binarize)
225.292 + {
225.293 + /* delete the resultant problem object */
225.294 + if (lp != NULL) lpx_delete_prob(lp);
225.295 + /* delete MIP presolver workspace */
225.296 + if (ipp != NULL) ipp_delete_wksp(ipp);
225.297 + /*lp=tlp;*/
225.298 + }
225.299 + return 0;
225.300 + fail: if (fp != NULL) fclose(fp);
225.301 + return 1;
225.302 +}
225.303 +#endif
225.304 +
225.305 +/* eof */
226.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
226.2 +++ b/src/glpluf.c Mon Dec 06 13:09:21 2010 +0100
226.3 @@ -0,0 +1,1846 @@
226.4 +/* glpluf.c (LU-factorization) */
226.5 +
226.6 +/***********************************************************************
226.7 +* This code is part of GLPK (GNU Linear Programming Kit).
226.8 +*
226.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
226.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
226.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
226.12 +* E-mail: <mao@gnu.org>.
226.13 +*
226.14 +* GLPK is free software: you can redistribute it and/or modify it
226.15 +* under the terms of the GNU General Public License as published by
226.16 +* the Free Software Foundation, either version 3 of the License, or
226.17 +* (at your option) any later version.
226.18 +*
226.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
226.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
226.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
226.22 +* License for more details.
226.23 +*
226.24 +* You should have received a copy of the GNU General Public License
226.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
226.26 +***********************************************************************/
226.27 +
226.28 +#include "glpenv.h"
226.29 +#include "glpluf.h"
226.30 +#define xfault xerror
226.31 +
226.32 +/* CAUTION: DO NOT CHANGE THE LIMIT BELOW */
226.33 +
226.34 +#define N_MAX 100000000 /* = 100*10^6 */
226.35 +/* maximal order of the original matrix */
226.36 +
226.37 +/***********************************************************************
226.38 +* NAME
226.39 +*
226.40 +* luf_create_it - create LU-factorization
226.41 +*
226.42 +* SYNOPSIS
226.43 +*
226.44 +* #include "glpluf.h"
226.45 +* LUF *luf_create_it(void);
226.46 +*
226.47 +* DESCRIPTION
226.48 +*
226.49 +* The routine luf_create_it creates a program object, which represents
226.50 +* LU-factorization of a square matrix.
226.51 +*
226.52 +* RETURNS
226.53 +*
226.54 +* The routine luf_create_it returns a pointer to the object created. */
226.55 +
226.56 +LUF *luf_create_it(void)
226.57 +{ LUF *luf;
226.58 + luf = xmalloc(sizeof(LUF));
226.59 + luf->n_max = luf->n = 0;
226.60 + luf->valid = 0;
226.61 + luf->fr_ptr = luf->fr_len = NULL;
226.62 + luf->fc_ptr = luf->fc_len = NULL;
226.63 + luf->vr_ptr = luf->vr_len = luf->vr_cap = NULL;
226.64 + luf->vr_piv = NULL;
226.65 + luf->vc_ptr = luf->vc_len = luf->vc_cap = NULL;
226.66 + luf->pp_row = luf->pp_col = NULL;
226.67 + luf->qq_row = luf->qq_col = NULL;
226.68 + luf->sv_size = 0;
226.69 + luf->sv_beg = luf->sv_end = 0;
226.70 + luf->sv_ind = NULL;
226.71 + luf->sv_val = NULL;
226.72 + luf->sv_head = luf->sv_tail = 0;
226.73 + luf->sv_prev = luf->sv_next = NULL;
226.74 + luf->vr_max = NULL;
226.75 + luf->rs_head = luf->rs_prev = luf->rs_next = NULL;
226.76 + luf->cs_head = luf->cs_prev = luf->cs_next = NULL;
226.77 + luf->flag = NULL;
226.78 + luf->work = NULL;
226.79 + luf->new_sva = 0;
226.80 + luf->piv_tol = 0.10;
226.81 + luf->piv_lim = 4;
226.82 + luf->suhl = 1;
226.83 + luf->eps_tol = 1e-15;
226.84 + luf->max_gro = 1e+10;
226.85 + luf->nnz_a = luf->nnz_f = luf->nnz_v = 0;
226.86 + luf->max_a = luf->big_v = 0.0;
226.87 + luf->rank = 0;
226.88 + return luf;
226.89 +}
226.90 +
226.91 +/***********************************************************************
226.92 +* NAME
226.93 +*
226.94 +* luf_defrag_sva - defragment the sparse vector area
226.95 +*
226.96 +* SYNOPSIS
226.97 +*
226.98 +* #include "glpluf.h"
226.99 +* void luf_defrag_sva(LUF *luf);
226.100 +*
226.101 +* DESCRIPTION
226.102 +*
226.103 +* The routine luf_defrag_sva defragments the sparse vector area (SVA)
226.104 +* gathering all unused locations in one continuous extent. In order to
226.105 +* do that the routine moves all unused locations from the left part of
226.106 +* SVA (which contains rows and columns of the matrix V) to the middle
226.107 +* part (which contains free locations). This is attained by relocating
226.108 +* elements of rows and columns of the matrix V toward the beginning of
226.109 +* the left part.
226.110 +*
226.111 +* NOTE that this "garbage collection" involves changing row and column
226.112 +* pointers of the matrix V. */
226.113 +
226.114 +void luf_defrag_sva(LUF *luf)
226.115 +{ int n = luf->n;
226.116 + int *vr_ptr = luf->vr_ptr;
226.117 + int *vr_len = luf->vr_len;
226.118 + int *vr_cap = luf->vr_cap;
226.119 + int *vc_ptr = luf->vc_ptr;
226.120 + int *vc_len = luf->vc_len;
226.121 + int *vc_cap = luf->vc_cap;
226.122 + int *sv_ind = luf->sv_ind;
226.123 + double *sv_val = luf->sv_val;
226.124 + int *sv_next = luf->sv_next;
226.125 + int sv_beg = 1;
226.126 + int i, j, k;
226.127 + /* skip rows and columns, which do not need to be relocated */
226.128 + for (k = luf->sv_head; k != 0; k = sv_next[k])
226.129 + { if (k <= n)
226.130 + { /* i-th row of the matrix V */
226.131 + i = k;
226.132 + if (vr_ptr[i] != sv_beg) break;
226.133 + vr_cap[i] = vr_len[i];
226.134 + sv_beg += vr_cap[i];
226.135 + }
226.136 + else
226.137 + { /* j-th column of the matrix V */
226.138 + j = k - n;
226.139 + if (vc_ptr[j] != sv_beg) break;
226.140 + vc_cap[j] = vc_len[j];
226.141 + sv_beg += vc_cap[j];
226.142 + }
226.143 + }
226.144 + /* relocate other rows and columns in order to gather all unused
226.145 + locations in one continuous extent */
226.146 + for (k = k; k != 0; k = sv_next[k])
226.147 + { if (k <= n)
226.148 + { /* i-th row of the matrix V */
226.149 + i = k;
226.150 + memmove(&sv_ind[sv_beg], &sv_ind[vr_ptr[i]],
226.151 + vr_len[i] * sizeof(int));
226.152 + memmove(&sv_val[sv_beg], &sv_val[vr_ptr[i]],
226.153 + vr_len[i] * sizeof(double));
226.154 + vr_ptr[i] = sv_beg;
226.155 + vr_cap[i] = vr_len[i];
226.156 + sv_beg += vr_cap[i];
226.157 + }
226.158 + else
226.159 + { /* j-th column of the matrix V */
226.160 + j = k - n;
226.161 + memmove(&sv_ind[sv_beg], &sv_ind[vc_ptr[j]],
226.162 + vc_len[j] * sizeof(int));
226.163 + memmove(&sv_val[sv_beg], &sv_val[vc_ptr[j]],
226.164 + vc_len[j] * sizeof(double));
226.165 + vc_ptr[j] = sv_beg;
226.166 + vc_cap[j] = vc_len[j];
226.167 + sv_beg += vc_cap[j];
226.168 + }
226.169 + }
226.170 + /* set new pointer to the beginning of the free part */
226.171 + luf->sv_beg = sv_beg;
226.172 + return;
226.173 +}
226.174 +
226.175 +/***********************************************************************
226.176 +* NAME
226.177 +*
226.178 +* luf_enlarge_row - enlarge row capacity
226.179 +*
226.180 +* SYNOPSIS
226.181 +*
226.182 +* #include "glpluf.h"
226.183 +* int luf_enlarge_row(LUF *luf, int i, int cap);
226.184 +*
226.185 +* DESCRIPTION
226.186 +*
226.187 +* The routine luf_enlarge_row enlarges capacity of the i-th row of the
226.188 +* matrix V to cap locations (assuming that its current capacity is less
226.189 +* than cap). In order to do that the routine relocates elements of the
226.190 +* i-th row to the end of the left part of SVA (which contains rows and
226.191 +* columns of the matrix V) and then expands the left part by allocating
226.192 +* cap free locations from the free part. If there are less than cap
226.193 +* free locations, the routine defragments the sparse vector area.
226.194 +*
226.195 +* Due to "garbage collection" this operation may change row and column
226.196 +* pointers of the matrix V.
226.197 +*
226.198 +* RETURNS
226.199 +*
226.200 +* If no error occured, the routine returns zero. Otherwise, in case of
226.201 +* overflow of the sparse vector area, the routine returns non-zero. */
226.202 +
226.203 +int luf_enlarge_row(LUF *luf, int i, int cap)
226.204 +{ int n = luf->n;
226.205 + int *vr_ptr = luf->vr_ptr;
226.206 + int *vr_len = luf->vr_len;
226.207 + int *vr_cap = luf->vr_cap;
226.208 + int *vc_cap = luf->vc_cap;
226.209 + int *sv_ind = luf->sv_ind;
226.210 + double *sv_val = luf->sv_val;
226.211 + int *sv_prev = luf->sv_prev;
226.212 + int *sv_next = luf->sv_next;
226.213 + int ret = 0;
226.214 + int cur, k, kk;
226.215 + xassert(1 <= i && i <= n);
226.216 + xassert(vr_cap[i] < cap);
226.217 + /* if there are less than cap free locations, defragment SVA */
226.218 + if (luf->sv_end - luf->sv_beg < cap)
226.219 + { luf_defrag_sva(luf);
226.220 + if (luf->sv_end - luf->sv_beg < cap)
226.221 + { ret = 1;
226.222 + goto done;
226.223 + }
226.224 + }
226.225 + /* save current capacity of the i-th row */
226.226 + cur = vr_cap[i];
226.227 + /* copy existing elements to the beginning of the free part */
226.228 + memmove(&sv_ind[luf->sv_beg], &sv_ind[vr_ptr[i]],
226.229 + vr_len[i] * sizeof(int));
226.230 + memmove(&sv_val[luf->sv_beg], &sv_val[vr_ptr[i]],
226.231 + vr_len[i] * sizeof(double));
226.232 + /* set new pointer and new capacity of the i-th row */
226.233 + vr_ptr[i] = luf->sv_beg;
226.234 + vr_cap[i] = cap;
226.235 + /* set new pointer to the beginning of the free part */
226.236 + luf->sv_beg += cap;
226.237 + /* now the i-th row starts in the rightmost location among other
226.238 + rows and columns of the matrix V, so its node should be moved
226.239 + to the end of the row/column linked list */
226.240 + k = i;
226.241 + /* remove the i-th row node from the linked list */
226.242 + if (sv_prev[k] == 0)
226.243 + luf->sv_head = sv_next[k];
226.244 + else
226.245 + { /* capacity of the previous row/column can be increased at the
226.246 + expense of old locations of the i-th row */
226.247 + kk = sv_prev[k];
226.248 + if (kk <= n) vr_cap[kk] += cur; else vc_cap[kk-n] += cur;
226.249 + sv_next[sv_prev[k]] = sv_next[k];
226.250 + }
226.251 + if (sv_next[k] == 0)
226.252 + luf->sv_tail = sv_prev[k];
226.253 + else
226.254 + sv_prev[sv_next[k]] = sv_prev[k];
226.255 + /* insert the i-th row node to the end of the linked list */
226.256 + sv_prev[k] = luf->sv_tail;
226.257 + sv_next[k] = 0;
226.258 + if (sv_prev[k] == 0)
226.259 + luf->sv_head = k;
226.260 + else
226.261 + sv_next[sv_prev[k]] = k;
226.262 + luf->sv_tail = k;
226.263 +done: return ret;
226.264 +}
226.265 +
226.266 +/***********************************************************************
226.267 +* NAME
226.268 +*
226.269 +* luf_enlarge_col - enlarge column capacity
226.270 +*
226.271 +* SYNOPSIS
226.272 +*
226.273 +* #include "glpluf.h"
226.274 +* int luf_enlarge_col(LUF *luf, int j, int cap);
226.275 +*
226.276 +* DESCRIPTION
226.277 +*
226.278 +* The routine luf_enlarge_col enlarges capacity of the j-th column of
226.279 +* the matrix V to cap locations (assuming that its current capacity is
226.280 +* less than cap). In order to do that the routine relocates elements
226.281 +* of the j-th column to the end of the left part of SVA (which contains
226.282 +* rows and columns of the matrix V) and then expands the left part by
226.283 +* allocating cap free locations from the free part. If there are less
226.284 +* than cap free locations, the routine defragments the sparse vector
226.285 +* area.
226.286 +*
226.287 +* Due to "garbage collection" this operation may change row and column
226.288 +* pointers of the matrix V.
226.289 +*
226.290 +* RETURNS
226.291 +*
226.292 +* If no error occured, the routine returns zero. Otherwise, in case of
226.293 +* overflow of the sparse vector area, the routine returns non-zero. */
226.294 +
226.295 +int luf_enlarge_col(LUF *luf, int j, int cap)
226.296 +{ int n = luf->n;
226.297 + int *vr_cap = luf->vr_cap;
226.298 + int *vc_ptr = luf->vc_ptr;
226.299 + int *vc_len = luf->vc_len;
226.300 + int *vc_cap = luf->vc_cap;
226.301 + int *sv_ind = luf->sv_ind;
226.302 + double *sv_val = luf->sv_val;
226.303 + int *sv_prev = luf->sv_prev;
226.304 + int *sv_next = luf->sv_next;
226.305 + int ret = 0;
226.306 + int cur, k, kk;
226.307 + xassert(1 <= j && j <= n);
226.308 + xassert(vc_cap[j] < cap);
226.309 + /* if there are less than cap free locations, defragment SVA */
226.310 + if (luf->sv_end - luf->sv_beg < cap)
226.311 + { luf_defrag_sva(luf);
226.312 + if (luf->sv_end - luf->sv_beg < cap)
226.313 + { ret = 1;
226.314 + goto done;
226.315 + }
226.316 + }
226.317 + /* save current capacity of the j-th column */
226.318 + cur = vc_cap[j];
226.319 + /* copy existing elements to the beginning of the free part */
226.320 + memmove(&sv_ind[luf->sv_beg], &sv_ind[vc_ptr[j]],
226.321 + vc_len[j] * sizeof(int));
226.322 + memmove(&sv_val[luf->sv_beg], &sv_val[vc_ptr[j]],
226.323 + vc_len[j] * sizeof(double));
226.324 + /* set new pointer and new capacity of the j-th column */
226.325 + vc_ptr[j] = luf->sv_beg;
226.326 + vc_cap[j] = cap;
226.327 + /* set new pointer to the beginning of the free part */
226.328 + luf->sv_beg += cap;
226.329 + /* now the j-th column starts in the rightmost location among
226.330 + other rows and columns of the matrix V, so its node should be
226.331 + moved to the end of the row/column linked list */
226.332 + k = n + j;
226.333 + /* remove the j-th column node from the linked list */
226.334 + if (sv_prev[k] == 0)
226.335 + luf->sv_head = sv_next[k];
226.336 + else
226.337 + { /* capacity of the previous row/column can be increased at the
226.338 + expense of old locations of the j-th column */
226.339 + kk = sv_prev[k];
226.340 + if (kk <= n) vr_cap[kk] += cur; else vc_cap[kk-n] += cur;
226.341 + sv_next[sv_prev[k]] = sv_next[k];
226.342 + }
226.343 + if (sv_next[k] == 0)
226.344 + luf->sv_tail = sv_prev[k];
226.345 + else
226.346 + sv_prev[sv_next[k]] = sv_prev[k];
226.347 + /* insert the j-th column node to the end of the linked list */
226.348 + sv_prev[k] = luf->sv_tail;
226.349 + sv_next[k] = 0;
226.350 + if (sv_prev[k] == 0)
226.351 + luf->sv_head = k;
226.352 + else
226.353 + sv_next[sv_prev[k]] = k;
226.354 + luf->sv_tail = k;
226.355 +done: return ret;
226.356 +}
226.357 +
226.358 +/***********************************************************************
226.359 +* reallocate - reallocate LU-factorization arrays
226.360 +*
226.361 +* This routine reallocates arrays, whose size depends of n, the order
226.362 +* of the matrix A to be factorized. */
226.363 +
226.364 +static void reallocate(LUF *luf, int n)
226.365 +{ int n_max = luf->n_max;
226.366 + luf->n = n;
226.367 + if (n <= n_max) goto done;
226.368 + if (luf->fr_ptr != NULL) xfree(luf->fr_ptr);
226.369 + if (luf->fr_len != NULL) xfree(luf->fr_len);
226.370 + if (luf->fc_ptr != NULL) xfree(luf->fc_ptr);
226.371 + if (luf->fc_len != NULL) xfree(luf->fc_len);
226.372 + if (luf->vr_ptr != NULL) xfree(luf->vr_ptr);
226.373 + if (luf->vr_len != NULL) xfree(luf->vr_len);
226.374 + if (luf->vr_cap != NULL) xfree(luf->vr_cap);
226.375 + if (luf->vr_piv != NULL) xfree(luf->vr_piv);
226.376 + if (luf->vc_ptr != NULL) xfree(luf->vc_ptr);
226.377 + if (luf->vc_len != NULL) xfree(luf->vc_len);
226.378 + if (luf->vc_cap != NULL) xfree(luf->vc_cap);
226.379 + if (luf->pp_row != NULL) xfree(luf->pp_row);
226.380 + if (luf->pp_col != NULL) xfree(luf->pp_col);
226.381 + if (luf->qq_row != NULL) xfree(luf->qq_row);
226.382 + if (luf->qq_col != NULL) xfree(luf->qq_col);
226.383 + if (luf->sv_prev != NULL) xfree(luf->sv_prev);
226.384 + if (luf->sv_next != NULL) xfree(luf->sv_next);
226.385 + if (luf->vr_max != NULL) xfree(luf->vr_max);
226.386 + if (luf->rs_head != NULL) xfree(luf->rs_head);
226.387 + if (luf->rs_prev != NULL) xfree(luf->rs_prev);
226.388 + if (luf->rs_next != NULL) xfree(luf->rs_next);
226.389 + if (luf->cs_head != NULL) xfree(luf->cs_head);
226.390 + if (luf->cs_prev != NULL) xfree(luf->cs_prev);
226.391 + if (luf->cs_next != NULL) xfree(luf->cs_next);
226.392 + if (luf->flag != NULL) xfree(luf->flag);
226.393 + if (luf->work != NULL) xfree(luf->work);
226.394 + luf->n_max = n_max = n + 100;
226.395 + luf->fr_ptr = xcalloc(1+n_max, sizeof(int));
226.396 + luf->fr_len = xcalloc(1+n_max, sizeof(int));
226.397 + luf->fc_ptr = xcalloc(1+n_max, sizeof(int));
226.398 + luf->fc_len = xcalloc(1+n_max, sizeof(int));
226.399 + luf->vr_ptr = xcalloc(1+n_max, sizeof(int));
226.400 + luf->vr_len = xcalloc(1+n_max, sizeof(int));
226.401 + luf->vr_cap = xcalloc(1+n_max, sizeof(int));
226.402 + luf->vr_piv = xcalloc(1+n_max, sizeof(double));
226.403 + luf->vc_ptr = xcalloc(1+n_max, sizeof(int));
226.404 + luf->vc_len = xcalloc(1+n_max, sizeof(int));
226.405 + luf->vc_cap = xcalloc(1+n_max, sizeof(int));
226.406 + luf->pp_row = xcalloc(1+n_max, sizeof(int));
226.407 + luf->pp_col = xcalloc(1+n_max, sizeof(int));
226.408 + luf->qq_row = xcalloc(1+n_max, sizeof(int));
226.409 + luf->qq_col = xcalloc(1+n_max, sizeof(int));
226.410 + luf->sv_prev = xcalloc(1+n_max+n_max, sizeof(int));
226.411 + luf->sv_next = xcalloc(1+n_max+n_max, sizeof(int));
226.412 + luf->vr_max = xcalloc(1+n_max, sizeof(double));
226.413 + luf->rs_head = xcalloc(1+n_max, sizeof(int));
226.414 + luf->rs_prev = xcalloc(1+n_max, sizeof(int));
226.415 + luf->rs_next = xcalloc(1+n_max, sizeof(int));
226.416 + luf->cs_head = xcalloc(1+n_max, sizeof(int));
226.417 + luf->cs_prev = xcalloc(1+n_max, sizeof(int));
226.418 + luf->cs_next = xcalloc(1+n_max, sizeof(int));
226.419 + luf->flag = xcalloc(1+n_max, sizeof(int));
226.420 + luf->work = xcalloc(1+n_max, sizeof(double));
226.421 +done: return;
226.422 +}
226.423 +
226.424 +/***********************************************************************
226.425 +* initialize - initialize LU-factorization data structures
226.426 +*
226.427 +* This routine initializes data structures for subsequent computing
226.428 +* the LU-factorization of a given matrix A, which is specified by the
226.429 +* formal routine col. On exit V = A and F = P = Q = I, where I is the
226.430 +* unity matrix. (Row-wise representation of the matrix F is not used
226.431 +* at the factorization stage and therefore is not initialized.)
226.432 +*
226.433 +* If no error occured, the routine returns zero. Otherwise, in case of
226.434 +* overflow of the sparse vector area, the routine returns non-zero. */
226.435 +
226.436 +static int initialize(LUF *luf, int (*col)(void *info, int j, int rn[],
226.437 + double aj[]), void *info)
226.438 +{ int n = luf->n;
226.439 + int *fc_ptr = luf->fc_ptr;
226.440 + int *fc_len = luf->fc_len;
226.441 + int *vr_ptr = luf->vr_ptr;
226.442 + int *vr_len = luf->vr_len;
226.443 + int *vr_cap = luf->vr_cap;
226.444 + int *vc_ptr = luf->vc_ptr;
226.445 + int *vc_len = luf->vc_len;
226.446 + int *vc_cap = luf->vc_cap;
226.447 + int *pp_row = luf->pp_row;
226.448 + int *pp_col = luf->pp_col;
226.449 + int *qq_row = luf->qq_row;
226.450 + int *qq_col = luf->qq_col;
226.451 + int *sv_ind = luf->sv_ind;
226.452 + double *sv_val = luf->sv_val;
226.453 + int *sv_prev = luf->sv_prev;
226.454 + int *sv_next = luf->sv_next;
226.455 + double *vr_max = luf->vr_max;
226.456 + int *rs_head = luf->rs_head;
226.457 + int *rs_prev = luf->rs_prev;
226.458 + int *rs_next = luf->rs_next;
226.459 + int *cs_head = luf->cs_head;
226.460 + int *cs_prev = luf->cs_prev;
226.461 + int *cs_next = luf->cs_next;
226.462 + int *flag = luf->flag;
226.463 + double *work = luf->work;
226.464 + int ret = 0;
226.465 + int i, i_ptr, j, j_beg, j_end, k, len, nnz, sv_beg, sv_end, ptr;
226.466 + double big, val;
226.467 + /* free all locations of the sparse vector area */
226.468 + sv_beg = 1;
226.469 + sv_end = luf->sv_size + 1;
226.470 + /* (row-wise representation of the matrix F is not initialized,
226.471 + because it is not used at the factorization stage) */
226.472 + /* build the matrix F in column-wise format (initially F = I) */
226.473 + for (j = 1; j <= n; j++)
226.474 + { fc_ptr[j] = sv_end;
226.475 + fc_len[j] = 0;
226.476 + }
226.477 + /* clear rows of the matrix V; clear the flag array */
226.478 + for (i = 1; i <= n; i++)
226.479 + vr_len[i] = vr_cap[i] = 0, flag[i] = 0;
226.480 + /* build the matrix V in column-wise format (initially V = A);
226.481 + count non-zeros in rows of this matrix; count total number of
226.482 + non-zeros; compute largest of absolute values of elements */
226.483 + nnz = 0;
226.484 + big = 0.0;
226.485 + for (j = 1; j <= n; j++)
226.486 + { int *rn = pp_row;
226.487 + double *aj = work;
226.488 + /* obtain j-th column of the matrix A */
226.489 + len = col(info, j, rn, aj);
226.490 + if (!(0 <= len && len <= n))
226.491 + xfault("luf_factorize: j = %d; len = %d; invalid column len"
226.492 + "gth\n", j, len);
226.493 + /* check for free locations */
226.494 + if (sv_end - sv_beg < len)
226.495 + { /* overflow of the sparse vector area */
226.496 + ret = 1;
226.497 + goto done;
226.498 + }
226.499 + /* set pointer to the j-th column */
226.500 + vc_ptr[j] = sv_beg;
226.501 + /* set length of the j-th column */
226.502 + vc_len[j] = vc_cap[j] = len;
226.503 + /* count total number of non-zeros */
226.504 + nnz += len;
226.505 + /* walk through elements of the j-th column */
226.506 + for (ptr = 1; ptr <= len; ptr++)
226.507 + { /* get row index and numerical value of a[i,j] */
226.508 + i = rn[ptr];
226.509 + val = aj[ptr];
226.510 + if (!(1 <= i && i <= n))
226.511 + xfault("luf_factorize: i = %d; j = %d; invalid row index"
226.512 + "\n", i, j);
226.513 + if (flag[i])
226.514 + xfault("luf_factorize: i = %d; j = %d; duplicate element"
226.515 + " not allowed\n", i, j);
226.516 + if (val == 0.0)
226.517 + xfault("luf_factorize: i = %d; j = %d; zero element not "
226.518 + "allowed\n", i, j);
226.519 + /* add new element v[i,j] = a[i,j] to j-th column */
226.520 + sv_ind[sv_beg] = i;
226.521 + sv_val[sv_beg] = val;
226.522 + sv_beg++;
226.523 + /* big := max(big, |a[i,j]|) */
226.524 + if (val < 0.0) val = - val;
226.525 + if (big < val) big = val;
226.526 + /* mark non-zero in the i-th position of the j-th column */
226.527 + flag[i] = 1;
226.528 + /* increase length of the i-th row */
226.529 + vr_cap[i]++;
226.530 + }
226.531 + /* reset all non-zero marks */
226.532 + for (ptr = 1; ptr <= len; ptr++) flag[rn[ptr]] = 0;
226.533 + }
226.534 + /* allocate rows of the matrix V */
226.535 + for (i = 1; i <= n; i++)
226.536 + { /* get length of the i-th row */
226.537 + len = vr_cap[i];
226.538 + /* check for free locations */
226.539 + if (sv_end - sv_beg < len)
226.540 + { /* overflow of the sparse vector area */
226.541 + ret = 1;
226.542 + goto done;
226.543 + }
226.544 + /* set pointer to the i-th row */
226.545 + vr_ptr[i] = sv_beg;
226.546 + /* reserve locations for the i-th row */
226.547 + sv_beg += len;
226.548 + }
226.549 + /* build the matrix V in row-wise format using representation of
226.550 + this matrix in column-wise format */
226.551 + for (j = 1; j <= n; j++)
226.552 + { /* walk through elements of the j-th column */
226.553 + j_beg = vc_ptr[j];
226.554 + j_end = j_beg + vc_len[j] - 1;
226.555 + for (k = j_beg; k <= j_end; k++)
226.556 + { /* get row index and numerical value of v[i,j] */
226.557 + i = sv_ind[k];
226.558 + val = sv_val[k];
226.559 + /* store element in the i-th row */
226.560 + i_ptr = vr_ptr[i] + vr_len[i];
226.561 + sv_ind[i_ptr] = j;
226.562 + sv_val[i_ptr] = val;
226.563 + /* increase count of the i-th row */
226.564 + vr_len[i]++;
226.565 + }
226.566 + }
226.567 + /* initialize the matrices P and Q (initially P = Q = I) */
226.568 + for (k = 1; k <= n; k++)
226.569 + pp_row[k] = pp_col[k] = qq_row[k] = qq_col[k] = k;
226.570 + /* set sva partitioning pointers */
226.571 + luf->sv_beg = sv_beg;
226.572 + luf->sv_end = sv_end;
226.573 + /* the initial physical order of rows and columns of the matrix V
226.574 + is n+1, ..., n+n, 1, ..., n (firstly columns, then rows) */
226.575 + luf->sv_head = n+1;
226.576 + luf->sv_tail = n;
226.577 + for (i = 1; i <= n; i++)
226.578 + { sv_prev[i] = i-1;
226.579 + sv_next[i] = i+1;
226.580 + }
226.581 + sv_prev[1] = n+n;
226.582 + sv_next[n] = 0;
226.583 + for (j = 1; j <= n; j++)
226.584 + { sv_prev[n+j] = n+j-1;
226.585 + sv_next[n+j] = n+j+1;
226.586 + }
226.587 + sv_prev[n+1] = 0;
226.588 + sv_next[n+n] = 1;
226.589 + /* clear working arrays */
226.590 + for (k = 1; k <= n; k++)
226.591 + { flag[k] = 0;
226.592 + work[k] = 0.0;
226.593 + }
226.594 + /* initialize some statistics */
226.595 + luf->nnz_a = nnz;
226.596 + luf->nnz_f = 0;
226.597 + luf->nnz_v = nnz;
226.598 + luf->max_a = big;
226.599 + luf->big_v = big;
226.600 + luf->rank = -1;
226.601 + /* initially the active submatrix is the entire matrix V */
226.602 + /* largest of absolute values of elements in each active row is
226.603 + unknown yet */
226.604 + for (i = 1; i <= n; i++) vr_max[i] = -1.0;
226.605 + /* build linked lists of active rows */
226.606 + for (len = 0; len <= n; len++) rs_head[len] = 0;
226.607 + for (i = 1; i <= n; i++)
226.608 + { len = vr_len[i];
226.609 + rs_prev[i] = 0;
226.610 + rs_next[i] = rs_head[len];
226.611 + if (rs_next[i] != 0) rs_prev[rs_next[i]] = i;
226.612 + rs_head[len] = i;
226.613 + }
226.614 + /* build linked lists of active columns */
226.615 + for (len = 0; len <= n; len++) cs_head[len] = 0;
226.616 + for (j = 1; j <= n; j++)
226.617 + { len = vc_len[j];
226.618 + cs_prev[j] = 0;
226.619 + cs_next[j] = cs_head[len];
226.620 + if (cs_next[j] != 0) cs_prev[cs_next[j]] = j;
226.621 + cs_head[len] = j;
226.622 + }
226.623 +done: /* return to the factorizing routine */
226.624 + return ret;
226.625 +}
226.626 +
226.627 +/***********************************************************************
226.628 +* find_pivot - choose a pivot element
226.629 +*
226.630 +* This routine chooses a pivot element in the active submatrix of the
226.631 +* matrix U = P*V*Q.
226.632 +*
226.633 +* It is assumed that on entry the matrix U has the following partially
226.634 +* triangularized form:
226.635 +*
226.636 +* 1 k n
226.637 +* 1 x x x x x x x x x x
226.638 +* . x x x x x x x x x
226.639 +* . . x x x x x x x x
226.640 +* . . . x x x x x x x
226.641 +* k . . . . * * * * * *
226.642 +* . . . . * * * * * *
226.643 +* . . . . * * * * * *
226.644 +* . . . . * * * * * *
226.645 +* . . . . * * * * * *
226.646 +* n . . . . * * * * * *
226.647 +*
226.648 +* where rows and columns k, k+1, ..., n belong to the active submatrix
226.649 +* (elements of the active submatrix are marked by '*').
226.650 +*
226.651 +* Since the matrix U = P*V*Q is not stored, the routine works with the
226.652 +* matrix V. It is assumed that the row-wise representation corresponds
226.653 +* to the matrix V, but the column-wise representation corresponds to
226.654 +* the active submatrix of the matrix V, i.e. elements of the matrix V,
226.655 +* which doesn't belong to the active submatrix, are missing from the
226.656 +* column linked lists. It is also assumed that each active row of the
226.657 +* matrix V is in the set R[len], where len is number of non-zeros in
226.658 +* the row, and each active column of the matrix V is in the set C[len],
226.659 +* where len is number of non-zeros in the column (in the latter case
226.660 +* only elements of the active submatrix are counted; such elements are
226.661 +* marked by '*' on the figure above).
226.662 +*
226.663 +* For the reason of numerical stability the routine applies so called
226.664 +* threshold pivoting proposed by J.Reid. It is assumed that an element
226.665 +* v[i,j] can be selected as a pivot candidate if it is not very small
226.666 +* (in absolute value) among other elements in the same row, i.e. if it
226.667 +* satisfies to the stability condition |v[i,j]| >= tol * max|v[i,*]|,
226.668 +* where 0 < tol < 1 is a given tolerance.
226.669 +*
226.670 +* In order to keep sparsity of the matrix V the routine uses Markowitz
226.671 +* strategy, trying to choose such element v[p,q], which satisfies to
226.672 +* the stability condition (see above) and has smallest Markowitz cost
226.673 +* (nr[p]-1) * (nc[q]-1), where nr[p] and nc[q] are numbers of non-zero
226.674 +* elements, respectively, in the p-th row and in the q-th column of the
226.675 +* active submatrix.
226.676 +*
226.677 +* In order to reduce the search, i.e. not to walk through all elements
226.678 +* of the active submatrix, the routine exploits a technique proposed by
226.679 +* I.Duff. This technique is based on using the sets R[len] and C[len]
226.680 +* of active rows and columns.
226.681 +*
226.682 +* If the pivot element v[p,q] has been chosen, the routine stores its
226.683 +* indices to the locations *p and *q and returns zero. Otherwise, if
226.684 +* the active submatrix is empty and therefore the pivot element can't
226.685 +* be chosen, the routine returns non-zero. */
226.686 +
226.687 +static int find_pivot(LUF *luf, int *_p, int *_q)
226.688 +{ int n = luf->n;
226.689 + int *vr_ptr = luf->vr_ptr;
226.690 + int *vr_len = luf->vr_len;
226.691 + int *vc_ptr = luf->vc_ptr;
226.692 + int *vc_len = luf->vc_len;
226.693 + int *sv_ind = luf->sv_ind;
226.694 + double *sv_val = luf->sv_val;
226.695 + double *vr_max = luf->vr_max;
226.696 + int *rs_head = luf->rs_head;
226.697 + int *rs_next = luf->rs_next;
226.698 + int *cs_head = luf->cs_head;
226.699 + int *cs_prev = luf->cs_prev;
226.700 + int *cs_next = luf->cs_next;
226.701 + double piv_tol = luf->piv_tol;
226.702 + int piv_lim = luf->piv_lim;
226.703 + int suhl = luf->suhl;
226.704 + int p, q, len, i, i_beg, i_end, i_ptr, j, j_beg, j_end, j_ptr,
226.705 + ncand, next_j, min_p, min_q, min_len;
226.706 + double best, cost, big, temp;
226.707 + /* initially no pivot candidates have been found so far */
226.708 + p = q = 0, best = DBL_MAX, ncand = 0;
226.709 + /* if in the active submatrix there is a column that has the only
226.710 + non-zero (column singleton), choose it as pivot */
226.711 + j = cs_head[1];
226.712 + if (j != 0)
226.713 + { xassert(vc_len[j] == 1);
226.714 + p = sv_ind[vc_ptr[j]], q = j;
226.715 + goto done;
226.716 + }
226.717 + /* if in the active submatrix there is a row that has the only
226.718 + non-zero (row singleton), choose it as pivot */
226.719 + i = rs_head[1];
226.720 + if (i != 0)
226.721 + { xassert(vr_len[i] == 1);
226.722 + p = i, q = sv_ind[vr_ptr[i]];
226.723 + goto done;
226.724 + }
226.725 + /* there are no singletons in the active submatrix; walk through
226.726 + other non-empty rows and columns */
226.727 + for (len = 2; len <= n; len++)
226.728 + { /* consider active columns that have len non-zeros */
226.729 + for (j = cs_head[len]; j != 0; j = next_j)
226.730 + { /* the j-th column has len non-zeros */
226.731 + j_beg = vc_ptr[j];
226.732 + j_end = j_beg + vc_len[j] - 1;
226.733 + /* save pointer to the next column with the same length */
226.734 + next_j = cs_next[j];
226.735 + /* find an element in the j-th column, which is placed in a
226.736 + row with minimal number of non-zeros and satisfies to the
226.737 + stability condition (such element may not exist) */
226.738 + min_p = min_q = 0, min_len = INT_MAX;
226.739 + for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
226.740 + { /* get row index of v[i,j] */
226.741 + i = sv_ind[j_ptr];
226.742 + i_beg = vr_ptr[i];
226.743 + i_end = i_beg + vr_len[i] - 1;
226.744 + /* if the i-th row is not shorter than that one, where
226.745 + minimal element is currently placed, skip v[i,j] */
226.746 + if (vr_len[i] >= min_len) continue;
226.747 + /* determine the largest of absolute values of elements
226.748 + in the i-th row */
226.749 + big = vr_max[i];
226.750 + if (big < 0.0)
226.751 + { /* the largest value is unknown yet; compute it */
226.752 + for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
226.753 + { temp = sv_val[i_ptr];
226.754 + if (temp < 0.0) temp = - temp;
226.755 + if (big < temp) big = temp;
226.756 + }
226.757 + vr_max[i] = big;
226.758 + }
226.759 + /* find v[i,j] in the i-th row */
226.760 + for (i_ptr = vr_ptr[i]; sv_ind[i_ptr] != j; i_ptr++);
226.761 + xassert(i_ptr <= i_end);
226.762 + /* if v[i,j] doesn't satisfy to the stability condition,
226.763 + skip it */
226.764 + temp = sv_val[i_ptr];
226.765 + if (temp < 0.0) temp = - temp;
226.766 + if (temp < piv_tol * big) continue;
226.767 + /* v[i,j] is better than the current minimal element */
226.768 + min_p = i, min_q = j, min_len = vr_len[i];
226.769 + /* if Markowitz cost of the current minimal element is
226.770 + not greater than (len-1)**2, it can be chosen right
226.771 + now; this heuristic reduces the search and works well
226.772 + in many cases */
226.773 + if (min_len <= len)
226.774 + { p = min_p, q = min_q;
226.775 + goto done;
226.776 + }
226.777 + }
226.778 + /* the j-th column has been scanned */
226.779 + if (min_p != 0)
226.780 + { /* the minimal element is a next pivot candidate */
226.781 + ncand++;
226.782 + /* compute its Markowitz cost */
226.783 + cost = (double)(min_len - 1) * (double)(len - 1);
226.784 + /* choose between the minimal element and the current
226.785 + candidate */
226.786 + if (cost < best) p = min_p, q = min_q, best = cost;
226.787 + /* if piv_lim candidates have been considered, there are
226.788 + doubts that a much better candidate exists; therefore
226.789 + it's time to terminate the search */
226.790 + if (ncand == piv_lim) goto done;
226.791 + }
226.792 + else
226.793 + { /* the j-th column has no elements, which satisfy to the
226.794 + stability condition; Uwe Suhl suggests to exclude such
226.795 + column from the further consideration until it becomes
226.796 + a column singleton; in hard cases this significantly
226.797 + reduces a time needed for pivot searching */
226.798 + if (suhl)
226.799 + { /* remove the j-th column from the active set */
226.800 + if (cs_prev[j] == 0)
226.801 + cs_head[len] = cs_next[j];
226.802 + else
226.803 + cs_next[cs_prev[j]] = cs_next[j];
226.804 + if (cs_next[j] == 0)
226.805 + /* nop */;
226.806 + else
226.807 + cs_prev[cs_next[j]] = cs_prev[j];
226.808 + /* the following assignment is used to avoid an error
226.809 + when the routine eliminate (see below) will try to
226.810 + remove the j-th column from the active set */
226.811 + cs_prev[j] = cs_next[j] = j;
226.812 + }
226.813 + }
226.814 + }
226.815 + /* consider active rows that have len non-zeros */
226.816 + for (i = rs_head[len]; i != 0; i = rs_next[i])
226.817 + { /* the i-th row has len non-zeros */
226.818 + i_beg = vr_ptr[i];
226.819 + i_end = i_beg + vr_len[i] - 1;
226.820 + /* determine the largest of absolute values of elements in
226.821 + the i-th row */
226.822 + big = vr_max[i];
226.823 + if (big < 0.0)
226.824 + { /* the largest value is unknown yet; compute it */
226.825 + for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
226.826 + { temp = sv_val[i_ptr];
226.827 + if (temp < 0.0) temp = - temp;
226.828 + if (big < temp) big = temp;
226.829 + }
226.830 + vr_max[i] = big;
226.831 + }
226.832 + /* find an element in the i-th row, which is placed in a
226.833 + column with minimal number of non-zeros and satisfies to
226.834 + the stability condition (such element always exists) */
226.835 + min_p = min_q = 0, min_len = INT_MAX;
226.836 + for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
226.837 + { /* get column index of v[i,j] */
226.838 + j = sv_ind[i_ptr];
226.839 + /* if the j-th column is not shorter than that one, where
226.840 + minimal element is currently placed, skip v[i,j] */
226.841 + if (vc_len[j] >= min_len) continue;
226.842 + /* if v[i,j] doesn't satisfy to the stability condition,
226.843 + skip it */
226.844 + temp = sv_val[i_ptr];
226.845 + if (temp < 0.0) temp = - temp;
226.846 + if (temp < piv_tol * big) continue;
226.847 + /* v[i,j] is better than the current minimal element */
226.848 + min_p = i, min_q = j, min_len = vc_len[j];
226.849 + /* if Markowitz cost of the current minimal element is
226.850 + not greater than (len-1)**2, it can be chosen right
226.851 + now; this heuristic reduces the search and works well
226.852 + in many cases */
226.853 + if (min_len <= len)
226.854 + { p = min_p, q = min_q;
226.855 + goto done;
226.856 + }
226.857 + }
226.858 + /* the i-th row has been scanned */
226.859 + if (min_p != 0)
226.860 + { /* the minimal element is a next pivot candidate */
226.861 + ncand++;
226.862 + /* compute its Markowitz cost */
226.863 + cost = (double)(len - 1) * (double)(min_len - 1);
226.864 + /* choose between the minimal element and the current
226.865 + candidate */
226.866 + if (cost < best) p = min_p, q = min_q, best = cost;
226.867 + /* if piv_lim candidates have been considered, there are
226.868 + doubts that a much better candidate exists; therefore
226.869 + it's time to terminate the search */
226.870 + if (ncand == piv_lim) goto done;
226.871 + }
226.872 + else
226.873 + { /* this can't be because this can never be */
226.874 + xassert(min_p != min_p);
226.875 + }
226.876 + }
226.877 + }
226.878 +done: /* bring the pivot to the factorizing routine */
226.879 + *_p = p, *_q = q;
226.880 + return (p == 0);
226.881 +}
226.882 +
226.883 +/***********************************************************************
226.884 +* eliminate - perform gaussian elimination.
226.885 +*
226.886 +* This routine performs elementary gaussian transformations in order
226.887 +* to eliminate subdiagonal elements in the k-th column of the matrix
226.888 +* U = P*V*Q using the pivot element u[k,k], where k is the number of
226.889 +* the current elimination step.
226.890 +*
226.891 +* The parameters p and q are, respectively, row and column indices of
226.892 +* the element v[p,q], which corresponds to the element u[k,k].
226.893 +*
226.894 +* Each time when the routine applies the elementary transformation to
226.895 +* a non-pivot row of the matrix V, it stores the corresponding element
226.896 +* to the matrix F in order to keep the main equality A = F*V.
226.897 +*
226.898 +* The routine assumes that on entry the matrices L = P*F*inv(P) and
226.899 +* U = P*V*Q are the following:
226.900 +*
226.901 +* 1 k 1 k n
226.902 +* 1 1 . . . . . . . . . 1 x x x x x x x x x x
226.903 +* x 1 . . . . . . . . . x x x x x x x x x
226.904 +* x x 1 . . . . . . . . . x x x x x x x x
226.905 +* x x x 1 . . . . . . . . . x x x x x x x
226.906 +* k x x x x 1 . . . . . k . . . . * * * * * *
226.907 +* x x x x _ 1 . . . . . . . . # * * * * *
226.908 +* x x x x _ . 1 . . . . . . . # * * * * *
226.909 +* x x x x _ . . 1 . . . . . . # * * * * *
226.910 +* x x x x _ . . . 1 . . . . . # * * * * *
226.911 +* n x x x x _ . . . . 1 n . . . . # * * * * *
226.912 +*
226.913 +* matrix L matrix U
226.914 +*
226.915 +* where rows and columns of the matrix U with numbers k, k+1, ..., n
226.916 +* form the active submatrix (eliminated elements are marked by '#' and
226.917 +* other elements of the active submatrix are marked by '*'). Note that
226.918 +* each eliminated non-zero element u[i,k] of the matrix U gives the
226.919 +* corresponding element l[i,k] of the matrix L (marked by '_').
226.920 +*
226.921 +* Actually all operations are performed on the matrix V. Should note
226.922 +* that the row-wise representation corresponds to the matrix V, but the
226.923 +* column-wise representation corresponds to the active submatrix of the
226.924 +* matrix V, i.e. elements of the matrix V, which doesn't belong to the
226.925 +* active submatrix, are missing from the column linked lists.
226.926 +*
226.927 +* Let u[k,k] = v[p,q] be the pivot. In order to eliminate subdiagonal
226.928 +* elements u[i',k] = v[i,q], i' = k+1, k+2, ..., n, the routine applies
226.929 +* the following elementary gaussian transformations:
226.930 +*
226.931 +* (i-th row of V) := (i-th row of V) - f[i,p] * (p-th row of V),
226.932 +*
226.933 +* where f[i,p] = v[i,q] / v[p,q] is a gaussian multiplier.
226.934 +*
226.935 +* Additionally, in order to keep the main equality A = F*V, each time
226.936 +* when the routine applies the transformation to i-th row of the matrix
226.937 +* V, it also adds f[i,p] as a new element to the matrix F.
226.938 +*
226.939 +* IMPORTANT: On entry the working arrays flag and work should contain
226.940 +* zeros. This status is provided by the routine on exit.
226.941 +*
226.942 +* If no error occured, the routine returns zero. Otherwise, in case of
226.943 +* overflow of the sparse vector area, the routine returns non-zero. */
226.944 +
226.945 +static int eliminate(LUF *luf, int p, int q)
226.946 +{ int n = luf->n;
226.947 + int *fc_ptr = luf->fc_ptr;
226.948 + int *fc_len = luf->fc_len;
226.949 + int *vr_ptr = luf->vr_ptr;
226.950 + int *vr_len = luf->vr_len;
226.951 + int *vr_cap = luf->vr_cap;
226.952 + double *vr_piv = luf->vr_piv;
226.953 + int *vc_ptr = luf->vc_ptr;
226.954 + int *vc_len = luf->vc_len;
226.955 + int *vc_cap = luf->vc_cap;
226.956 + int *sv_ind = luf->sv_ind;
226.957 + double *sv_val = luf->sv_val;
226.958 + int *sv_prev = luf->sv_prev;
226.959 + int *sv_next = luf->sv_next;
226.960 + double *vr_max = luf->vr_max;
226.961 + int *rs_head = luf->rs_head;
226.962 + int *rs_prev = luf->rs_prev;
226.963 + int *rs_next = luf->rs_next;
226.964 + int *cs_head = luf->cs_head;
226.965 + int *cs_prev = luf->cs_prev;
226.966 + int *cs_next = luf->cs_next;
226.967 + int *flag = luf->flag;
226.968 + double *work = luf->work;
226.969 + double eps_tol = luf->eps_tol;
226.970 + /* at this stage the row-wise representation of the matrix F is
226.971 + not used, so fr_len can be used as a working array */
226.972 + int *ndx = luf->fr_len;
226.973 + int ret = 0;
226.974 + int len, fill, i, i_beg, i_end, i_ptr, j, j_beg, j_end, j_ptr, k,
226.975 + p_beg, p_end, p_ptr, q_beg, q_end, q_ptr;
226.976 + double fip, val, vpq, temp;
226.977 + xassert(1 <= p && p <= n);
226.978 + xassert(1 <= q && q <= n);
226.979 + /* remove the p-th (pivot) row from the active set; this row will
226.980 + never return there */
226.981 + if (rs_prev[p] == 0)
226.982 + rs_head[vr_len[p]] = rs_next[p];
226.983 + else
226.984 + rs_next[rs_prev[p]] = rs_next[p];
226.985 + if (rs_next[p] == 0)
226.986 + ;
226.987 + else
226.988 + rs_prev[rs_next[p]] = rs_prev[p];
226.989 + /* remove the q-th (pivot) column from the active set; this column
226.990 + will never return there */
226.991 + if (cs_prev[q] == 0)
226.992 + cs_head[vc_len[q]] = cs_next[q];
226.993 + else
226.994 + cs_next[cs_prev[q]] = cs_next[q];
226.995 + if (cs_next[q] == 0)
226.996 + ;
226.997 + else
226.998 + cs_prev[cs_next[q]] = cs_prev[q];
226.999 + /* find the pivot v[p,q] = u[k,k] in the p-th row */
226.1000 + p_beg = vr_ptr[p];
226.1001 + p_end = p_beg + vr_len[p] - 1;
226.1002 + for (p_ptr = p_beg; sv_ind[p_ptr] != q; p_ptr++) /* nop */;
226.1003 + xassert(p_ptr <= p_end);
226.1004 + /* store value of the pivot */
226.1005 + vpq = (vr_piv[p] = sv_val[p_ptr]);
226.1006 + /* remove the pivot from the p-th row */
226.1007 + sv_ind[p_ptr] = sv_ind[p_end];
226.1008 + sv_val[p_ptr] = sv_val[p_end];
226.1009 + vr_len[p]--;
226.1010 + p_end--;
226.1011 + /* find the pivot v[p,q] = u[k,k] in the q-th column */
226.1012 + q_beg = vc_ptr[q];
226.1013 + q_end = q_beg + vc_len[q] - 1;
226.1014 + for (q_ptr = q_beg; sv_ind[q_ptr] != p; q_ptr++) /* nop */;
226.1015 + xassert(q_ptr <= q_end);
226.1016 + /* remove the pivot from the q-th column */
226.1017 + sv_ind[q_ptr] = sv_ind[q_end];
226.1018 + vc_len[q]--;
226.1019 + q_end--;
226.1020 + /* walk through the p-th (pivot) row, which doesn't contain the
226.1021 + pivot v[p,q] already, and do the following... */
226.1022 + for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++)
226.1023 + { /* get column index of v[p,j] */
226.1024 + j = sv_ind[p_ptr];
226.1025 + /* store v[p,j] to the working array */
226.1026 + flag[j] = 1;
226.1027 + work[j] = sv_val[p_ptr];
226.1028 + /* remove the j-th column from the active set; this column will
226.1029 + return there later with new length */
226.1030 + if (cs_prev[j] == 0)
226.1031 + cs_head[vc_len[j]] = cs_next[j];
226.1032 + else
226.1033 + cs_next[cs_prev[j]] = cs_next[j];
226.1034 + if (cs_next[j] == 0)
226.1035 + ;
226.1036 + else
226.1037 + cs_prev[cs_next[j]] = cs_prev[j];
226.1038 + /* find v[p,j] in the j-th column */
226.1039 + j_beg = vc_ptr[j];
226.1040 + j_end = j_beg + vc_len[j] - 1;
226.1041 + for (j_ptr = j_beg; sv_ind[j_ptr] != p; j_ptr++) /* nop */;
226.1042 + xassert(j_ptr <= j_end);
226.1043 + /* since v[p,j] leaves the active submatrix, remove it from the
226.1044 + j-th column; however, v[p,j] is kept in the p-th row */
226.1045 + sv_ind[j_ptr] = sv_ind[j_end];
226.1046 + vc_len[j]--;
226.1047 + }
226.1048 + /* walk through the q-th (pivot) column, which doesn't contain the
226.1049 + pivot v[p,q] already, and perform gaussian elimination */
226.1050 + while (q_beg <= q_end)
226.1051 + { /* element v[i,q] should be eliminated */
226.1052 + /* get row index of v[i,q] */
226.1053 + i = sv_ind[q_beg];
226.1054 + /* remove the i-th row from the active set; later this row will
226.1055 + return there with new length */
226.1056 + if (rs_prev[i] == 0)
226.1057 + rs_head[vr_len[i]] = rs_next[i];
226.1058 + else
226.1059 + rs_next[rs_prev[i]] = rs_next[i];
226.1060 + if (rs_next[i] == 0)
226.1061 + ;
226.1062 + else
226.1063 + rs_prev[rs_next[i]] = rs_prev[i];
226.1064 + /* find v[i,q] in the i-th row */
226.1065 + i_beg = vr_ptr[i];
226.1066 + i_end = i_beg + vr_len[i] - 1;
226.1067 + for (i_ptr = i_beg; sv_ind[i_ptr] != q; i_ptr++) /* nop */;
226.1068 + xassert(i_ptr <= i_end);
226.1069 + /* compute gaussian multiplier f[i,p] = v[i,q] / v[p,q] */
226.1070 + fip = sv_val[i_ptr] / vpq;
226.1071 + /* since v[i,q] should be eliminated, remove it from the i-th
226.1072 + row */
226.1073 + sv_ind[i_ptr] = sv_ind[i_end];
226.1074 + sv_val[i_ptr] = sv_val[i_end];
226.1075 + vr_len[i]--;
226.1076 + i_end--;
226.1077 + /* and from the q-th column */
226.1078 + sv_ind[q_beg] = sv_ind[q_end];
226.1079 + vc_len[q]--;
226.1080 + q_end--;
226.1081 + /* perform gaussian transformation:
226.1082 + (i-th row) := (i-th row) - f[i,p] * (p-th row)
226.1083 + note that now the p-th row, which is in the working array,
226.1084 + doesn't contain the pivot v[p,q], and the i-th row doesn't
226.1085 + contain the eliminated element v[i,q] */
226.1086 + /* walk through the i-th row and transform existing non-zero
226.1087 + elements */
226.1088 + fill = vr_len[p];
226.1089 + for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
226.1090 + { /* get column index of v[i,j] */
226.1091 + j = sv_ind[i_ptr];
226.1092 + /* v[i,j] := v[i,j] - f[i,p] * v[p,j] */
226.1093 + if (flag[j])
226.1094 + { /* v[p,j] != 0 */
226.1095 + temp = (sv_val[i_ptr] -= fip * work[j]);
226.1096 + if (temp < 0.0) temp = - temp;
226.1097 + flag[j] = 0;
226.1098 + fill--; /* since both v[i,j] and v[p,j] exist */
226.1099 + if (temp == 0.0 || temp < eps_tol)
226.1100 + { /* new v[i,j] is closer to zero; replace it by exact
226.1101 + zero, i.e. remove it from the active submatrix */
226.1102 + /* remove v[i,j] from the i-th row */
226.1103 + sv_ind[i_ptr] = sv_ind[i_end];
226.1104 + sv_val[i_ptr] = sv_val[i_end];
226.1105 + vr_len[i]--;
226.1106 + i_ptr--;
226.1107 + i_end--;
226.1108 + /* find v[i,j] in the j-th column */
226.1109 + j_beg = vc_ptr[j];
226.1110 + j_end = j_beg + vc_len[j] - 1;
226.1111 + for (j_ptr = j_beg; sv_ind[j_ptr] != i; j_ptr++);
226.1112 + xassert(j_ptr <= j_end);
226.1113 + /* remove v[i,j] from the j-th column */
226.1114 + sv_ind[j_ptr] = sv_ind[j_end];
226.1115 + vc_len[j]--;
226.1116 + }
226.1117 + else
226.1118 + { /* v_big := max(v_big, |v[i,j]|) */
226.1119 + if (luf->big_v < temp) luf->big_v = temp;
226.1120 + }
226.1121 + }
226.1122 + }
226.1123 + /* now flag is the pattern of the set v[p,*] \ v[i,*], and fill
226.1124 + is number of non-zeros in this set; therefore up to fill new
226.1125 + non-zeros may appear in the i-th row */
226.1126 + if (vr_len[i] + fill > vr_cap[i])
226.1127 + { /* enlarge the i-th row */
226.1128 + if (luf_enlarge_row(luf, i, vr_len[i] + fill))
226.1129 + { /* overflow of the sparse vector area */
226.1130 + ret = 1;
226.1131 + goto done;
226.1132 + }
226.1133 + /* defragmentation may change row and column pointers of the
226.1134 + matrix V */
226.1135 + p_beg = vr_ptr[p];
226.1136 + p_end = p_beg + vr_len[p] - 1;
226.1137 + q_beg = vc_ptr[q];
226.1138 + q_end = q_beg + vc_len[q] - 1;
226.1139 + }
226.1140 + /* walk through the p-th (pivot) row and create new elements
226.1141 + of the i-th row that appear due to fill-in; column indices
226.1142 + of these new elements are accumulated in the array ndx */
226.1143 + len = 0;
226.1144 + for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++)
226.1145 + { /* get column index of v[p,j], which may cause fill-in */
226.1146 + j = sv_ind[p_ptr];
226.1147 + if (flag[j])
226.1148 + { /* compute new non-zero v[i,j] = 0 - f[i,p] * v[p,j] */
226.1149 + temp = (val = - fip * work[j]);
226.1150 + if (temp < 0.0) temp = - temp;
226.1151 + if (temp == 0.0 || temp < eps_tol)
226.1152 + /* if v[i,j] is closer to zero; just ignore it */;
226.1153 + else
226.1154 + { /* add v[i,j] to the i-th row */
226.1155 + i_ptr = vr_ptr[i] + vr_len[i];
226.1156 + sv_ind[i_ptr] = j;
226.1157 + sv_val[i_ptr] = val;
226.1158 + vr_len[i]++;
226.1159 + /* remember column index of v[i,j] */
226.1160 + ndx[++len] = j;
226.1161 + /* big_v := max(big_v, |v[i,j]|) */
226.1162 + if (luf->big_v < temp) luf->big_v = temp;
226.1163 + }
226.1164 + }
226.1165 + else
226.1166 + { /* there is no fill-in, because v[i,j] already exists in
226.1167 + the i-th row; restore the flag of the element v[p,j],
226.1168 + which was reset before */
226.1169 + flag[j] = 1;
226.1170 + }
226.1171 + }
226.1172 + /* add new non-zeros v[i,j] to the corresponding columns */
226.1173 + for (k = 1; k <= len; k++)
226.1174 + { /* get column index of new non-zero v[i,j] */
226.1175 + j = ndx[k];
226.1176 + /* one free location is needed in the j-th column */
226.1177 + if (vc_len[j] + 1 > vc_cap[j])
226.1178 + { /* enlarge the j-th column */
226.1179 + if (luf_enlarge_col(luf, j, vc_len[j] + 10))
226.1180 + { /* overflow of the sparse vector area */
226.1181 + ret = 1;
226.1182 + goto done;
226.1183 + }
226.1184 + /* defragmentation may change row and column pointers of
226.1185 + the matrix V */
226.1186 + p_beg = vr_ptr[p];
226.1187 + p_end = p_beg + vr_len[p] - 1;
226.1188 + q_beg = vc_ptr[q];
226.1189 + q_end = q_beg + vc_len[q] - 1;
226.1190 + }
226.1191 + /* add new non-zero v[i,j] to the j-th column */
226.1192 + j_ptr = vc_ptr[j] + vc_len[j];
226.1193 + sv_ind[j_ptr] = i;
226.1194 + vc_len[j]++;
226.1195 + }
226.1196 + /* now the i-th row has been completely transformed, therefore
226.1197 + it can return to the active set with new length */
226.1198 + rs_prev[i] = 0;
226.1199 + rs_next[i] = rs_head[vr_len[i]];
226.1200 + if (rs_next[i] != 0) rs_prev[rs_next[i]] = i;
226.1201 + rs_head[vr_len[i]] = i;
226.1202 + /* the largest of absolute values of elements in the i-th row
226.1203 + is currently unknown */
226.1204 + vr_max[i] = -1.0;
226.1205 + /* at least one free location is needed to store the gaussian
226.1206 + multiplier */
226.1207 + if (luf->sv_end - luf->sv_beg < 1)
226.1208 + { /* there are no free locations at all; defragment SVA */
226.1209 + luf_defrag_sva(luf);
226.1210 + if (luf->sv_end - luf->sv_beg < 1)
226.1211 + { /* overflow of the sparse vector area */
226.1212 + ret = 1;
226.1213 + goto done;
226.1214 + }
226.1215 + /* defragmentation may change row and column pointers of the
226.1216 + matrix V */
226.1217 + p_beg = vr_ptr[p];
226.1218 + p_end = p_beg + vr_len[p] - 1;
226.1219 + q_beg = vc_ptr[q];
226.1220 + q_end = q_beg + vc_len[q] - 1;
226.1221 + }
226.1222 + /* add the element f[i,p], which is the gaussian multiplier,
226.1223 + to the matrix F */
226.1224 + luf->sv_end--;
226.1225 + sv_ind[luf->sv_end] = i;
226.1226 + sv_val[luf->sv_end] = fip;
226.1227 + fc_len[p]++;
226.1228 + /* end of elimination loop */
226.1229 + }
226.1230 + /* at this point the q-th (pivot) column should be empty */
226.1231 + xassert(vc_len[q] == 0);
226.1232 + /* reset capacity of the q-th column */
226.1233 + vc_cap[q] = 0;
226.1234 + /* remove node of the q-th column from the addressing list */
226.1235 + k = n + q;
226.1236 + if (sv_prev[k] == 0)
226.1237 + luf->sv_head = sv_next[k];
226.1238 + else
226.1239 + sv_next[sv_prev[k]] = sv_next[k];
226.1240 + if (sv_next[k] == 0)
226.1241 + luf->sv_tail = sv_prev[k];
226.1242 + else
226.1243 + sv_prev[sv_next[k]] = sv_prev[k];
226.1244 + /* the p-th column of the matrix F has been completely built; set
226.1245 + its pointer */
226.1246 + fc_ptr[p] = luf->sv_end;
226.1247 + /* walk through the p-th (pivot) row and do the following... */
226.1248 + for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++)
226.1249 + { /* get column index of v[p,j] */
226.1250 + j = sv_ind[p_ptr];
226.1251 + /* erase v[p,j] from the working array */
226.1252 + flag[j] = 0;
226.1253 + work[j] = 0.0;
226.1254 + /* the j-th column has been completely transformed, therefore
226.1255 + it can return to the active set with new length; however
226.1256 + the special case c_prev[j] = c_next[j] = j means that the
226.1257 + routine find_pivot excluded the j-th column from the active
226.1258 + set due to Uwe Suhl's rule, and therefore in this case the
226.1259 + column can return to the active set only if it is a column
226.1260 + singleton */
226.1261 + if (!(vc_len[j] != 1 && cs_prev[j] == j && cs_next[j] == j))
226.1262 + { cs_prev[j] = 0;
226.1263 + cs_next[j] = cs_head[vc_len[j]];
226.1264 + if (cs_next[j] != 0) cs_prev[cs_next[j]] = j;
226.1265 + cs_head[vc_len[j]] = j;
226.1266 + }
226.1267 + }
226.1268 +done: /* return to the factorizing routine */
226.1269 + return ret;
226.1270 +}
226.1271 +
226.1272 +/***********************************************************************
226.1273 +* build_v_cols - build the matrix V in column-wise format
226.1274 +*
226.1275 +* This routine builds the column-wise representation of the matrix V
226.1276 +* using its row-wise representation.
226.1277 +*
226.1278 +* If no error occured, the routine returns zero. Otherwise, in case of
226.1279 +* overflow of the sparse vector area, the routine returns non-zero. */
226.1280 +
226.1281 +static int build_v_cols(LUF *luf)
226.1282 +{ int n = luf->n;
226.1283 + int *vr_ptr = luf->vr_ptr;
226.1284 + int *vr_len = luf->vr_len;
226.1285 + int *vc_ptr = luf->vc_ptr;
226.1286 + int *vc_len = luf->vc_len;
226.1287 + int *vc_cap = luf->vc_cap;
226.1288 + int *sv_ind = luf->sv_ind;
226.1289 + double *sv_val = luf->sv_val;
226.1290 + int *sv_prev = luf->sv_prev;
226.1291 + int *sv_next = luf->sv_next;
226.1292 + int ret = 0;
226.1293 + int i, i_beg, i_end, i_ptr, j, j_ptr, k, nnz;
226.1294 + /* it is assumed that on entry all columns of the matrix V are
226.1295 + empty, i.e. vc_len[j] = vc_cap[j] = 0 for all j = 1, ..., n,
226.1296 + and have been removed from the addressing list */
226.1297 + /* count non-zeros in columns of the matrix V; count total number
226.1298 + of non-zeros in this matrix */
226.1299 + nnz = 0;
226.1300 + for (i = 1; i <= n; i++)
226.1301 + { /* walk through elements of the i-th row and count non-zeros
226.1302 + in the corresponding columns */
226.1303 + i_beg = vr_ptr[i];
226.1304 + i_end = i_beg + vr_len[i] - 1;
226.1305 + for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
226.1306 + vc_cap[sv_ind[i_ptr]]++;
226.1307 + /* count total number of non-zeros */
226.1308 + nnz += vr_len[i];
226.1309 + }
226.1310 + /* store total number of non-zeros */
226.1311 + luf->nnz_v = nnz;
226.1312 + /* check for free locations */
226.1313 + if (luf->sv_end - luf->sv_beg < nnz)
226.1314 + { /* overflow of the sparse vector area */
226.1315 + ret = 1;
226.1316 + goto done;
226.1317 + }
226.1318 + /* allocate columns of the matrix V */
226.1319 + for (j = 1; j <= n; j++)
226.1320 + { /* set pointer to the j-th column */
226.1321 + vc_ptr[j] = luf->sv_beg;
226.1322 + /* reserve locations for the j-th column */
226.1323 + luf->sv_beg += vc_cap[j];
226.1324 + }
226.1325 + /* build the matrix V in column-wise format using this matrix in
226.1326 + row-wise format */
226.1327 + for (i = 1; i <= n; i++)
226.1328 + { /* walk through elements of the i-th row */
226.1329 + i_beg = vr_ptr[i];
226.1330 + i_end = i_beg + vr_len[i] - 1;
226.1331 + for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
226.1332 + { /* get column index */
226.1333 + j = sv_ind[i_ptr];
226.1334 + /* store element in the j-th column */
226.1335 + j_ptr = vc_ptr[j] + vc_len[j];
226.1336 + sv_ind[j_ptr] = i;
226.1337 + sv_val[j_ptr] = sv_val[i_ptr];
226.1338 + /* increase length of the j-th column */
226.1339 + vc_len[j]++;
226.1340 + }
226.1341 + }
226.1342 + /* now columns are placed in the sparse vector area behind rows
226.1343 + in the order n+1, n+2, ..., n+n; so insert column nodes in the
226.1344 + addressing list using this order */
226.1345 + for (k = n+1; k <= n+n; k++)
226.1346 + { sv_prev[k] = k-1;
226.1347 + sv_next[k] = k+1;
226.1348 + }
226.1349 + sv_prev[n+1] = luf->sv_tail;
226.1350 + sv_next[luf->sv_tail] = n+1;
226.1351 + sv_next[n+n] = 0;
226.1352 + luf->sv_tail = n+n;
226.1353 +done: /* return to the factorizing routine */
226.1354 + return ret;
226.1355 +}
226.1356 +
226.1357 +/***********************************************************************
226.1358 +* build_f_rows - build the matrix F in row-wise format
226.1359 +*
226.1360 +* This routine builds the row-wise representation of the matrix F using
226.1361 +* its column-wise representation.
226.1362 +*
226.1363 +* If no error occured, the routine returns zero. Otherwise, in case of
226.1364 +* overflow of the sparse vector area, the routine returns non-zero. */
226.1365 +
226.1366 +static int build_f_rows(LUF *luf)
226.1367 +{ int n = luf->n;
226.1368 + int *fr_ptr = luf->fr_ptr;
226.1369 + int *fr_len = luf->fr_len;
226.1370 + int *fc_ptr = luf->fc_ptr;
226.1371 + int *fc_len = luf->fc_len;
226.1372 + int *sv_ind = luf->sv_ind;
226.1373 + double *sv_val = luf->sv_val;
226.1374 + int ret = 0;
226.1375 + int i, j, j_beg, j_end, j_ptr, ptr, nnz;
226.1376 + /* clear rows of the matrix F */
226.1377 + for (i = 1; i <= n; i++) fr_len[i] = 0;
226.1378 + /* count non-zeros in rows of the matrix F; count total number of
226.1379 + non-zeros in this matrix */
226.1380 + nnz = 0;
226.1381 + for (j = 1; j <= n; j++)
226.1382 + { /* walk through elements of the j-th column and count non-zeros
226.1383 + in the corresponding rows */
226.1384 + j_beg = fc_ptr[j];
226.1385 + j_end = j_beg + fc_len[j] - 1;
226.1386 + for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
226.1387 + fr_len[sv_ind[j_ptr]]++;
226.1388 + /* increase total number of non-zeros */
226.1389 + nnz += fc_len[j];
226.1390 + }
226.1391 + /* store total number of non-zeros */
226.1392 + luf->nnz_f = nnz;
226.1393 + /* check for free locations */
226.1394 + if (luf->sv_end - luf->sv_beg < nnz)
226.1395 + { /* overflow of the sparse vector area */
226.1396 + ret = 1;
226.1397 + goto done;
226.1398 + }
226.1399 + /* allocate rows of the matrix F */
226.1400 + for (i = 1; i <= n; i++)
226.1401 + { /* set pointer to the end of the i-th row; later this pointer
226.1402 + will be set to the beginning of the i-th row */
226.1403 + fr_ptr[i] = luf->sv_end;
226.1404 + /* reserve locations for the i-th row */
226.1405 + luf->sv_end -= fr_len[i];
226.1406 + }
226.1407 + /* build the matrix F in row-wise format using this matrix in
226.1408 + column-wise format */
226.1409 + for (j = 1; j <= n; j++)
226.1410 + { /* walk through elements of the j-th column */
226.1411 + j_beg = fc_ptr[j];
226.1412 + j_end = j_beg + fc_len[j] - 1;
226.1413 + for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
226.1414 + { /* get row index */
226.1415 + i = sv_ind[j_ptr];
226.1416 + /* store element in the i-th row */
226.1417 + ptr = --fr_ptr[i];
226.1418 + sv_ind[ptr] = j;
226.1419 + sv_val[ptr] = sv_val[j_ptr];
226.1420 + }
226.1421 + }
226.1422 +done: /* return to the factorizing routine */
226.1423 + return ret;
226.1424 +}
226.1425 +
226.1426 +/***********************************************************************
226.1427 +* NAME
226.1428 +*
226.1429 +* luf_factorize - compute LU-factorization
226.1430 +*
226.1431 +* SYNOPSIS
226.1432 +*
226.1433 +* #include "glpluf.h"
226.1434 +* int luf_factorize(LUF *luf, int n, int (*col)(void *info, int j,
226.1435 +* int ind[], double val[]), void *info);
226.1436 +*
226.1437 +* DESCRIPTION
226.1438 +*
226.1439 +* The routine luf_factorize computes LU-factorization of a specified
226.1440 +* square matrix A.
226.1441 +*
226.1442 +* The parameter luf specifies LU-factorization program object created
226.1443 +* by the routine luf_create_it.
226.1444 +*
226.1445 +* The parameter n specifies the order of A, n > 0.
226.1446 +*
226.1447 +* The formal routine col specifies the matrix A to be factorized. To
226.1448 +* obtain j-th column of A the routine luf_factorize calls the routine
226.1449 +* col with the parameter j (1 <= j <= n). In response the routine col
226.1450 +* should store row indices and numerical values of non-zero elements
226.1451 +* of j-th column of A to locations ind[1,...,len] and val[1,...,len],
226.1452 +* respectively, where len is the number of non-zeros in j-th column
226.1453 +* returned on exit. Neither zero nor duplicate elements are allowed.
226.1454 +*
226.1455 +* The parameter info is a transit pointer passed to the routine col.
226.1456 +*
226.1457 +* RETURNS
226.1458 +*
226.1459 +* 0 LU-factorization has been successfully computed.
226.1460 +*
226.1461 +* LUF_ESING
226.1462 +* The specified matrix is singular within the working precision.
226.1463 +* (On some elimination step the active submatrix is exactly zero,
226.1464 +* so no pivot can be chosen.)
226.1465 +*
226.1466 +* LUF_ECOND
226.1467 +* The specified matrix is ill-conditioned.
226.1468 +* (On some elimination step too intensive growth of elements of the
226.1469 +* active submatix has been detected.)
226.1470 +*
226.1471 +* If matrix A is well scaled, the return code LUF_ECOND may also mean
226.1472 +* that the threshold pivoting tolerance piv_tol should be increased.
226.1473 +*
226.1474 +* In case of non-zero return code the factorization becomes invalid.
226.1475 +* It should not be used in other operations until the cause of failure
226.1476 +* has been eliminated and the factorization has been recomputed again
226.1477 +* with the routine luf_factorize.
226.1478 +*
226.1479 +* REPAIRING SINGULAR MATRIX
226.1480 +*
226.1481 +* If the routine luf_factorize returns non-zero code, it provides all
226.1482 +* necessary information that can be used for "repairing" the matrix A,
226.1483 +* where "repairing" means replacing linearly dependent columns of the
226.1484 +* matrix A by appropriate columns of the unity matrix. This feature is
226.1485 +* needed when this routine is used for factorizing the basis matrix
226.1486 +* within the simplex method procedure.
226.1487 +*
226.1488 +* On exit linearly dependent columns of the (partially transformed)
226.1489 +* matrix U have numbers rank+1, rank+2, ..., n, where rank is estimated
226.1490 +* rank of the matrix A stored by the routine to the member luf->rank.
226.1491 +* The correspondence between columns of A and U is the same as between
226.1492 +* columns of V and U. Thus, linearly dependent columns of the matrix A
226.1493 +* have numbers qq_col[rank+1], qq_col[rank+2], ..., qq_col[n], where
226.1494 +* qq_col is the column-like representation of the permutation matrix Q.
226.1495 +* It is understood that each j-th linearly dependent column of the
226.1496 +* matrix U should be replaced by the unity vector, where all elements
226.1497 +* are zero except the unity diagonal element u[j,j]. On the other hand
226.1498 +* j-th row of the matrix U corresponds to the row of the matrix V (and
226.1499 +* therefore of the matrix A) with the number pp_row[j], where pp_row is
226.1500 +* the row-like representation of the permutation matrix P. Thus, each
226.1501 +* j-th linearly dependent column of the matrix U should be replaced by
226.1502 +* column of the unity matrix with the number pp_row[j].
226.1503 +*
226.1504 +* The code that repairs the matrix A may look like follows:
226.1505 +*
226.1506 +* for (j = rank+1; j <= n; j++)
226.1507 +* { replace the column qq_col[j] of the matrix A by the column
226.1508 +* pp_row[j] of the unity matrix;
226.1509 +* }
226.1510 +*
226.1511 +* where rank, pp_row, and qq_col are members of the structure LUF. */
226.1512 +
226.1513 +int luf_factorize(LUF *luf, int n, int (*col)(void *info, int j,
226.1514 + int ind[], double val[]), void *info)
226.1515 +{ int *pp_row, *pp_col, *qq_row, *qq_col;
226.1516 + double max_gro = luf->max_gro;
226.1517 + int i, j, k, p, q, t, ret;
226.1518 + if (n < 1)
226.1519 + xfault("luf_factorize: n = %d; invalid parameter\n", n);
226.1520 + if (n > N_MAX)
226.1521 + xfault("luf_factorize: n = %d; matrix too big\n", n);
226.1522 + /* invalidate the factorization */
226.1523 + luf->valid = 0;
226.1524 + /* reallocate arrays, if necessary */
226.1525 + reallocate(luf, n);
226.1526 + pp_row = luf->pp_row;
226.1527 + pp_col = luf->pp_col;
226.1528 + qq_row = luf->qq_row;
226.1529 + qq_col = luf->qq_col;
226.1530 + /* estimate initial size of the SVA, if not specified */
226.1531 + if (luf->sv_size == 0 && luf->new_sva == 0)
226.1532 + luf->new_sva = 5 * (n + 10);
226.1533 +more: /* reallocate the sparse vector area, if required */
226.1534 + if (luf->new_sva > 0)
226.1535 + { if (luf->sv_ind != NULL) xfree(luf->sv_ind);
226.1536 + if (luf->sv_val != NULL) xfree(luf->sv_val);
226.1537 + luf->sv_size = luf->new_sva;
226.1538 + luf->sv_ind = xcalloc(1+luf->sv_size, sizeof(int));
226.1539 + luf->sv_val = xcalloc(1+luf->sv_size, sizeof(double));
226.1540 + luf->new_sva = 0;
226.1541 + }
226.1542 + /* initialize LU-factorization data structures */
226.1543 + if (initialize(luf, col, info))
226.1544 + { /* overflow of the sparse vector area */
226.1545 + luf->new_sva = luf->sv_size + luf->sv_size;
226.1546 + xassert(luf->new_sva > luf->sv_size);
226.1547 + goto more;
226.1548 + }
226.1549 + /* main elimination loop */
226.1550 + for (k = 1; k <= n; k++)
226.1551 + { /* choose a pivot element v[p,q] */
226.1552 + if (find_pivot(luf, &p, &q))
226.1553 + { /* no pivot can be chosen, because the active submatrix is
226.1554 + exactly zero */
226.1555 + luf->rank = k - 1;
226.1556 + ret = LUF_ESING;
226.1557 + goto done;
226.1558 + }
226.1559 + /* let v[p,q] correspond to u[i',j']; permute k-th and i'-th
226.1560 + rows and k-th and j'-th columns of the matrix U = P*V*Q to
226.1561 + move the element u[i',j'] to the position u[k,k] */
226.1562 + i = pp_col[p], j = qq_row[q];
226.1563 + xassert(k <= i && i <= n && k <= j && j <= n);
226.1564 + /* permute k-th and i-th rows of the matrix U */
226.1565 + t = pp_row[k];
226.1566 + pp_row[i] = t, pp_col[t] = i;
226.1567 + pp_row[k] = p, pp_col[p] = k;
226.1568 + /* permute k-th and j-th columns of the matrix U */
226.1569 + t = qq_col[k];
226.1570 + qq_col[j] = t, qq_row[t] = j;
226.1571 + qq_col[k] = q, qq_row[q] = k;
226.1572 + /* eliminate subdiagonal elements of k-th column of the matrix
226.1573 + U = P*V*Q using the pivot element u[k,k] = v[p,q] */
226.1574 + if (eliminate(luf, p, q))
226.1575 + { /* overflow of the sparse vector area */
226.1576 + luf->new_sva = luf->sv_size + luf->sv_size;
226.1577 + xassert(luf->new_sva > luf->sv_size);
226.1578 + goto more;
226.1579 + }
226.1580 + /* check relative growth of elements of the matrix V */
226.1581 + if (luf->big_v > max_gro * luf->max_a)
226.1582 + { /* the growth is too intensive, therefore most probably the
226.1583 + matrix A is ill-conditioned */
226.1584 + luf->rank = k - 1;
226.1585 + ret = LUF_ECOND;
226.1586 + goto done;
226.1587 + }
226.1588 + }
226.1589 + /* now the matrix U = P*V*Q is upper triangular, the matrix V has
226.1590 + been built in row-wise format, and the matrix F has been built
226.1591 + in column-wise format */
226.1592 + /* defragment the sparse vector area in order to merge all free
226.1593 + locations in one continuous extent */
226.1594 + luf_defrag_sva(luf);
226.1595 + /* build the matrix V in column-wise format */
226.1596 + if (build_v_cols(luf))
226.1597 + { /* overflow of the sparse vector area */
226.1598 + luf->new_sva = luf->sv_size + luf->sv_size;
226.1599 + xassert(luf->new_sva > luf->sv_size);
226.1600 + goto more;
226.1601 + }
226.1602 + /* build the matrix F in row-wise format */
226.1603 + if (build_f_rows(luf))
226.1604 + { /* overflow of the sparse vector area */
226.1605 + luf->new_sva = luf->sv_size + luf->sv_size;
226.1606 + xassert(luf->new_sva > luf->sv_size);
226.1607 + goto more;
226.1608 + }
226.1609 + /* the LU-factorization has been successfully computed */
226.1610 + luf->valid = 1;
226.1611 + luf->rank = n;
226.1612 + ret = 0;
226.1613 + /* if there are few free locations in the sparse vector area, try
226.1614 + increasing its size in the future */
226.1615 + t = 3 * (n + luf->nnz_v) + 2 * luf->nnz_f;
226.1616 + if (luf->sv_size < t)
226.1617 + { luf->new_sva = luf->sv_size;
226.1618 + while (luf->new_sva < t)
226.1619 + { k = luf->new_sva;
226.1620 + luf->new_sva = k + k;
226.1621 + xassert(luf->new_sva > k);
226.1622 + }
226.1623 + }
226.1624 +done: /* return to the calling program */
226.1625 + return ret;
226.1626 +}
226.1627 +
226.1628 +/***********************************************************************
226.1629 +* NAME
226.1630 +*
226.1631 +* luf_f_solve - solve system F*x = b or F'*x = b
226.1632 +*
226.1633 +* SYNOPSIS
226.1634 +*
226.1635 +* #include "glpluf.h"
226.1636 +* void luf_f_solve(LUF *luf, int tr, double x[]);
226.1637 +*
226.1638 +* DESCRIPTION
226.1639 +*
226.1640 +* The routine luf_f_solve solves either the system F*x = b (if the
226.1641 +* flag tr is zero) or the system F'*x = b (if the flag tr is non-zero),
226.1642 +* where the matrix F is a component of LU-factorization specified by
226.1643 +* the parameter luf, F' is a matrix transposed to F.
226.1644 +*
226.1645 +* On entry the array x should contain elements of the right-hand side
226.1646 +* vector b in locations x[1], ..., x[n], where n is the order of the
226.1647 +* matrix F. On exit this array will contain elements of the solution
226.1648 +* vector x in the same locations. */
226.1649 +
226.1650 +void luf_f_solve(LUF *luf, int tr, double x[])
226.1651 +{ int n = luf->n;
226.1652 + int *fr_ptr = luf->fr_ptr;
226.1653 + int *fr_len = luf->fr_len;
226.1654 + int *fc_ptr = luf->fc_ptr;
226.1655 + int *fc_len = luf->fc_len;
226.1656 + int *pp_row = luf->pp_row;
226.1657 + int *sv_ind = luf->sv_ind;
226.1658 + double *sv_val = luf->sv_val;
226.1659 + int i, j, k, beg, end, ptr;
226.1660 + double xk;
226.1661 + if (!luf->valid)
226.1662 + xfault("luf_f_solve: LU-factorization is not valid\n");
226.1663 + if (!tr)
226.1664 + { /* solve the system F*x = b */
226.1665 + for (j = 1; j <= n; j++)
226.1666 + { k = pp_row[j];
226.1667 + xk = x[k];
226.1668 + if (xk != 0.0)
226.1669 + { beg = fc_ptr[k];
226.1670 + end = beg + fc_len[k] - 1;
226.1671 + for (ptr = beg; ptr <= end; ptr++)
226.1672 + x[sv_ind[ptr]] -= sv_val[ptr] * xk;
226.1673 + }
226.1674 + }
226.1675 + }
226.1676 + else
226.1677 + { /* solve the system F'*x = b */
226.1678 + for (i = n; i >= 1; i--)
226.1679 + { k = pp_row[i];
226.1680 + xk = x[k];
226.1681 + if (xk != 0.0)
226.1682 + { beg = fr_ptr[k];
226.1683 + end = beg + fr_len[k] - 1;
226.1684 + for (ptr = beg; ptr <= end; ptr++)
226.1685 + x[sv_ind[ptr]] -= sv_val[ptr] * xk;
226.1686 + }
226.1687 + }
226.1688 + }
226.1689 + return;
226.1690 +}
226.1691 +
226.1692 +/***********************************************************************
226.1693 +* NAME
226.1694 +*
226.1695 +* luf_v_solve - solve system V*x = b or V'*x = b
226.1696 +*
226.1697 +* SYNOPSIS
226.1698 +*
226.1699 +* #include "glpluf.h"
226.1700 +* void luf_v_solve(LUF *luf, int tr, double x[]);
226.1701 +*
226.1702 +* DESCRIPTION
226.1703 +*
226.1704 +* The routine luf_v_solve solves either the system V*x = b (if the
226.1705 +* flag tr is zero) or the system V'*x = b (if the flag tr is non-zero),
226.1706 +* where the matrix V is a component of LU-factorization specified by
226.1707 +* the parameter luf, V' is a matrix transposed to V.
226.1708 +*
226.1709 +* On entry the array x should contain elements of the right-hand side
226.1710 +* vector b in locations x[1], ..., x[n], where n is the order of the
226.1711 +* matrix V. On exit this array will contain elements of the solution
226.1712 +* vector x in the same locations. */
226.1713 +
226.1714 +void luf_v_solve(LUF *luf, int tr, double x[])
226.1715 +{ int n = luf->n;
226.1716 + int *vr_ptr = luf->vr_ptr;
226.1717 + int *vr_len = luf->vr_len;
226.1718 + double *vr_piv = luf->vr_piv;
226.1719 + int *vc_ptr = luf->vc_ptr;
226.1720 + int *vc_len = luf->vc_len;
226.1721 + int *pp_row = luf->pp_row;
226.1722 + int *qq_col = luf->qq_col;
226.1723 + int *sv_ind = luf->sv_ind;
226.1724 + double *sv_val = luf->sv_val;
226.1725 + double *b = luf->work;
226.1726 + int i, j, k, beg, end, ptr;
226.1727 + double temp;
226.1728 + if (!luf->valid)
226.1729 + xfault("luf_v_solve: LU-factorization is not valid\n");
226.1730 + for (k = 1; k <= n; k++) b[k] = x[k], x[k] = 0.0;
226.1731 + if (!tr)
226.1732 + { /* solve the system V*x = b */
226.1733 + for (k = n; k >= 1; k--)
226.1734 + { i = pp_row[k], j = qq_col[k];
226.1735 + temp = b[i];
226.1736 + if (temp != 0.0)
226.1737 + { x[j] = (temp /= vr_piv[i]);
226.1738 + beg = vc_ptr[j];
226.1739 + end = beg + vc_len[j] - 1;
226.1740 + for (ptr = beg; ptr <= end; ptr++)
226.1741 + b[sv_ind[ptr]] -= sv_val[ptr] * temp;
226.1742 + }
226.1743 + }
226.1744 + }
226.1745 + else
226.1746 + { /* solve the system V'*x = b */
226.1747 + for (k = 1; k <= n; k++)
226.1748 + { i = pp_row[k], j = qq_col[k];
226.1749 + temp = b[j];
226.1750 + if (temp != 0.0)
226.1751 + { x[i] = (temp /= vr_piv[i]);
226.1752 + beg = vr_ptr[i];
226.1753 + end = beg + vr_len[i] - 1;
226.1754 + for (ptr = beg; ptr <= end; ptr++)
226.1755 + b[sv_ind[ptr]] -= sv_val[ptr] * temp;
226.1756 + }
226.1757 + }
226.1758 + }
226.1759 + return;
226.1760 +}
226.1761 +
226.1762 +/***********************************************************************
226.1763 +* NAME
226.1764 +*
226.1765 +* luf_a_solve - solve system A*x = b or A'*x = b
226.1766 +*
226.1767 +* SYNOPSIS
226.1768 +*
226.1769 +* #include "glpluf.h"
226.1770 +* void luf_a_solve(LUF *luf, int tr, double x[]);
226.1771 +*
226.1772 +* DESCRIPTION
226.1773 +*
226.1774 +* The routine luf_a_solve solves either the system A*x = b (if the
226.1775 +* flag tr is zero) or the system A'*x = b (if the flag tr is non-zero),
226.1776 +* where the parameter luf specifies LU-factorization of the matrix A,
226.1777 +* A' is a matrix transposed to A.
226.1778 +*
226.1779 +* On entry the array x should contain elements of the right-hand side
226.1780 +* vector b in locations x[1], ..., x[n], where n is the order of the
226.1781 +* matrix A. On exit this array will contain elements of the solution
226.1782 +* vector x in the same locations. */
226.1783 +
226.1784 +void luf_a_solve(LUF *luf, int tr, double x[])
226.1785 +{ if (!luf->valid)
226.1786 + xfault("luf_a_solve: LU-factorization is not valid\n");
226.1787 + if (!tr)
226.1788 + { /* A = F*V, therefore inv(A) = inv(V)*inv(F) */
226.1789 + luf_f_solve(luf, 0, x);
226.1790 + luf_v_solve(luf, 0, x);
226.1791 + }
226.1792 + else
226.1793 + { /* A' = V'*F', therefore inv(A') = inv(F')*inv(V') */
226.1794 + luf_v_solve(luf, 1, x);
226.1795 + luf_f_solve(luf, 1, x);
226.1796 + }
226.1797 + return;
226.1798 +}
226.1799 +
226.1800 +/***********************************************************************
226.1801 +* NAME
226.1802 +*
226.1803 +* luf_delete_it - delete LU-factorization
226.1804 +*
226.1805 +* SYNOPSIS
226.1806 +*
226.1807 +* #include "glpluf.h"
226.1808 +* void luf_delete_it(LUF *luf);
226.1809 +*
226.1810 +* DESCRIPTION
226.1811 +*
226.1812 +* The routine luf_delete deletes LU-factorization specified by the
226.1813 +* parameter luf and frees all the memory allocated to this program
226.1814 +* object. */
226.1815 +
226.1816 +void luf_delete_it(LUF *luf)
226.1817 +{ if (luf->fr_ptr != NULL) xfree(luf->fr_ptr);
226.1818 + if (luf->fr_len != NULL) xfree(luf->fr_len);
226.1819 + if (luf->fc_ptr != NULL) xfree(luf->fc_ptr);
226.1820 + if (luf->fc_len != NULL) xfree(luf->fc_len);
226.1821 + if (luf->vr_ptr != NULL) xfree(luf->vr_ptr);
226.1822 + if (luf->vr_len != NULL) xfree(luf->vr_len);
226.1823 + if (luf->vr_cap != NULL) xfree(luf->vr_cap);
226.1824 + if (luf->vr_piv != NULL) xfree(luf->vr_piv);
226.1825 + if (luf->vc_ptr != NULL) xfree(luf->vc_ptr);
226.1826 + if (luf->vc_len != NULL) xfree(luf->vc_len);
226.1827 + if (luf->vc_cap != NULL) xfree(luf->vc_cap);
226.1828 + if (luf->pp_row != NULL) xfree(luf->pp_row);
226.1829 + if (luf->pp_col != NULL) xfree(luf->pp_col);
226.1830 + if (luf->qq_row != NULL) xfree(luf->qq_row);
226.1831 + if (luf->qq_col != NULL) xfree(luf->qq_col);
226.1832 + if (luf->sv_ind != NULL) xfree(luf->sv_ind);
226.1833 + if (luf->sv_val != NULL) xfree(luf->sv_val);
226.1834 + if (luf->sv_prev != NULL) xfree(luf->sv_prev);
226.1835 + if (luf->sv_next != NULL) xfree(luf->sv_next);
226.1836 + if (luf->vr_max != NULL) xfree(luf->vr_max);
226.1837 + if (luf->rs_head != NULL) xfree(luf->rs_head);
226.1838 + if (luf->rs_prev != NULL) xfree(luf->rs_prev);
226.1839 + if (luf->rs_next != NULL) xfree(luf->rs_next);
226.1840 + if (luf->cs_head != NULL) xfree(luf->cs_head);
226.1841 + if (luf->cs_prev != NULL) xfree(luf->cs_prev);
226.1842 + if (luf->cs_next != NULL) xfree(luf->cs_next);
226.1843 + if (luf->flag != NULL) xfree(luf->flag);
226.1844 + if (luf->work != NULL) xfree(luf->work);
226.1845 + xfree(luf);
226.1846 + return;
226.1847 +}
226.1848 +
226.1849 +/* eof */
227.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
227.2 +++ b/src/glpluf.h Mon Dec 06 13:09:21 2010 +0100
227.3 @@ -0,0 +1,326 @@
227.4 +/* glpluf.h (LU-factorization) */
227.5 +
227.6 +/***********************************************************************
227.7 +* This code is part of GLPK (GNU Linear Programming Kit).
227.8 +*
227.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
227.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
227.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
227.12 +* E-mail: <mao@gnu.org>.
227.13 +*
227.14 +* GLPK is free software: you can redistribute it and/or modify it
227.15 +* under the terms of the GNU General Public License as published by
227.16 +* the Free Software Foundation, either version 3 of the License, or
227.17 +* (at your option) any later version.
227.18 +*
227.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
227.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
227.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
227.22 +* License for more details.
227.23 +*
227.24 +* You should have received a copy of the GNU General Public License
227.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
227.26 +***********************************************************************/
227.27 +
227.28 +#ifndef GLPLUF_H
227.29 +#define GLPLUF_H
227.30 +
227.31 +/***********************************************************************
227.32 +* The structure LUF defines LU-factorization of a square matrix A and
227.33 +* is the following quartet:
227.34 +*
227.35 +* [A] = (F, V, P, Q), (1)
227.36 +*
227.37 +* where F and V are such matrices that
227.38 +*
227.39 +* A = F * V, (2)
227.40 +*
227.41 +* and P and Q are such permutation matrices that the matrix
227.42 +*
227.43 +* L = P * F * inv(P) (3)
227.44 +*
227.45 +* is lower triangular with unity diagonal, and the matrix
227.46 +*
227.47 +* U = P * V * Q (4)
227.48 +*
227.49 +* is upper triangular. All the matrices have the order n.
227.50 +*
227.51 +* Matrices F and V are stored in row- and column-wise sparse format
227.52 +* as row and column linked lists of non-zero elements. Unity elements
227.53 +* on the main diagonal of matrix F are not stored. Pivot elements of
227.54 +* matrix V (which correspond to diagonal elements of matrix U) are
227.55 +* stored separately in an ordinary array.
227.56 +*
227.57 +* Permutation matrices P and Q are stored in ordinary arrays in both
227.58 +* row- and column-like formats.
227.59 +*
227.60 +* Matrices L and U are completely defined by matrices F, V, P, and Q
227.61 +* and therefore not stored explicitly.
227.62 +*
227.63 +* The factorization (1)-(4) is a version of LU-factorization. Indeed,
227.64 +* from (3) and (4) it follows that:
227.65 +*
227.66 +* F = inv(P) * L * P,
227.67 +*
227.68 +* U = inv(P) * U * inv(Q),
227.69 +*
227.70 +* and substitution into (2) leads to:
227.71 +*
227.72 +* A = F * V = inv(P) * L * U * inv(Q).
227.73 +*
227.74 +* For more details see the program documentation. */
227.75 +
227.76 +typedef struct LUF LUF;
227.77 +
227.78 +struct LUF
227.79 +{ /* LU-factorization of a square matrix */
227.80 + int n_max;
227.81 + /* maximal value of n (increased automatically, if necessary) */
227.82 + int n;
227.83 + /* the order of matrices A, F, V, P, Q */
227.84 + int valid;
227.85 + /* the factorization is valid only if this flag is set */
227.86 + /*--------------------------------------------------------------*/
227.87 + /* matrix F in row-wise format */
227.88 + int *fr_ptr; /* int fr_ptr[1+n_max]; */
227.89 + /* fr_ptr[i], i = 1,...,n, is a pointer to the first element of
227.90 + i-th row in SVA */
227.91 + int *fr_len; /* int fr_len[1+n_max]; */
227.92 + /* fr_len[i], i = 1,...,n, is the number of elements in i-th row
227.93 + (except unity diagonal element) */
227.94 + /*--------------------------------------------------------------*/
227.95 + /* matrix F in column-wise format */
227.96 + int *fc_ptr; /* int fc_ptr[1+n_max]; */
227.97 + /* fc_ptr[j], j = 1,...,n, is a pointer to the first element of
227.98 + j-th column in SVA */
227.99 + int *fc_len; /* int fc_len[1+n_max]; */
227.100 + /* fc_len[j], j = 1,...,n, is the number of elements in j-th
227.101 + column (except unity diagonal element) */
227.102 + /*--------------------------------------------------------------*/
227.103 + /* matrix V in row-wise format */
227.104 + int *vr_ptr; /* int vr_ptr[1+n_max]; */
227.105 + /* vr_ptr[i], i = 1,...,n, is a pointer to the first element of
227.106 + i-th row in SVA */
227.107 + int *vr_len; /* int vr_len[1+n_max]; */
227.108 + /* vr_len[i], i = 1,...,n, is the number of elements in i-th row
227.109 + (except pivot element) */
227.110 + int *vr_cap; /* int vr_cap[1+n_max]; */
227.111 + /* vr_cap[i], i = 1,...,n, is the capacity of i-th row, i.e.
227.112 + maximal number of elements which can be stored in the row
227.113 + without relocating it, vr_cap[i] >= vr_len[i] */
227.114 + double *vr_piv; /* double vr_piv[1+n_max]; */
227.115 + /* vr_piv[p], p = 1,...,n, is the pivot element v[p,q] which
227.116 + corresponds to a diagonal element of matrix U = P*V*Q */
227.117 + /*--------------------------------------------------------------*/
227.118 + /* matrix V in column-wise format */
227.119 + int *vc_ptr; /* int vc_ptr[1+n_max]; */
227.120 + /* vc_ptr[j], j = 1,...,n, is a pointer to the first element of
227.121 + j-th column in SVA */
227.122 + int *vc_len; /* int vc_len[1+n_max]; */
227.123 + /* vc_len[j], j = 1,...,n, is the number of elements in j-th
227.124 + column (except pivot element) */
227.125 + int *vc_cap; /* int vc_cap[1+n_max]; */
227.126 + /* vc_cap[j], j = 1,...,n, is the capacity of j-th column, i.e.
227.127 + maximal number of elements which can be stored in the column
227.128 + without relocating it, vc_cap[j] >= vc_len[j] */
227.129 + /*--------------------------------------------------------------*/
227.130 + /* matrix P */
227.131 + int *pp_row; /* int pp_row[1+n_max]; */
227.132 + /* pp_row[i] = j means that P[i,j] = 1 */
227.133 + int *pp_col; /* int pp_col[1+n_max]; */
227.134 + /* pp_col[j] = i means that P[i,j] = 1 */
227.135 + /* if i-th row or column of matrix F is i'-th row or column of
227.136 + matrix L, or if i-th row of matrix V is i'-th row of matrix U,
227.137 + then pp_row[i'] = i and pp_col[i] = i' */
227.138 + /*--------------------------------------------------------------*/
227.139 + /* matrix Q */
227.140 + int *qq_row; /* int qq_row[1+n_max]; */
227.141 + /* qq_row[i] = j means that Q[i,j] = 1 */
227.142 + int *qq_col; /* int qq_col[1+n_max]; */
227.143 + /* qq_col[j] = i means that Q[i,j] = 1 */
227.144 + /* if j-th column of matrix V is j'-th column of matrix U, then
227.145 + qq_row[j] = j' and qq_col[j'] = j */
227.146 + /*--------------------------------------------------------------*/
227.147 + /* the Sparse Vector Area (SVA) is a set of locations used to
227.148 + store sparse vectors representing rows and columns of matrices
227.149 + F and V; each location is a doublet (ind, val), where ind is
227.150 + an index, and val is a numerical value of a sparse vector
227.151 + element; in the whole each sparse vector is a set of adjacent
227.152 + locations defined by a pointer to the first element and the
227.153 + number of elements; these pointer and number are stored in the
227.154 + corresponding matrix data structure (see above); the left part
227.155 + of SVA is used to store rows and columns of matrix V, and its
227.156 + right part is used to store rows and columns of matrix F; the
227.157 + middle part of SVA contains free (unused) locations */
227.158 + int sv_size;
227.159 + /* the size of SVA, in locations; all locations are numbered by
227.160 + integers 1, ..., n, and location 0 is not used; if necessary,
227.161 + the SVA size is automatically increased */
227.162 + int sv_beg, sv_end;
227.163 + /* SVA partitioning pointers:
227.164 + locations from 1 to sv_beg-1 belong to the left part
227.165 + locations from sv_beg to sv_end-1 belong to the middle part
227.166 + locations from sv_end to sv_size belong to the right part
227.167 + the size of the middle part is (sv_end - sv_beg) */
227.168 + int *sv_ind; /* sv_ind[1+sv_size]; */
227.169 + /* sv_ind[k], 1 <= k <= sv_size, is the index field of k-th
227.170 + location */
227.171 + double *sv_val; /* sv_val[1+sv_size]; */
227.172 + /* sv_val[k], 1 <= k <= sv_size, is the value field of k-th
227.173 + location */
227.174 + /*--------------------------------------------------------------*/
227.175 + /* in order to efficiently defragment the left part of SVA there
227.176 + is a doubly linked list of rows and columns of matrix V, where
227.177 + rows are numbered by 1, ..., n, while columns are numbered by
227.178 + n+1, ..., n+n, that allows uniquely identifying each row and
227.179 + column of V by only one integer; in this list rows and columns
227.180 + are ordered by ascending their pointers vr_ptr and vc_ptr */
227.181 + int sv_head;
227.182 + /* the number of leftmost row/column */
227.183 + int sv_tail;
227.184 + /* the number of rightmost row/column */
227.185 + int *sv_prev; /* int sv_prev[1+n_max+n_max]; */
227.186 + /* sv_prev[k], k = 1,...,n+n, is the number of a row/column which
227.187 + precedes k-th row/column */
227.188 + int *sv_next; /* int sv_next[1+n_max+n_max]; */
227.189 + /* sv_next[k], k = 1,...,n+n, is the number of a row/column which
227.190 + succedes k-th row/column */
227.191 + /*--------------------------------------------------------------*/
227.192 + /* working segment (used only during factorization) */
227.193 + double *vr_max; /* int vr_max[1+n_max]; */
227.194 + /* vr_max[i], 1 <= i <= n, is used only if i-th row of matrix V
227.195 + is active (i.e. belongs to the active submatrix), and is the
227.196 + largest magnitude of elements in i-th row; if vr_max[i] < 0,
227.197 + the largest magnitude is not known yet and should be computed
227.198 + by the pivoting routine */
227.199 + /*--------------------------------------------------------------*/
227.200 + /* in order to efficiently implement Markowitz strategy and Duff
227.201 + search technique there are two families {R[0], R[1], ..., R[n]}
227.202 + and {C[0], C[1], ..., C[n]}; member R[k] is the set of active
227.203 + rows of matrix V, which have k non-zeros, and member C[k] is
227.204 + the set of active columns of V, which have k non-zeros in the
227.205 + active submatrix (i.e. in the active rows); each set R[k] and
227.206 + C[k] is implemented as a separate doubly linked list */
227.207 + int *rs_head; /* int rs_head[1+n_max]; */
227.208 + /* rs_head[k], 0 <= k <= n, is the number of first active row,
227.209 + which has k non-zeros */
227.210 + int *rs_prev; /* int rs_prev[1+n_max]; */
227.211 + /* rs_prev[i], 1 <= i <= n, is the number of previous row, which
227.212 + has the same number of non-zeros as i-th row */
227.213 + int *rs_next; /* int rs_next[1+n_max]; */
227.214 + /* rs_next[i], 1 <= i <= n, is the number of next row, which has
227.215 + the same number of non-zeros as i-th row */
227.216 + int *cs_head; /* int cs_head[1+n_max]; */
227.217 + /* cs_head[k], 0 <= k <= n, is the number of first active column,
227.218 + which has k non-zeros (in the active rows) */
227.219 + int *cs_prev; /* int cs_prev[1+n_max]; */
227.220 + /* cs_prev[j], 1 <= j <= n, is the number of previous column,
227.221 + which has the same number of non-zeros (in the active rows) as
227.222 + j-th column */
227.223 + int *cs_next; /* int cs_next[1+n_max]; */
227.224 + /* cs_next[j], 1 <= j <= n, is the number of next column, which
227.225 + has the same number of non-zeros (in the active rows) as j-th
227.226 + column */
227.227 + /* (end of working segment) */
227.228 + /*--------------------------------------------------------------*/
227.229 + /* working arrays */
227.230 + int *flag; /* int flag[1+n_max]; */
227.231 + /* integer working array */
227.232 + double *work; /* double work[1+n_max]; */
227.233 + /* floating-point working array */
227.234 + /*--------------------------------------------------------------*/
227.235 + /* control parameters */
227.236 + int new_sva;
227.237 + /* new required size of the sparse vector area, in locations; set
227.238 + automatically by the factorizing routine */
227.239 + double piv_tol;
227.240 + /* threshold pivoting tolerance, 0 < piv_tol < 1; element v[i,j]
227.241 + of the active submatrix fits to be pivot if it satisfies to the
227.242 + stability criterion |v[i,j]| >= piv_tol * max |v[i,*]|, i.e. if
227.243 + it is not very small in the magnitude among other elements in
227.244 + the same row; decreasing this parameter gives better sparsity
227.245 + at the expense of numerical accuracy and vice versa */
227.246 + int piv_lim;
227.247 + /* maximal allowable number of pivot candidates to be considered;
227.248 + if piv_lim pivot candidates have been considered, the pivoting
227.249 + routine terminates the search with the best candidate found */
227.250 + int suhl;
227.251 + /* if this flag is set, the pivoting routine applies a heuristic
227.252 + proposed by Uwe Suhl: if a column of the active submatrix has
227.253 + no eligible pivot candidates (i.e. all its elements do not
227.254 + satisfy to the stability criterion), the routine excludes it
227.255 + from futher consideration until it becomes column singleton;
227.256 + in many cases this allows reducing the time needed for pivot
227.257 + searching */
227.258 + double eps_tol;
227.259 + /* epsilon tolerance; each element of the active submatrix, whose
227.260 + magnitude is less than eps_tol, is replaced by exact zero */
227.261 + double max_gro;
227.262 + /* maximal allowable growth of elements of matrix V during all
227.263 + the factorization process; if on some eliminaion step the ratio
227.264 + big_v / max_a (see below) becomes greater than max_gro, matrix
227.265 + A is considered as ill-conditioned (assuming that the pivoting
227.266 + tolerance piv_tol has an appropriate value) */
227.267 + /*--------------------------------------------------------------*/
227.268 + /* some statistics */
227.269 + int nnz_a;
227.270 + /* the number of non-zeros in matrix A */
227.271 + int nnz_f;
227.272 + /* the number of non-zeros in matrix F (except diagonal elements,
227.273 + which are not stored) */
227.274 + int nnz_v;
227.275 + /* the number of non-zeros in matrix V (except its pivot elements,
227.276 + which are stored in a separate array) */
227.277 + double max_a;
227.278 + /* the largest magnitude of elements of matrix A */
227.279 + double big_v;
227.280 + /* the largest magnitude of elements of matrix V appeared in the
227.281 + active submatrix during all the factorization process */
227.282 + int rank;
227.283 + /* estimated rank of matrix A */
227.284 +};
227.285 +
227.286 +/* return codes: */
227.287 +#define LUF_ESING 1 /* singular matrix */
227.288 +#define LUF_ECOND 2 /* ill-conditioned matrix */
227.289 +
227.290 +#define luf_create_it _glp_luf_create_it
227.291 +LUF *luf_create_it(void);
227.292 +/* create LU-factorization */
227.293 +
227.294 +#define luf_defrag_sva _glp_luf_defrag_sva
227.295 +void luf_defrag_sva(LUF *luf);
227.296 +/* defragment the sparse vector area */
227.297 +
227.298 +#define luf_enlarge_row _glp_luf_enlarge_row
227.299 +int luf_enlarge_row(LUF *luf, int i, int cap);
227.300 +/* enlarge row capacity */
227.301 +
227.302 +#define luf_enlarge_col _glp_luf_enlarge_col
227.303 +int luf_enlarge_col(LUF *luf, int j, int cap);
227.304 +/* enlarge column capacity */
227.305 +
227.306 +#define luf_factorize _glp_luf_factorize
227.307 +int luf_factorize(LUF *luf, int n, int (*col)(void *info, int j,
227.308 + int ind[], double val[]), void *info);
227.309 +/* compute LU-factorization */
227.310 +
227.311 +#define luf_f_solve _glp_luf_f_solve
227.312 +void luf_f_solve(LUF *luf, int tr, double x[]);
227.313 +/* solve system F*x = b or F'*x = b */
227.314 +
227.315 +#define luf_v_solve _glp_luf_v_solve
227.316 +void luf_v_solve(LUF *luf, int tr, double x[]);
227.317 +/* solve system V*x = b or V'*x = b */
227.318 +
227.319 +#define luf_a_solve _glp_luf_a_solve
227.320 +void luf_a_solve(LUF *luf, int tr, double x[]);
227.321 +/* solve system A*x = b or A'*x = b */
227.322 +
227.323 +#define luf_delete_it _glp_luf_delete_it
227.324 +void luf_delete_it(LUF *luf);
227.325 +/* delete LU-factorization */
227.326 +
227.327 +#endif
227.328 +
227.329 +/* eof */
228.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
228.2 +++ b/src/glplux.c Mon Dec 06 13:09:21 2010 +0100
228.3 @@ -0,0 +1,1028 @@
228.4 +/* glplux.c */
228.5 +
228.6 +/***********************************************************************
228.7 +* This code is part of GLPK (GNU Linear Programming Kit).
228.8 +*
228.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
228.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
228.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
228.12 +* E-mail: <mao@gnu.org>.
228.13 +*
228.14 +* GLPK is free software: you can redistribute it and/or modify it
228.15 +* under the terms of the GNU General Public License as published by
228.16 +* the Free Software Foundation, either version 3 of the License, or
228.17 +* (at your option) any later version.
228.18 +*
228.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
228.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
228.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
228.22 +* License for more details.
228.23 +*
228.24 +* You should have received a copy of the GNU General Public License
228.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
228.26 +***********************************************************************/
228.27 +
228.28 +#include "glplux.h"
228.29 +#define xfault xerror
228.30 +#define dmp_create_poolx(size) dmp_create_pool()
228.31 +
228.32 +/*----------------------------------------------------------------------
228.33 +// lux_create - create LU-factorization.
228.34 +//
228.35 +// SYNOPSIS
228.36 +//
228.37 +// #include "glplux.h"
228.38 +// LUX *lux_create(int n);
228.39 +//
228.40 +// DESCRIPTION
228.41 +//
228.42 +// The routine lux_create creates LU-factorization data structure for
228.43 +// a matrix of the order n. Initially the factorization corresponds to
228.44 +// the unity matrix (F = V = P = Q = I, so A = I).
228.45 +//
228.46 +// RETURNS
228.47 +//
228.48 +// The routine returns a pointer to the created LU-factorization data
228.49 +// structure, which represents the unity matrix of the order n. */
228.50 +
228.51 +LUX *lux_create(int n)
228.52 +{ LUX *lux;
228.53 + int k;
228.54 + if (n < 1)
228.55 + xfault("lux_create: n = %d; invalid parameter\n", n);
228.56 + lux = xmalloc(sizeof(LUX));
228.57 + lux->n = n;
228.58 + lux->pool = dmp_create_poolx(sizeof(LUXELM));
228.59 + lux->F_row = xcalloc(1+n, sizeof(LUXELM *));
228.60 + lux->F_col = xcalloc(1+n, sizeof(LUXELM *));
228.61 + lux->V_piv = xcalloc(1+n, sizeof(mpq_t));
228.62 + lux->V_row = xcalloc(1+n, sizeof(LUXELM *));
228.63 + lux->V_col = xcalloc(1+n, sizeof(LUXELM *));
228.64 + lux->P_row = xcalloc(1+n, sizeof(int));
228.65 + lux->P_col = xcalloc(1+n, sizeof(int));
228.66 + lux->Q_row = xcalloc(1+n, sizeof(int));
228.67 + lux->Q_col = xcalloc(1+n, sizeof(int));
228.68 + for (k = 1; k <= n; k++)
228.69 + { lux->F_row[k] = lux->F_col[k] = NULL;
228.70 + mpq_init(lux->V_piv[k]);
228.71 + mpq_set_si(lux->V_piv[k], 1, 1);
228.72 + lux->V_row[k] = lux->V_col[k] = NULL;
228.73 + lux->P_row[k] = lux->P_col[k] = k;
228.74 + lux->Q_row[k] = lux->Q_col[k] = k;
228.75 + }
228.76 + lux->rank = n;
228.77 + return lux;
228.78 +}
228.79 +
228.80 +/*----------------------------------------------------------------------
228.81 +// initialize - initialize LU-factorization data structures.
228.82 +//
228.83 +// This routine initializes data structures for subsequent computing
228.84 +// the LU-factorization of a given matrix A, which is specified by the
228.85 +// formal routine col. On exit V = A and F = P = Q = I, where I is the
228.86 +// unity matrix. */
228.87 +
228.88 +static void initialize(LUX *lux, int (*col)(void *info, int j,
228.89 + int ind[], mpq_t val[]), void *info, LUXWKA *wka)
228.90 +{ int n = lux->n;
228.91 + DMP *pool = lux->pool;
228.92 + LUXELM **F_row = lux->F_row;
228.93 + LUXELM **F_col = lux->F_col;
228.94 + mpq_t *V_piv = lux->V_piv;
228.95 + LUXELM **V_row = lux->V_row;
228.96 + LUXELM **V_col = lux->V_col;
228.97 + int *P_row = lux->P_row;
228.98 + int *P_col = lux->P_col;
228.99 + int *Q_row = lux->Q_row;
228.100 + int *Q_col = lux->Q_col;
228.101 + int *R_len = wka->R_len;
228.102 + int *R_head = wka->R_head;
228.103 + int *R_prev = wka->R_prev;
228.104 + int *R_next = wka->R_next;
228.105 + int *C_len = wka->C_len;
228.106 + int *C_head = wka->C_head;
228.107 + int *C_prev = wka->C_prev;
228.108 + int *C_next = wka->C_next;
228.109 + LUXELM *fij, *vij;
228.110 + int i, j, k, len, *ind;
228.111 + mpq_t *val;
228.112 + /* F := I */
228.113 + for (i = 1; i <= n; i++)
228.114 + { while (F_row[i] != NULL)
228.115 + { fij = F_row[i], F_row[i] = fij->r_next;
228.116 + mpq_clear(fij->val);
228.117 + dmp_free_atom(pool, fij, sizeof(LUXELM));
228.118 + }
228.119 + }
228.120 + for (j = 1; j <= n; j++) F_col[j] = NULL;
228.121 + /* V := 0 */
228.122 + for (k = 1; k <= n; k++) mpq_set_si(V_piv[k], 0, 1);
228.123 + for (i = 1; i <= n; i++)
228.124 + { while (V_row[i] != NULL)
228.125 + { vij = V_row[i], V_row[i] = vij->r_next;
228.126 + mpq_clear(vij->val);
228.127 + dmp_free_atom(pool, vij, sizeof(LUXELM));
228.128 + }
228.129 + }
228.130 + for (j = 1; j <= n; j++) V_col[j] = NULL;
228.131 + /* V := A */
228.132 + ind = xcalloc(1+n, sizeof(int));
228.133 + val = xcalloc(1+n, sizeof(mpq_t));
228.134 + for (k = 1; k <= n; k++) mpq_init(val[k]);
228.135 + for (j = 1; j <= n; j++)
228.136 + { /* obtain j-th column of matrix A */
228.137 + len = col(info, j, ind, val);
228.138 + if (!(0 <= len && len <= n))
228.139 + xfault("lux_decomp: j = %d: len = %d; invalid column length"
228.140 + "\n", j, len);
228.141 + /* copy elements of j-th column to matrix V */
228.142 + for (k = 1; k <= len; k++)
228.143 + { /* get row index of a[i,j] */
228.144 + i = ind[k];
228.145 + if (!(1 <= i && i <= n))
228.146 + xfault("lux_decomp: j = %d: i = %d; row index out of ran"
228.147 + "ge\n", j, i);
228.148 + /* check for duplicate indices */
228.149 + if (V_row[i] != NULL && V_row[i]->j == j)
228.150 + xfault("lux_decomp: j = %d: i = %d; duplicate row indice"
228.151 + "s not allowed\n", j, i);
228.152 + /* check for zero value */
228.153 + if (mpq_sgn(val[k]) == 0)
228.154 + xfault("lux_decomp: j = %d: i = %d; zero elements not al"
228.155 + "lowed\n", j, i);
228.156 + /* add new element v[i,j] = a[i,j] to V */
228.157 + vij = dmp_get_atom(pool, sizeof(LUXELM));
228.158 + vij->i = i, vij->j = j;
228.159 + mpq_init(vij->val);
228.160 + mpq_set(vij->val, val[k]);
228.161 + vij->r_prev = NULL;
228.162 + vij->r_next = V_row[i];
228.163 + vij->c_prev = NULL;
228.164 + vij->c_next = V_col[j];
228.165 + if (vij->r_next != NULL) vij->r_next->r_prev = vij;
228.166 + if (vij->c_next != NULL) vij->c_next->c_prev = vij;
228.167 + V_row[i] = V_col[j] = vij;
228.168 + }
228.169 + }
228.170 + xfree(ind);
228.171 + for (k = 1; k <= n; k++) mpq_clear(val[k]);
228.172 + xfree(val);
228.173 + /* P := Q := I */
228.174 + for (k = 1; k <= n; k++)
228.175 + P_row[k] = P_col[k] = Q_row[k] = Q_col[k] = k;
228.176 + /* the rank of A and V is not determined yet */
228.177 + lux->rank = -1;
228.178 + /* initially the entire matrix V is active */
228.179 + /* determine its row lengths */
228.180 + for (i = 1; i <= n; i++)
228.181 + { len = 0;
228.182 + for (vij = V_row[i]; vij != NULL; vij = vij->r_next) len++;
228.183 + R_len[i] = len;
228.184 + }
228.185 + /* build linked lists of active rows */
228.186 + for (len = 0; len <= n; len++) R_head[len] = 0;
228.187 + for (i = 1; i <= n; i++)
228.188 + { len = R_len[i];
228.189 + R_prev[i] = 0;
228.190 + R_next[i] = R_head[len];
228.191 + if (R_next[i] != 0) R_prev[R_next[i]] = i;
228.192 + R_head[len] = i;
228.193 + }
228.194 + /* determine its column lengths */
228.195 + for (j = 1; j <= n; j++)
228.196 + { len = 0;
228.197 + for (vij = V_col[j]; vij != NULL; vij = vij->c_next) len++;
228.198 + C_len[j] = len;
228.199 + }
228.200 + /* build linked lists of active columns */
228.201 + for (len = 0; len <= n; len++) C_head[len] = 0;
228.202 + for (j = 1; j <= n; j++)
228.203 + { len = C_len[j];
228.204 + C_prev[j] = 0;
228.205 + C_next[j] = C_head[len];
228.206 + if (C_next[j] != 0) C_prev[C_next[j]] = j;
228.207 + C_head[len] = j;
228.208 + }
228.209 + return;
228.210 +}
228.211 +
228.212 +/*----------------------------------------------------------------------
228.213 +// find_pivot - choose a pivot element.
228.214 +//
228.215 +// This routine chooses a pivot element v[p,q] in the active submatrix
228.216 +// of matrix U = P*V*Q.
228.217 +//
228.218 +// It is assumed that on entry the matrix U has the following partially
228.219 +// triangularized form:
228.220 +//
228.221 +// 1 k n
228.222 +// 1 x x x x x x x x x x
228.223 +// . x x x x x x x x x
228.224 +// . . x x x x x x x x
228.225 +// . . . x x x x x x x
228.226 +// k . . . . * * * * * *
228.227 +// . . . . * * * * * *
228.228 +// . . . . * * * * * *
228.229 +// . . . . * * * * * *
228.230 +// . . . . * * * * * *
228.231 +// n . . . . * * * * * *
228.232 +//
228.233 +// where rows and columns k, k+1, ..., n belong to the active submatrix
228.234 +// (elements of the active submatrix are marked by '*').
228.235 +//
228.236 +// Since the matrix U = P*V*Q is not stored, the routine works with the
228.237 +// matrix V. It is assumed that the row-wise representation corresponds
228.238 +// to the matrix V, but the column-wise representation corresponds to
228.239 +// the active submatrix of the matrix V, i.e. elements of the matrix V,
228.240 +// which does not belong to the active submatrix, are missing from the
228.241 +// column linked lists. It is also assumed that each active row of the
228.242 +// matrix V is in the set R[len], where len is number of non-zeros in
228.243 +// the row, and each active column of the matrix V is in the set C[len],
228.244 +// where len is number of non-zeros in the column (in the latter case
228.245 +// only elements of the active submatrix are counted; such elements are
228.246 +// marked by '*' on the figure above).
228.247 +//
228.248 +// Due to exact arithmetic any non-zero element of the active submatrix
228.249 +// can be chosen as a pivot. However, to keep sparsity of the matrix V
228.250 +// the routine uses Markowitz strategy, trying to choose such element
228.251 +// v[p,q], which has smallest Markowitz cost (nr[p]-1) * (nc[q]-1),
228.252 +// where nr[p] and nc[q] are the number of non-zero elements, resp., in
228.253 +// p-th row and in q-th column of the active submatrix.
228.254 +//
228.255 +// In order to reduce the search, i.e. not to walk through all elements
228.256 +// of the active submatrix, the routine exploits a technique proposed by
228.257 +// I.Duff. This technique is based on using the sets R[len] and C[len]
228.258 +// of active rows and columns.
228.259 +//
228.260 +// On exit the routine returns a pointer to a pivot v[p,q] chosen, or
228.261 +// NULL, if the active submatrix is empty. */
228.262 +
228.263 +static LUXELM *find_pivot(LUX *lux, LUXWKA *wka)
228.264 +{ int n = lux->n;
228.265 + LUXELM **V_row = lux->V_row;
228.266 + LUXELM **V_col = lux->V_col;
228.267 + int *R_len = wka->R_len;
228.268 + int *R_head = wka->R_head;
228.269 + int *R_next = wka->R_next;
228.270 + int *C_len = wka->C_len;
228.271 + int *C_head = wka->C_head;
228.272 + int *C_next = wka->C_next;
228.273 + LUXELM *piv, *some, *vij;
228.274 + int i, j, len, min_len, ncand, piv_lim = 5;
228.275 + double best, cost;
228.276 + /* nothing is chosen so far */
228.277 + piv = NULL, best = DBL_MAX, ncand = 0;
228.278 + /* if in the active submatrix there is a column that has the only
228.279 + non-zero (column singleton), choose it as a pivot */
228.280 + j = C_head[1];
228.281 + if (j != 0)
228.282 + { xassert(C_len[j] == 1);
228.283 + piv = V_col[j];
228.284 + xassert(piv != NULL && piv->c_next == NULL);
228.285 + goto done;
228.286 + }
228.287 + /* if in the active submatrix there is a row that has the only
228.288 + non-zero (row singleton), choose it as a pivot */
228.289 + i = R_head[1];
228.290 + if (i != 0)
228.291 + { xassert(R_len[i] == 1);
228.292 + piv = V_row[i];
228.293 + xassert(piv != NULL && piv->r_next == NULL);
228.294 + goto done;
228.295 + }
228.296 + /* there are no singletons in the active submatrix; walk through
228.297 + other non-empty rows and columns */
228.298 + for (len = 2; len <= n; len++)
228.299 + { /* consider active columns having len non-zeros */
228.300 + for (j = C_head[len]; j != 0; j = C_next[j])
228.301 + { /* j-th column has len non-zeros */
228.302 + /* find an element in the row of minimal length */
228.303 + some = NULL, min_len = INT_MAX;
228.304 + for (vij = V_col[j]; vij != NULL; vij = vij->c_next)
228.305 + { if (min_len > R_len[vij->i])
228.306 + some = vij, min_len = R_len[vij->i];
228.307 + /* if Markowitz cost of this element is not greater than
228.308 + (len-1)**2, it can be chosen right now; this heuristic
228.309 + reduces the search and works well in many cases */
228.310 + if (min_len <= len)
228.311 + { piv = some;
228.312 + goto done;
228.313 + }
228.314 + }
228.315 + /* j-th column has been scanned */
228.316 + /* the minimal element found is a next pivot candidate */
228.317 + xassert(some != NULL);
228.318 + ncand++;
228.319 + /* compute its Markowitz cost */
228.320 + cost = (double)(min_len - 1) * (double)(len - 1);
228.321 + /* choose between the current candidate and this element */
228.322 + if (cost < best) piv = some, best = cost;
228.323 + /* if piv_lim candidates have been considered, there is a
228.324 + doubt that a much better candidate exists; therefore it
228.325 + is the time to terminate the search */
228.326 + if (ncand == piv_lim) goto done;
228.327 + }
228.328 + /* now consider active rows having len non-zeros */
228.329 + for (i = R_head[len]; i != 0; i = R_next[i])
228.330 + { /* i-th row has len non-zeros */
228.331 + /* find an element in the column of minimal length */
228.332 + some = NULL, min_len = INT_MAX;
228.333 + for (vij = V_row[i]; vij != NULL; vij = vij->r_next)
228.334 + { if (min_len > C_len[vij->j])
228.335 + some = vij, min_len = C_len[vij->j];
228.336 + /* if Markowitz cost of this element is not greater than
228.337 + (len-1)**2, it can be chosen right now; this heuristic
228.338 + reduces the search and works well in many cases */
228.339 + if (min_len <= len)
228.340 + { piv = some;
228.341 + goto done;
228.342 + }
228.343 + }
228.344 + /* i-th row has been scanned */
228.345 + /* the minimal element found is a next pivot candidate */
228.346 + xassert(some != NULL);
228.347 + ncand++;
228.348 + /* compute its Markowitz cost */
228.349 + cost = (double)(len - 1) * (double)(min_len - 1);
228.350 + /* choose between the current candidate and this element */
228.351 + if (cost < best) piv = some, best = cost;
228.352 + /* if piv_lim candidates have been considered, there is a
228.353 + doubt that a much better candidate exists; therefore it
228.354 + is the time to terminate the search */
228.355 + if (ncand == piv_lim) goto done;
228.356 + }
228.357 + }
228.358 +done: /* bring the pivot v[p,q] to the factorizing routine */
228.359 + return piv;
228.360 +}
228.361 +
228.362 +/*----------------------------------------------------------------------
228.363 +// eliminate - perform gaussian elimination.
228.364 +//
228.365 +// This routine performs elementary gaussian transformations in order
228.366 +// to eliminate subdiagonal elements in the k-th column of the matrix
228.367 +// U = P*V*Q using the pivot element u[k,k], where k is the number of
228.368 +// the current elimination step.
228.369 +//
228.370 +// The parameter piv specifies the pivot element v[p,q] = u[k,k].
228.371 +//
228.372 +// Each time when the routine applies the elementary transformation to
228.373 +// a non-pivot row of the matrix V, it stores the corresponding element
228.374 +// to the matrix F in order to keep the main equality A = F*V.
228.375 +//
228.376 +// The routine assumes that on entry the matrices L = P*F*inv(P) and
228.377 +// U = P*V*Q are the following:
228.378 +//
228.379 +// 1 k 1 k n
228.380 +// 1 1 . . . . . . . . . 1 x x x x x x x x x x
228.381 +// x 1 . . . . . . . . . x x x x x x x x x
228.382 +// x x 1 . . . . . . . . . x x x x x x x x
228.383 +// x x x 1 . . . . . . . . . x x x x x x x
228.384 +// k x x x x 1 . . . . . k . . . . * * * * * *
228.385 +// x x x x _ 1 . . . . . . . . # * * * * *
228.386 +// x x x x _ . 1 . . . . . . . # * * * * *
228.387 +// x x x x _ . . 1 . . . . . . # * * * * *
228.388 +// x x x x _ . . . 1 . . . . . # * * * * *
228.389 +// n x x x x _ . . . . 1 n . . . . # * * * * *
228.390 +//
228.391 +// matrix L matrix U
228.392 +//
228.393 +// where rows and columns of the matrix U with numbers k, k+1, ..., n
228.394 +// form the active submatrix (eliminated elements are marked by '#' and
228.395 +// other elements of the active submatrix are marked by '*'). Note that
228.396 +// each eliminated non-zero element u[i,k] of the matrix U gives the
228.397 +// corresponding element l[i,k] of the matrix L (marked by '_').
228.398 +//
228.399 +// Actually all operations are performed on the matrix V. Should note
228.400 +// that the row-wise representation corresponds to the matrix V, but the
228.401 +// column-wise representation corresponds to the active submatrix of the
228.402 +// matrix V, i.e. elements of the matrix V, which doesn't belong to the
228.403 +// active submatrix, are missing from the column linked lists.
228.404 +//
228.405 +// Let u[k,k] = v[p,q] be the pivot. In order to eliminate subdiagonal
228.406 +// elements u[i',k] = v[i,q], i' = k+1, k+2, ..., n, the routine applies
228.407 +// the following elementary gaussian transformations:
228.408 +//
228.409 +// (i-th row of V) := (i-th row of V) - f[i,p] * (p-th row of V),
228.410 +//
228.411 +// where f[i,p] = v[i,q] / v[p,q] is a gaussian multiplier.
228.412 +//
228.413 +// Additionally, in order to keep the main equality A = F*V, each time
228.414 +// when the routine applies the transformation to i-th row of the matrix
228.415 +// V, it also adds f[i,p] as a new element to the matrix F.
228.416 +//
228.417 +// IMPORTANT: On entry the working arrays flag and work should contain
228.418 +// zeros. This status is provided by the routine on exit. */
228.419 +
228.420 +static void eliminate(LUX *lux, LUXWKA *wka, LUXELM *piv, int flag[],
228.421 + mpq_t work[])
228.422 +{ DMP *pool = lux->pool;
228.423 + LUXELM **F_row = lux->F_row;
228.424 + LUXELM **F_col = lux->F_col;
228.425 + mpq_t *V_piv = lux->V_piv;
228.426 + LUXELM **V_row = lux->V_row;
228.427 + LUXELM **V_col = lux->V_col;
228.428 + int *R_len = wka->R_len;
228.429 + int *R_head = wka->R_head;
228.430 + int *R_prev = wka->R_prev;
228.431 + int *R_next = wka->R_next;
228.432 + int *C_len = wka->C_len;
228.433 + int *C_head = wka->C_head;
228.434 + int *C_prev = wka->C_prev;
228.435 + int *C_next = wka->C_next;
228.436 + LUXELM *fip, *vij, *vpj, *viq, *next;
228.437 + mpq_t temp;
228.438 + int i, j, p, q;
228.439 + mpq_init(temp);
228.440 + /* determine row and column indices of the pivot v[p,q] */
228.441 + xassert(piv != NULL);
228.442 + p = piv->i, q = piv->j;
228.443 + /* remove p-th (pivot) row from the active set; it will never
228.444 + return there */
228.445 + if (R_prev[p] == 0)
228.446 + R_head[R_len[p]] = R_next[p];
228.447 + else
228.448 + R_next[R_prev[p]] = R_next[p];
228.449 + if (R_next[p] == 0)
228.450 + ;
228.451 + else
228.452 + R_prev[R_next[p]] = R_prev[p];
228.453 + /* remove q-th (pivot) column from the active set; it will never
228.454 + return there */
228.455 + if (C_prev[q] == 0)
228.456 + C_head[C_len[q]] = C_next[q];
228.457 + else
228.458 + C_next[C_prev[q]] = C_next[q];
228.459 + if (C_next[q] == 0)
228.460 + ;
228.461 + else
228.462 + C_prev[C_next[q]] = C_prev[q];
228.463 + /* store the pivot value in a separate array */
228.464 + mpq_set(V_piv[p], piv->val);
228.465 + /* remove the pivot from p-th row */
228.466 + if (piv->r_prev == NULL)
228.467 + V_row[p] = piv->r_next;
228.468 + else
228.469 + piv->r_prev->r_next = piv->r_next;
228.470 + if (piv->r_next == NULL)
228.471 + ;
228.472 + else
228.473 + piv->r_next->r_prev = piv->r_prev;
228.474 + R_len[p]--;
228.475 + /* remove the pivot from q-th column */
228.476 + if (piv->c_prev == NULL)
228.477 + V_col[q] = piv->c_next;
228.478 + else
228.479 + piv->c_prev->c_next = piv->c_next;
228.480 + if (piv->c_next == NULL)
228.481 + ;
228.482 + else
228.483 + piv->c_next->c_prev = piv->c_prev;
228.484 + C_len[q]--;
228.485 + /* free the space occupied by the pivot */
228.486 + mpq_clear(piv->val);
228.487 + dmp_free_atom(pool, piv, sizeof(LUXELM));
228.488 + /* walk through p-th (pivot) row, which already does not contain
228.489 + the pivot v[p,q], and do the following... */
228.490 + for (vpj = V_row[p]; vpj != NULL; vpj = vpj->r_next)
228.491 + { /* get column index of v[p,j] */
228.492 + j = vpj->j;
228.493 + /* store v[p,j] in the working array */
228.494 + flag[j] = 1;
228.495 + mpq_set(work[j], vpj->val);
228.496 + /* remove j-th column from the active set; it will return there
228.497 + later with a new length */
228.498 + if (C_prev[j] == 0)
228.499 + C_head[C_len[j]] = C_next[j];
228.500 + else
228.501 + C_next[C_prev[j]] = C_next[j];
228.502 + if (C_next[j] == 0)
228.503 + ;
228.504 + else
228.505 + C_prev[C_next[j]] = C_prev[j];
228.506 + /* v[p,j] leaves the active submatrix, so remove it from j-th
228.507 + column; however, v[p,j] is kept in p-th row */
228.508 + if (vpj->c_prev == NULL)
228.509 + V_col[j] = vpj->c_next;
228.510 + else
228.511 + vpj->c_prev->c_next = vpj->c_next;
228.512 + if (vpj->c_next == NULL)
228.513 + ;
228.514 + else
228.515 + vpj->c_next->c_prev = vpj->c_prev;
228.516 + C_len[j]--;
228.517 + }
228.518 + /* now walk through q-th (pivot) column, which already does not
228.519 + contain the pivot v[p,q], and perform gaussian elimination */
228.520 + while (V_col[q] != NULL)
228.521 + { /* element v[i,q] has to be eliminated */
228.522 + viq = V_col[q];
228.523 + /* get row index of v[i,q] */
228.524 + i = viq->i;
228.525 + /* remove i-th row from the active set; later it will return
228.526 + there with a new length */
228.527 + if (R_prev[i] == 0)
228.528 + R_head[R_len[i]] = R_next[i];
228.529 + else
228.530 + R_next[R_prev[i]] = R_next[i];
228.531 + if (R_next[i] == 0)
228.532 + ;
228.533 + else
228.534 + R_prev[R_next[i]] = R_prev[i];
228.535 + /* compute gaussian multiplier f[i,p] = v[i,q] / v[p,q] and
228.536 + store it in the matrix F */
228.537 + fip = dmp_get_atom(pool, sizeof(LUXELM));
228.538 + fip->i = i, fip->j = p;
228.539 + mpq_init(fip->val);
228.540 + mpq_div(fip->val, viq->val, V_piv[p]);
228.541 + fip->r_prev = NULL;
228.542 + fip->r_next = F_row[i];
228.543 + fip->c_prev = NULL;
228.544 + fip->c_next = F_col[p];
228.545 + if (fip->r_next != NULL) fip->r_next->r_prev = fip;
228.546 + if (fip->c_next != NULL) fip->c_next->c_prev = fip;
228.547 + F_row[i] = F_col[p] = fip;
228.548 + /* v[i,q] has to be eliminated, so remove it from i-th row */
228.549 + if (viq->r_prev == NULL)
228.550 + V_row[i] = viq->r_next;
228.551 + else
228.552 + viq->r_prev->r_next = viq->r_next;
228.553 + if (viq->r_next == NULL)
228.554 + ;
228.555 + else
228.556 + viq->r_next->r_prev = viq->r_prev;
228.557 + R_len[i]--;
228.558 + /* and also from q-th column */
228.559 + V_col[q] = viq->c_next;
228.560 + C_len[q]--;
228.561 + /* free the space occupied by v[i,q] */
228.562 + mpq_clear(viq->val);
228.563 + dmp_free_atom(pool, viq, sizeof(LUXELM));
228.564 + /* perform gaussian transformation:
228.565 + (i-th row) := (i-th row) - f[i,p] * (p-th row)
228.566 + note that now p-th row, which is in the working array,
228.567 + does not contain the pivot v[p,q], and i-th row does not
228.568 + contain the element v[i,q] to be eliminated */
228.569 + /* walk through i-th row and transform existing non-zero
228.570 + elements */
228.571 + for (vij = V_row[i]; vij != NULL; vij = next)
228.572 + { next = vij->r_next;
228.573 + /* get column index of v[i,j] */
228.574 + j = vij->j;
228.575 + /* v[i,j] := v[i,j] - f[i,p] * v[p,j] */
228.576 + if (flag[j])
228.577 + { /* v[p,j] != 0 */
228.578 + flag[j] = 0;
228.579 + mpq_mul(temp, fip->val, work[j]);
228.580 + mpq_sub(vij->val, vij->val, temp);
228.581 + if (mpq_sgn(vij->val) == 0)
228.582 + { /* new v[i,j] is zero, so remove it from the active
228.583 + submatrix */
228.584 + /* remove v[i,j] from i-th row */
228.585 + if (vij->r_prev == NULL)
228.586 + V_row[i] = vij->r_next;
228.587 + else
228.588 + vij->r_prev->r_next = vij->r_next;
228.589 + if (vij->r_next == NULL)
228.590 + ;
228.591 + else
228.592 + vij->r_next->r_prev = vij->r_prev;
228.593 + R_len[i]--;
228.594 + /* remove v[i,j] from j-th column */
228.595 + if (vij->c_prev == NULL)
228.596 + V_col[j] = vij->c_next;
228.597 + else
228.598 + vij->c_prev->c_next = vij->c_next;
228.599 + if (vij->c_next == NULL)
228.600 + ;
228.601 + else
228.602 + vij->c_next->c_prev = vij->c_prev;
228.603 + C_len[j]--;
228.604 + /* free the space occupied by v[i,j] */
228.605 + mpq_clear(vij->val);
228.606 + dmp_free_atom(pool, vij, sizeof(LUXELM));
228.607 + }
228.608 + }
228.609 + }
228.610 + /* now flag is the pattern of the set v[p,*] \ v[i,*] */
228.611 + /* walk through p-th (pivot) row and create new elements in
228.612 + i-th row, which appear due to fill-in */
228.613 + for (vpj = V_row[p]; vpj != NULL; vpj = vpj->r_next)
228.614 + { j = vpj->j;
228.615 + if (flag[j])
228.616 + { /* create new non-zero v[i,j] = 0 - f[i,p] * v[p,j] and
228.617 + add it to i-th row and j-th column */
228.618 + vij = dmp_get_atom(pool, sizeof(LUXELM));
228.619 + vij->i = i, vij->j = j;
228.620 + mpq_init(vij->val);
228.621 + mpq_mul(vij->val, fip->val, work[j]);
228.622 + mpq_neg(vij->val, vij->val);
228.623 + vij->r_prev = NULL;
228.624 + vij->r_next = V_row[i];
228.625 + vij->c_prev = NULL;
228.626 + vij->c_next = V_col[j];
228.627 + if (vij->r_next != NULL) vij->r_next->r_prev = vij;
228.628 + if (vij->c_next != NULL) vij->c_next->c_prev = vij;
228.629 + V_row[i] = V_col[j] = vij;
228.630 + R_len[i]++, C_len[j]++;
228.631 + }
228.632 + else
228.633 + { /* there is no fill-in, because v[i,j] already exists in
228.634 + i-th row; restore the flag, which was reset before */
228.635 + flag[j] = 1;
228.636 + }
228.637 + }
228.638 + /* now i-th row has been completely transformed and can return
228.639 + to the active set with a new length */
228.640 + R_prev[i] = 0;
228.641 + R_next[i] = R_head[R_len[i]];
228.642 + if (R_next[i] != 0) R_prev[R_next[i]] = i;
228.643 + R_head[R_len[i]] = i;
228.644 + }
228.645 + /* at this point q-th (pivot) column must be empty */
228.646 + xassert(C_len[q] == 0);
228.647 + /* walk through p-th (pivot) row again and do the following... */
228.648 + for (vpj = V_row[p]; vpj != NULL; vpj = vpj->r_next)
228.649 + { /* get column index of v[p,j] */
228.650 + j = vpj->j;
228.651 + /* erase v[p,j] from the working array */
228.652 + flag[j] = 0;
228.653 + mpq_set_si(work[j], 0, 1);
228.654 + /* now j-th column has been completely transformed, so it can
228.655 + return to the active list with a new length */
228.656 + C_prev[j] = 0;
228.657 + C_next[j] = C_head[C_len[j]];
228.658 + if (C_next[j] != 0) C_prev[C_next[j]] = j;
228.659 + C_head[C_len[j]] = j;
228.660 + }
228.661 + mpq_clear(temp);
228.662 + /* return to the factorizing routine */
228.663 + return;
228.664 +}
228.665 +
228.666 +/*----------------------------------------------------------------------
228.667 +// lux_decomp - compute LU-factorization.
228.668 +//
228.669 +// SYNOPSIS
228.670 +//
228.671 +// #include "glplux.h"
228.672 +// int lux_decomp(LUX *lux, int (*col)(void *info, int j, int ind[],
228.673 +// mpq_t val[]), void *info);
228.674 +//
228.675 +// DESCRIPTION
228.676 +//
228.677 +// The routine lux_decomp computes LU-factorization of a given square
228.678 +// matrix A.
228.679 +//
228.680 +// The parameter lux specifies LU-factorization data structure built by
228.681 +// means of the routine lux_create.
228.682 +//
228.683 +// The formal routine col specifies the original matrix A. In order to
228.684 +// obtain j-th column of the matrix A the routine lux_decomp calls the
228.685 +// routine col with the parameter j (1 <= j <= n, where n is the order
228.686 +// of A). In response the routine col should store row indices and
228.687 +// numerical values of non-zero elements of j-th column of A to the
228.688 +// locations ind[1], ..., ind[len] and val[1], ..., val[len], resp.,
228.689 +// where len is the number of non-zeros in j-th column, which should be
228.690 +// returned on exit. Neiter zero nor duplicate elements are allowed.
228.691 +//
228.692 +// The parameter info is a transit pointer passed to the formal routine
228.693 +// col; it can be used for various purposes.
228.694 +//
228.695 +// RETURNS
228.696 +//
228.697 +// The routine lux_decomp returns the singularity flag. Zero flag means
228.698 +// that the original matrix A is non-singular while non-zero flag means
228.699 +// that A is (exactly!) singular.
228.700 +//
228.701 +// Note that LU-factorization is valid in both cases, however, in case
228.702 +// of singularity some rows of the matrix V (including pivot elements)
228.703 +// will be empty.
228.704 +//
228.705 +// REPAIRING SINGULAR MATRIX
228.706 +//
228.707 +// If the routine lux_decomp returns non-zero flag, it provides all
228.708 +// necessary information that can be used for "repairing" the matrix A,
228.709 +// where "repairing" means replacing linearly dependent columns of the
228.710 +// matrix A by appropriate columns of the unity matrix. This feature is
228.711 +// needed when the routine lux_decomp is used for reinverting the basis
228.712 +// matrix within the simplex method procedure.
228.713 +//
228.714 +// On exit linearly dependent columns of the matrix U have the numbers
228.715 +// rank+1, rank+2, ..., n, where rank is the exact rank of the matrix A
228.716 +// stored by the routine to the member lux->rank. The correspondence
228.717 +// between columns of A and U is the same as between columns of V and U.
228.718 +// Thus, linearly dependent columns of the matrix A have the numbers
228.719 +// Q_col[rank+1], Q_col[rank+2], ..., Q_col[n], where Q_col is an array
228.720 +// representing the permutation matrix Q in column-like format. It is
228.721 +// understood that each j-th linearly dependent column of the matrix U
228.722 +// should be replaced by the unity vector, where all elements are zero
228.723 +// except the unity diagonal element u[j,j]. On the other hand j-th row
228.724 +// of the matrix U corresponds to the row of the matrix V (and therefore
228.725 +// of the matrix A) with the number P_row[j], where P_row is an array
228.726 +// representing the permutation matrix P in row-like format. Thus, each
228.727 +// j-th linearly dependent column of the matrix U should be replaced by
228.728 +// a column of the unity matrix with the number P_row[j].
228.729 +//
228.730 +// The code that repairs the matrix A may look like follows:
228.731 +//
228.732 +// for (j = rank+1; j <= n; j++)
228.733 +// { replace column Q_col[j] of the matrix A by column P_row[j] of
228.734 +// the unity matrix;
228.735 +// }
228.736 +//
228.737 +// where rank, P_row, and Q_col are members of the structure LUX. */
228.738 +
228.739 +int lux_decomp(LUX *lux, int (*col)(void *info, int j, int ind[],
228.740 + mpq_t val[]), void *info)
228.741 +{ int n = lux->n;
228.742 + LUXELM **V_row = lux->V_row;
228.743 + LUXELM **V_col = lux->V_col;
228.744 + int *P_row = lux->P_row;
228.745 + int *P_col = lux->P_col;
228.746 + int *Q_row = lux->Q_row;
228.747 + int *Q_col = lux->Q_col;
228.748 + LUXELM *piv, *vij;
228.749 + LUXWKA *wka;
228.750 + int i, j, k, p, q, t, *flag;
228.751 + mpq_t *work;
228.752 + /* allocate working area */
228.753 + wka = xmalloc(sizeof(LUXWKA));
228.754 + wka->R_len = xcalloc(1+n, sizeof(int));
228.755 + wka->R_head = xcalloc(1+n, sizeof(int));
228.756 + wka->R_prev = xcalloc(1+n, sizeof(int));
228.757 + wka->R_next = xcalloc(1+n, sizeof(int));
228.758 + wka->C_len = xcalloc(1+n, sizeof(int));
228.759 + wka->C_head = xcalloc(1+n, sizeof(int));
228.760 + wka->C_prev = xcalloc(1+n, sizeof(int));
228.761 + wka->C_next = xcalloc(1+n, sizeof(int));
228.762 + /* initialize LU-factorization data structures */
228.763 + initialize(lux, col, info, wka);
228.764 + /* allocate working arrays */
228.765 + flag = xcalloc(1+n, sizeof(int));
228.766 + work = xcalloc(1+n, sizeof(mpq_t));
228.767 + for (k = 1; k <= n; k++)
228.768 + { flag[k] = 0;
228.769 + mpq_init(work[k]);
228.770 + }
228.771 + /* main elimination loop */
228.772 + for (k = 1; k <= n; k++)
228.773 + { /* choose a pivot element v[p,q] */
228.774 + piv = find_pivot(lux, wka);
228.775 + if (piv == NULL)
228.776 + { /* no pivot can be chosen, because the active submatrix is
228.777 + empty */
228.778 + break;
228.779 + }
228.780 + /* determine row and column indices of the pivot element */
228.781 + p = piv->i, q = piv->j;
228.782 + /* let v[p,q] correspond to u[i',j']; permute k-th and i'-th
228.783 + rows and k-th and j'-th columns of the matrix U = P*V*Q to
228.784 + move the element u[i',j'] to the position u[k,k] */
228.785 + i = P_col[p], j = Q_row[q];
228.786 + xassert(k <= i && i <= n && k <= j && j <= n);
228.787 + /* permute k-th and i-th rows of the matrix U */
228.788 + t = P_row[k];
228.789 + P_row[i] = t, P_col[t] = i;
228.790 + P_row[k] = p, P_col[p] = k;
228.791 + /* permute k-th and j-th columns of the matrix U */
228.792 + t = Q_col[k];
228.793 + Q_col[j] = t, Q_row[t] = j;
228.794 + Q_col[k] = q, Q_row[q] = k;
228.795 + /* eliminate subdiagonal elements of k-th column of the matrix
228.796 + U = P*V*Q using the pivot element u[k,k] = v[p,q] */
228.797 + eliminate(lux, wka, piv, flag, work);
228.798 + }
228.799 + /* determine the rank of A (and V) */
228.800 + lux->rank = k - 1;
228.801 + /* free working arrays */
228.802 + xfree(flag);
228.803 + for (k = 1; k <= n; k++) mpq_clear(work[k]);
228.804 + xfree(work);
228.805 + /* build column lists of the matrix V using its row lists */
228.806 + for (j = 1; j <= n; j++)
228.807 + xassert(V_col[j] == NULL);
228.808 + for (i = 1; i <= n; i++)
228.809 + { for (vij = V_row[i]; vij != NULL; vij = vij->r_next)
228.810 + { j = vij->j;
228.811 + vij->c_prev = NULL;
228.812 + vij->c_next = V_col[j];
228.813 + if (vij->c_next != NULL) vij->c_next->c_prev = vij;
228.814 + V_col[j] = vij;
228.815 + }
228.816 + }
228.817 + /* free working area */
228.818 + xfree(wka->R_len);
228.819 + xfree(wka->R_head);
228.820 + xfree(wka->R_prev);
228.821 + xfree(wka->R_next);
228.822 + xfree(wka->C_len);
228.823 + xfree(wka->C_head);
228.824 + xfree(wka->C_prev);
228.825 + xfree(wka->C_next);
228.826 + xfree(wka);
228.827 + /* return to the calling program */
228.828 + return (lux->rank < n);
228.829 +}
228.830 +
228.831 +/*----------------------------------------------------------------------
228.832 +// lux_f_solve - solve system F*x = b or F'*x = b.
228.833 +//
228.834 +// SYNOPSIS
228.835 +//
228.836 +// #include "glplux.h"
228.837 +// void lux_f_solve(LUX *lux, int tr, mpq_t x[]);
228.838 +//
228.839 +// DESCRIPTION
228.840 +//
228.841 +// The routine lux_f_solve solves either the system F*x = b (if the
228.842 +// flag tr is zero) or the system F'*x = b (if the flag tr is non-zero),
228.843 +// where the matrix F is a component of LU-factorization specified by
228.844 +// the parameter lux, F' is a matrix transposed to F.
228.845 +//
228.846 +// On entry the array x should contain elements of the right-hand side
228.847 +// vector b in locations x[1], ..., x[n], where n is the order of the
228.848 +// matrix F. On exit this array will contain elements of the solution
228.849 +// vector x in the same locations. */
228.850 +
228.851 +void lux_f_solve(LUX *lux, int tr, mpq_t x[])
228.852 +{ int n = lux->n;
228.853 + LUXELM **F_row = lux->F_row;
228.854 + LUXELM **F_col = lux->F_col;
228.855 + int *P_row = lux->P_row;
228.856 + LUXELM *fik, *fkj;
228.857 + int i, j, k;
228.858 + mpq_t temp;
228.859 + mpq_init(temp);
228.860 + if (!tr)
228.861 + { /* solve the system F*x = b */
228.862 + for (j = 1; j <= n; j++)
228.863 + { k = P_row[j];
228.864 + if (mpq_sgn(x[k]) != 0)
228.865 + { for (fik = F_col[k]; fik != NULL; fik = fik->c_next)
228.866 + { mpq_mul(temp, fik->val, x[k]);
228.867 + mpq_sub(x[fik->i], x[fik->i], temp);
228.868 + }
228.869 + }
228.870 + }
228.871 + }
228.872 + else
228.873 + { /* solve the system F'*x = b */
228.874 + for (i = n; i >= 1; i--)
228.875 + { k = P_row[i];
228.876 + if (mpq_sgn(x[k]) != 0)
228.877 + { for (fkj = F_row[k]; fkj != NULL; fkj = fkj->r_next)
228.878 + { mpq_mul(temp, fkj->val, x[k]);
228.879 + mpq_sub(x[fkj->j], x[fkj->j], temp);
228.880 + }
228.881 + }
228.882 + }
228.883 + }
228.884 + mpq_clear(temp);
228.885 + return;
228.886 +}
228.887 +
228.888 +/*----------------------------------------------------------------------
228.889 +// lux_v_solve - solve system V*x = b or V'*x = b.
228.890 +//
228.891 +// SYNOPSIS
228.892 +//
228.893 +// #include "glplux.h"
228.894 +// void lux_v_solve(LUX *lux, int tr, double x[]);
228.895 +//
228.896 +// DESCRIPTION
228.897 +//
228.898 +// The routine lux_v_solve solves either the system V*x = b (if the
228.899 +// flag tr is zero) or the system V'*x = b (if the flag tr is non-zero),
228.900 +// where the matrix V is a component of LU-factorization specified by
228.901 +// the parameter lux, V' is a matrix transposed to V.
228.902 +//
228.903 +// On entry the array x should contain elements of the right-hand side
228.904 +// vector b in locations x[1], ..., x[n], where n is the order of the
228.905 +// matrix V. On exit this array will contain elements of the solution
228.906 +// vector x in the same locations. */
228.907 +
228.908 +void lux_v_solve(LUX *lux, int tr, mpq_t x[])
228.909 +{ int n = lux->n;
228.910 + mpq_t *V_piv = lux->V_piv;
228.911 + LUXELM **V_row = lux->V_row;
228.912 + LUXELM **V_col = lux->V_col;
228.913 + int *P_row = lux->P_row;
228.914 + int *Q_col = lux->Q_col;
228.915 + LUXELM *vij;
228.916 + int i, j, k;
228.917 + mpq_t *b, temp;
228.918 + b = xcalloc(1+n, sizeof(mpq_t));
228.919 + for (k = 1; k <= n; k++)
228.920 + mpq_init(b[k]), mpq_set(b[k], x[k]), mpq_set_si(x[k], 0, 1);
228.921 + mpq_init(temp);
228.922 + if (!tr)
228.923 + { /* solve the system V*x = b */
228.924 + for (k = n; k >= 1; k--)
228.925 + { i = P_row[k], j = Q_col[k];
228.926 + if (mpq_sgn(b[i]) != 0)
228.927 + { mpq_set(x[j], b[i]);
228.928 + mpq_div(x[j], x[j], V_piv[i]);
228.929 + for (vij = V_col[j]; vij != NULL; vij = vij->c_next)
228.930 + { mpq_mul(temp, vij->val, x[j]);
228.931 + mpq_sub(b[vij->i], b[vij->i], temp);
228.932 + }
228.933 + }
228.934 + }
228.935 + }
228.936 + else
228.937 + { /* solve the system V'*x = b */
228.938 + for (k = 1; k <= n; k++)
228.939 + { i = P_row[k], j = Q_col[k];
228.940 + if (mpq_sgn(b[j]) != 0)
228.941 + { mpq_set(x[i], b[j]);
228.942 + mpq_div(x[i], x[i], V_piv[i]);
228.943 + for (vij = V_row[i]; vij != NULL; vij = vij->r_next)
228.944 + { mpq_mul(temp, vij->val, x[i]);
228.945 + mpq_sub(b[vij->j], b[vij->j], temp);
228.946 + }
228.947 + }
228.948 + }
228.949 + }
228.950 + for (k = 1; k <= n; k++) mpq_clear(b[k]);
228.951 + mpq_clear(temp);
228.952 + xfree(b);
228.953 + return;
228.954 +}
228.955 +
228.956 +/*----------------------------------------------------------------------
228.957 +// lux_solve - solve system A*x = b or A'*x = b.
228.958 +//
228.959 +// SYNOPSIS
228.960 +//
228.961 +// #include "glplux.h"
228.962 +// void lux_solve(LUX *lux, int tr, mpq_t x[]);
228.963 +//
228.964 +// DESCRIPTION
228.965 +//
228.966 +// The routine lux_solve solves either the system A*x = b (if the flag
228.967 +// tr is zero) or the system A'*x = b (if the flag tr is non-zero),
228.968 +// where the parameter lux specifies LU-factorization of the matrix A,
228.969 +// A' is a matrix transposed to A.
228.970 +//
228.971 +// On entry the array x should contain elements of the right-hand side
228.972 +// vector b in locations x[1], ..., x[n], where n is the order of the
228.973 +// matrix A. On exit this array will contain elements of the solution
228.974 +// vector x in the same locations. */
228.975 +
228.976 +void lux_solve(LUX *lux, int tr, mpq_t x[])
228.977 +{ if (lux->rank < lux->n)
228.978 + xfault("lux_solve: LU-factorization has incomplete rank\n");
228.979 + if (!tr)
228.980 + { /* A = F*V, therefore inv(A) = inv(V)*inv(F) */
228.981 + lux_f_solve(lux, 0, x);
228.982 + lux_v_solve(lux, 0, x);
228.983 + }
228.984 + else
228.985 + { /* A' = V'*F', therefore inv(A') = inv(F')*inv(V') */
228.986 + lux_v_solve(lux, 1, x);
228.987 + lux_f_solve(lux, 1, x);
228.988 + }
228.989 + return;
228.990 +}
228.991 +
228.992 +/*----------------------------------------------------------------------
228.993 +// lux_delete - delete LU-factorization.
228.994 +//
228.995 +// SYNOPSIS
228.996 +//
228.997 +// #include "glplux.h"
228.998 +// void lux_delete(LUX *lux);
228.999 +//
228.1000 +// DESCRIPTION
228.1001 +//
228.1002 +// The routine lux_delete deletes LU-factorization data structure,
228.1003 +// which the parameter lux points to, freeing all the memory allocated
228.1004 +// to this object. */
228.1005 +
228.1006 +void lux_delete(LUX *lux)
228.1007 +{ int n = lux->n;
228.1008 + LUXELM *fij, *vij;
228.1009 + int i;
228.1010 + for (i = 1; i <= n; i++)
228.1011 + { for (fij = lux->F_row[i]; fij != NULL; fij = fij->r_next)
228.1012 + mpq_clear(fij->val);
228.1013 + mpq_clear(lux->V_piv[i]);
228.1014 + for (vij = lux->V_row[i]; vij != NULL; vij = vij->r_next)
228.1015 + mpq_clear(vij->val);
228.1016 + }
228.1017 + dmp_delete_pool(lux->pool);
228.1018 + xfree(lux->F_row);
228.1019 + xfree(lux->F_col);
228.1020 + xfree(lux->V_piv);
228.1021 + xfree(lux->V_row);
228.1022 + xfree(lux->V_col);
228.1023 + xfree(lux->P_row);
228.1024 + xfree(lux->P_col);
228.1025 + xfree(lux->Q_row);
228.1026 + xfree(lux->Q_col);
228.1027 + xfree(lux);
228.1028 + return;
228.1029 +}
228.1030 +
228.1031 +/* eof */
229.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
229.2 +++ b/src/glplux.h Mon Dec 06 13:09:21 2010 +0100
229.3 @@ -0,0 +1,221 @@
229.4 +/* glplux.h (LU-factorization, bignum arithmetic) */
229.5 +
229.6 +/***********************************************************************
229.7 +* This code is part of GLPK (GNU Linear Programming Kit).
229.8 +*
229.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
229.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
229.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
229.12 +* E-mail: <mao@gnu.org>.
229.13 +*
229.14 +* GLPK is free software: you can redistribute it and/or modify it
229.15 +* under the terms of the GNU General Public License as published by
229.16 +* the Free Software Foundation, either version 3 of the License, or
229.17 +* (at your option) any later version.
229.18 +*
229.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
229.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
229.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
229.22 +* License for more details.
229.23 +*
229.24 +* You should have received a copy of the GNU General Public License
229.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
229.26 +***********************************************************************/
229.27 +
229.28 +#ifndef GLPLUX_H
229.29 +#define GLPLUX_H
229.30 +
229.31 +#include "glpdmp.h"
229.32 +#include "glpgmp.h"
229.33 +
229.34 +/*----------------------------------------------------------------------
229.35 +// The structure LUX defines LU-factorization of a square matrix A,
229.36 +// which is the following quartet:
229.37 +//
229.38 +// [A] = (F, V, P, Q), (1)
229.39 +//
229.40 +// where F and V are such matrices that
229.41 +//
229.42 +// A = F * V, (2)
229.43 +//
229.44 +// and P and Q are such permutation matrices that the matrix
229.45 +//
229.46 +// L = P * F * inv(P) (3)
229.47 +//
229.48 +// is lower triangular with unity diagonal, and the matrix
229.49 +//
229.50 +// U = P * V * Q (4)
229.51 +//
229.52 +// is upper triangular. All the matrices have the order n.
229.53 +//
229.54 +// The matrices F and V are stored in row/column-wise sparse format as
229.55 +// row and column linked lists of non-zero elements. Unity elements on
229.56 +// the main diagonal of the matrix F are not stored. Pivot elements of
229.57 +// the matrix V (that correspond to diagonal elements of the matrix U)
229.58 +// are also missing from the row and column lists and stored separately
229.59 +// in an ordinary array.
229.60 +//
229.61 +// The permutation matrices P and Q are stored as ordinary arrays using
229.62 +// both row- and column-like formats.
229.63 +//
229.64 +// The matrices L and U being completely defined by the matrices F, V,
229.65 +// P, and Q are not stored explicitly.
229.66 +//
229.67 +// It is easy to show that the factorization (1)-(3) is some version of
229.68 +// LU-factorization. Indeed, from (3) and (4) it follows that:
229.69 +//
229.70 +// F = inv(P) * L * P,
229.71 +//
229.72 +// V = inv(P) * U * inv(Q),
229.73 +//
229.74 +// and substitution into (2) gives:
229.75 +//
229.76 +// A = F * V = inv(P) * L * U * inv(Q).
229.77 +//
229.78 +// For more details see the program documentation. */
229.79 +
229.80 +typedef struct LUX LUX;
229.81 +typedef struct LUXELM LUXELM;
229.82 +typedef struct LUXWKA LUXWKA;
229.83 +
229.84 +struct LUX
229.85 +{ /* LU-factorization of a square matrix */
229.86 + int n;
229.87 + /* the order of matrices A, F, V, P, Q */
229.88 + DMP *pool;
229.89 + /* memory pool for elements of matrices F and V */
229.90 + LUXELM **F_row; /* LUXELM *F_row[1+n]; */
229.91 + /* F_row[0] is not used;
229.92 + F_row[i], 1 <= i <= n, is a pointer to the list of elements in
229.93 + i-th row of matrix F (diagonal elements are not stored) */
229.94 + LUXELM **F_col; /* LUXELM *F_col[1+n]; */
229.95 + /* F_col[0] is not used;
229.96 + F_col[j], 1 <= j <= n, is a pointer to the list of elements in
229.97 + j-th column of matrix F (diagonal elements are not stored) */
229.98 + mpq_t *V_piv; /* mpq_t V_piv[1+n]; */
229.99 + /* V_piv[0] is not used;
229.100 + V_piv[p], 1 <= p <= n, is a pivot element v[p,q] corresponding
229.101 + to a diagonal element u[k,k] of matrix U = P*V*Q (used on k-th
229.102 + elimination step, k = 1, 2, ..., n) */
229.103 + LUXELM **V_row; /* LUXELM *V_row[1+n]; */
229.104 + /* V_row[0] is not used;
229.105 + V_row[i], 1 <= i <= n, is a pointer to the list of elements in
229.106 + i-th row of matrix V (except pivot elements) */
229.107 + LUXELM **V_col; /* LUXELM *V_col[1+n]; */
229.108 + /* V_col[0] is not used;
229.109 + V_col[j], 1 <= j <= n, is a pointer to the list of elements in
229.110 + j-th column of matrix V (except pivot elements) */
229.111 + int *P_row; /* int P_row[1+n]; */
229.112 + /* P_row[0] is not used;
229.113 + P_row[i] = j means that p[i,j] = 1, where p[i,j] is an element
229.114 + of permutation matrix P */
229.115 + int *P_col; /* int P_col[1+n]; */
229.116 + /* P_col[0] is not used;
229.117 + P_col[j] = i means that p[i,j] = 1, where p[i,j] is an element
229.118 + of permutation matrix P */
229.119 + /* if i-th row or column of matrix F is i'-th row or column of
229.120 + matrix L = P*F*inv(P), or if i-th row of matrix V is i'-th row
229.121 + of matrix U = P*V*Q, then P_row[i'] = i and P_col[i] = i' */
229.122 + int *Q_row; /* int Q_row[1+n]; */
229.123 + /* Q_row[0] is not used;
229.124 + Q_row[i] = j means that q[i,j] = 1, where q[i,j] is an element
229.125 + of permutation matrix Q */
229.126 + int *Q_col; /* int Q_col[1+n]; */
229.127 + /* Q_col[0] is not used;
229.128 + Q_col[j] = i means that q[i,j] = 1, where q[i,j] is an element
229.129 + of permutation matrix Q */
229.130 + /* if j-th column of matrix V is j'-th column of matrix U = P*V*Q,
229.131 + then Q_row[j] = j' and Q_col[j'] = j */
229.132 + int rank;
229.133 + /* the (exact) rank of matrices A and V */
229.134 +};
229.135 +
229.136 +struct LUXELM
229.137 +{ /* element of matrix F or V */
229.138 + int i;
229.139 + /* row index, 1 <= i <= m */
229.140 + int j;
229.141 + /* column index, 1 <= j <= n */
229.142 + mpq_t val;
229.143 + /* numeric (non-zero) element value */
229.144 + LUXELM *r_prev;
229.145 + /* pointer to previous element in the same row */
229.146 + LUXELM *r_next;
229.147 + /* pointer to next element in the same row */
229.148 + LUXELM *c_prev;
229.149 + /* pointer to previous element in the same column */
229.150 + LUXELM *c_next;
229.151 + /* pointer to next element in the same column */
229.152 +};
229.153 +
229.154 +struct LUXWKA
229.155 +{ /* working area (used only during factorization) */
229.156 + /* in order to efficiently implement Markowitz strategy and Duff
229.157 + search technique there are two families {R[0], R[1], ..., R[n]}
229.158 + and {C[0], C[1], ..., C[n]}; member R[k] is a set of active
229.159 + rows of matrix V having k non-zeros, and member C[k] is a set
229.160 + of active columns of matrix V having k non-zeros (in the active
229.161 + submatrix); each set R[k] and C[k] is implemented as a separate
229.162 + doubly linked list */
229.163 + int *R_len; /* int R_len[1+n]; */
229.164 + /* R_len[0] is not used;
229.165 + R_len[i], 1 <= i <= n, is the number of non-zero elements in
229.166 + i-th row of matrix V (that is the length of i-th row) */
229.167 + int *R_head; /* int R_head[1+n]; */
229.168 + /* R_head[k], 0 <= k <= n, is the number of a first row, which is
229.169 + active and whose length is k */
229.170 + int *R_prev; /* int R_prev[1+n]; */
229.171 + /* R_prev[0] is not used;
229.172 + R_prev[i], 1 <= i <= n, is the number of a previous row, which
229.173 + is active and has the same length as i-th row */
229.174 + int *R_next; /* int R_next[1+n]; */
229.175 + /* R_prev[0] is not used;
229.176 + R_prev[i], 1 <= i <= n, is the number of a next row, which is
229.177 + active and has the same length as i-th row */
229.178 + int *C_len; /* int C_len[1+n]; */
229.179 + /* C_len[0] is not used;
229.180 + C_len[j], 1 <= j <= n, is the number of non-zero elements in
229.181 + j-th column of the active submatrix of matrix V (that is the
229.182 + length of j-th column in the active submatrix) */
229.183 + int *C_head; /* int C_head[1+n]; */
229.184 + /* C_head[k], 0 <= k <= n, is the number of a first column, which
229.185 + is active and whose length is k */
229.186 + int *C_prev; /* int C_prev[1+n]; */
229.187 + /* C_prev[0] is not used;
229.188 + C_prev[j], 1 <= j <= n, is the number of a previous column,
229.189 + which is active and has the same length as j-th column */
229.190 + int *C_next; /* int C_next[1+n]; */
229.191 + /* C_next[0] is not used;
229.192 + C_next[j], 1 <= j <= n, is the number of a next column, which
229.193 + is active and has the same length as j-th column */
229.194 +};
229.195 +
229.196 +#define lux_create _glp_lux_create
229.197 +#define lux_decomp _glp_lux_decomp
229.198 +#define lux_f_solve _glp_lux_f_solve
229.199 +#define lux_v_solve _glp_lux_v_solve
229.200 +#define lux_solve _glp_lux_solve
229.201 +#define lux_delete _glp_lux_delete
229.202 +
229.203 +LUX *lux_create(int n);
229.204 +/* create LU-factorization */
229.205 +
229.206 +int lux_decomp(LUX *lux, int (*col)(void *info, int j, int ind[],
229.207 + mpq_t val[]), void *info);
229.208 +/* compute LU-factorization */
229.209 +
229.210 +void lux_f_solve(LUX *lux, int tr, mpq_t x[]);
229.211 +/* solve system F*x = b or F'*x = b */
229.212 +
229.213 +void lux_v_solve(LUX *lux, int tr, mpq_t x[]);
229.214 +/* solve system V*x = b or V'*x = b */
229.215 +
229.216 +void lux_solve(LUX *lux, int tr, mpq_t x[]);
229.217 +/* solve system A*x = b or A'*x = b */
229.218 +
229.219 +void lux_delete(LUX *lux);
229.220 +/* delete LU-factorization */
229.221 +
229.222 +#endif
229.223 +
229.224 +/* eof */
230.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
230.2 +++ b/src/glpmat.c Mon Dec 06 13:09:21 2010 +0100
230.3 @@ -0,0 +1,924 @@
230.4 +/* glpmat.c */
230.5 +
230.6 +/***********************************************************************
230.7 +* This code is part of GLPK (GNU Linear Programming Kit).
230.8 +*
230.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
230.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
230.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
230.12 +* E-mail: <mao@gnu.org>.
230.13 +*
230.14 +* GLPK is free software: you can redistribute it and/or modify it
230.15 +* under the terms of the GNU General Public License as published by
230.16 +* the Free Software Foundation, either version 3 of the License, or
230.17 +* (at your option) any later version.
230.18 +*
230.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
230.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
230.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
230.22 +* License for more details.
230.23 +*
230.24 +* You should have received a copy of the GNU General Public License
230.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
230.26 +***********************************************************************/
230.27 +
230.28 +#include "glpenv.h"
230.29 +#include "glpmat.h"
230.30 +#include "glpqmd.h"
230.31 +#include "amd/amd.h"
230.32 +#include "colamd/colamd.h"
230.33 +
230.34 +/*----------------------------------------------------------------------
230.35 +-- check_fvs - check sparse vector in full-vector storage format.
230.36 +--
230.37 +-- SYNOPSIS
230.38 +--
230.39 +-- #include "glpmat.h"
230.40 +-- int check_fvs(int n, int nnz, int ind[], double vec[]);
230.41 +--
230.42 +-- DESCRIPTION
230.43 +--
230.44 +-- The routine check_fvs checks if a given vector of dimension n in
230.45 +-- full-vector storage format has correct representation.
230.46 +--
230.47 +-- RETURNS
230.48 +--
230.49 +-- The routine returns one of the following codes:
230.50 +--
230.51 +-- 0 - the vector is correct;
230.52 +-- 1 - the number of elements (n) is negative;
230.53 +-- 2 - the number of non-zero elements (nnz) is negative;
230.54 +-- 3 - some element index is out of range;
230.55 +-- 4 - some element index is duplicate;
230.56 +-- 5 - some non-zero element is out of pattern. */
230.57 +
230.58 +int check_fvs(int n, int nnz, int ind[], double vec[])
230.59 +{ int i, t, ret, *flag = NULL;
230.60 + /* check the number of elements */
230.61 + if (n < 0)
230.62 + { ret = 1;
230.63 + goto done;
230.64 + }
230.65 + /* check the number of non-zero elements */
230.66 + if (nnz < 0)
230.67 + { ret = 2;
230.68 + goto done;
230.69 + }
230.70 + /* check vector indices */
230.71 + flag = xcalloc(1+n, sizeof(int));
230.72 + for (i = 1; i <= n; i++) flag[i] = 0;
230.73 + for (t = 1; t <= nnz; t++)
230.74 + { i = ind[t];
230.75 + if (!(1 <= i && i <= n))
230.76 + { ret = 3;
230.77 + goto done;
230.78 + }
230.79 + if (flag[i])
230.80 + { ret = 4;
230.81 + goto done;
230.82 + }
230.83 + flag[i] = 1;
230.84 + }
230.85 + /* check vector elements */
230.86 + for (i = 1; i <= n; i++)
230.87 + { if (!flag[i] && vec[i] != 0.0)
230.88 + { ret = 5;
230.89 + goto done;
230.90 + }
230.91 + }
230.92 + /* the vector is ok */
230.93 + ret = 0;
230.94 +done: if (flag != NULL) xfree(flag);
230.95 + return ret;
230.96 +}
230.97 +
230.98 +/*----------------------------------------------------------------------
230.99 +-- check_pattern - check pattern of sparse matrix.
230.100 +--
230.101 +-- SYNOPSIS
230.102 +--
230.103 +-- #include "glpmat.h"
230.104 +-- int check_pattern(int m, int n, int A_ptr[], int A_ind[]);
230.105 +--
230.106 +-- DESCRIPTION
230.107 +--
230.108 +-- The routine check_pattern checks the pattern of a given mxn matrix
230.109 +-- in storage-by-rows format.
230.110 +--
230.111 +-- RETURNS
230.112 +--
230.113 +-- The routine returns one of the following codes:
230.114 +--
230.115 +-- 0 - the pattern is correct;
230.116 +-- 1 - the number of rows (m) is negative;
230.117 +-- 2 - the number of columns (n) is negative;
230.118 +-- 3 - A_ptr[1] is not 1;
230.119 +-- 4 - some column index is out of range;
230.120 +-- 5 - some column indices are duplicate. */
230.121 +
230.122 +int check_pattern(int m, int n, int A_ptr[], int A_ind[])
230.123 +{ int i, j, ptr, ret, *flag = NULL;
230.124 + /* check the number of rows */
230.125 + if (m < 0)
230.126 + { ret = 1;
230.127 + goto done;
230.128 + }
230.129 + /* check the number of columns */
230.130 + if (n < 0)
230.131 + { ret = 2;
230.132 + goto done;
230.133 + }
230.134 + /* check location A_ptr[1] */
230.135 + if (A_ptr[1] != 1)
230.136 + { ret = 3;
230.137 + goto done;
230.138 + }
230.139 + /* check row patterns */
230.140 + flag = xcalloc(1+n, sizeof(int));
230.141 + for (j = 1; j <= n; j++) flag[j] = 0;
230.142 + for (i = 1; i <= m; i++)
230.143 + { /* check pattern of row i */
230.144 + for (ptr = A_ptr[i]; ptr < A_ptr[i+1]; ptr++)
230.145 + { j = A_ind[ptr];
230.146 + /* check column index */
230.147 + if (!(1 <= j && j <= n))
230.148 + { ret = 4;
230.149 + goto done;
230.150 + }
230.151 + /* check for duplication */
230.152 + if (flag[j])
230.153 + { ret = 5;
230.154 + goto done;
230.155 + }
230.156 + flag[j] = 1;
230.157 + }
230.158 + /* clear flags */
230.159 + for (ptr = A_ptr[i]; ptr < A_ptr[i+1]; ptr++)
230.160 + { j = A_ind[ptr];
230.161 + flag[j] = 0;
230.162 + }
230.163 + }
230.164 + /* the pattern is ok */
230.165 + ret = 0;
230.166 +done: if (flag != NULL) xfree(flag);
230.167 + return ret;
230.168 +}
230.169 +
230.170 +/*----------------------------------------------------------------------
230.171 +-- transpose - transpose sparse matrix.
230.172 +--
230.173 +-- *Synopsis*
230.174 +--
230.175 +-- #include "glpmat.h"
230.176 +-- void transpose(int m, int n, int A_ptr[], int A_ind[],
230.177 +-- double A_val[], int AT_ptr[], int AT_ind[], double AT_val[]);
230.178 +--
230.179 +-- *Description*
230.180 +--
230.181 +-- For a given mxn sparse matrix A the routine transpose builds a nxm
230.182 +-- sparse matrix A' which is a matrix transposed to A.
230.183 +--
230.184 +-- The arrays A_ptr, A_ind, and A_val specify a given mxn matrix A to
230.185 +-- be transposed in storage-by-rows format. The parameter A_val can be
230.186 +-- NULL, in which case numeric values are not copied. The arrays A_ptr,
230.187 +-- A_ind, and A_val are not changed on exit.
230.188 +--
230.189 +-- On entry the arrays AT_ptr, AT_ind, and AT_val must be allocated,
230.190 +-- but their content is ignored. On exit the routine stores a resultant
230.191 +-- nxm matrix A' in these arrays in storage-by-rows format. Note that
230.192 +-- if the parameter A_val is NULL, the array AT_val is not used.
230.193 +--
230.194 +-- The routine transpose has a side effect that elements in rows of the
230.195 +-- resultant matrix A' follow in ascending their column indices. */
230.196 +
230.197 +void transpose(int m, int n, int A_ptr[], int A_ind[], double A_val[],
230.198 + int AT_ptr[], int AT_ind[], double AT_val[])
230.199 +{ int i, j, t, beg, end, pos, len;
230.200 + /* determine row lengths of resultant matrix */
230.201 + for (j = 1; j <= n; j++) AT_ptr[j] = 0;
230.202 + for (i = 1; i <= m; i++)
230.203 + { beg = A_ptr[i], end = A_ptr[i+1];
230.204 + for (t = beg; t < end; t++) AT_ptr[A_ind[t]]++;
230.205 + }
230.206 + /* set up row pointers of resultant matrix */
230.207 + pos = 1;
230.208 + for (j = 1; j <= n; j++)
230.209 + len = AT_ptr[j], pos += len, AT_ptr[j] = pos;
230.210 + AT_ptr[n+1] = pos;
230.211 + /* build resultant matrix */
230.212 + for (i = m; i >= 1; i--)
230.213 + { beg = A_ptr[i], end = A_ptr[i+1];
230.214 + for (t = beg; t < end; t++)
230.215 + { pos = --AT_ptr[A_ind[t]];
230.216 + AT_ind[pos] = i;
230.217 + if (A_val != NULL) AT_val[pos] = A_val[t];
230.218 + }
230.219 + }
230.220 + return;
230.221 +}
230.222 +
230.223 +/*----------------------------------------------------------------------
230.224 +-- adat_symbolic - compute S = P*A*D*A'*P' (symbolic phase).
230.225 +--
230.226 +-- *Synopsis*
230.227 +--
230.228 +-- #include "glpmat.h"
230.229 +-- int *adat_symbolic(int m, int n, int P_per[], int A_ptr[],
230.230 +-- int A_ind[], int S_ptr[]);
230.231 +--
230.232 +-- *Description*
230.233 +--
230.234 +-- The routine adat_symbolic implements the symbolic phase to compute
230.235 +-- symmetric matrix S = P*A*D*A'*P', where P is a permutation matrix,
230.236 +-- A is a given sparse matrix, D is a diagonal matrix, A' is a matrix
230.237 +-- transposed to A, P' is an inverse of P.
230.238 +--
230.239 +-- The parameter m is the number of rows in A and the order of P.
230.240 +--
230.241 +-- The parameter n is the number of columns in A and the order of D.
230.242 +--
230.243 +-- The array P_per specifies permutation matrix P. It is not changed on
230.244 +-- exit.
230.245 +--
230.246 +-- The arrays A_ptr and A_ind specify the pattern of matrix A. They are
230.247 +-- not changed on exit.
230.248 +--
230.249 +-- On exit the routine stores the pattern of upper triangular part of
230.250 +-- matrix S without diagonal elements in the arrays S_ptr and S_ind in
230.251 +-- storage-by-rows format. The array S_ptr should be allocated on entry,
230.252 +-- however, its content is ignored. The array S_ind is allocated by the
230.253 +-- routine itself which returns a pointer to it.
230.254 +--
230.255 +-- *Returns*
230.256 +--
230.257 +-- The routine returns a pointer to the array S_ind. */
230.258 +
230.259 +int *adat_symbolic(int m, int n, int P_per[], int A_ptr[], int A_ind[],
230.260 + int S_ptr[])
230.261 +{ int i, j, t, ii, jj, tt, k, size, len;
230.262 + int *S_ind, *AT_ptr, *AT_ind, *ind, *map, *temp;
230.263 + /* build the pattern of A', which is a matrix transposed to A, to
230.264 + efficiently access A in column-wise manner */
230.265 + AT_ptr = xcalloc(1+n+1, sizeof(int));
230.266 + AT_ind = xcalloc(A_ptr[m+1], sizeof(int));
230.267 + transpose(m, n, A_ptr, A_ind, NULL, AT_ptr, AT_ind, NULL);
230.268 + /* allocate the array S_ind */
230.269 + size = A_ptr[m+1] - 1;
230.270 + if (size < m) size = m;
230.271 + S_ind = xcalloc(1+size, sizeof(int));
230.272 + /* allocate and initialize working arrays */
230.273 + ind = xcalloc(1+m, sizeof(int));
230.274 + map = xcalloc(1+m, sizeof(int));
230.275 + for (jj = 1; jj <= m; jj++) map[jj] = 0;
230.276 + /* compute pattern of S; note that symbolically S = B*B', where
230.277 + B = P*A, B' is matrix transposed to B */
230.278 + S_ptr[1] = 1;
230.279 + for (ii = 1; ii <= m; ii++)
230.280 + { /* compute pattern of ii-th row of S */
230.281 + len = 0;
230.282 + i = P_per[ii]; /* i-th row of A = ii-th row of B */
230.283 + for (t = A_ptr[i]; t < A_ptr[i+1]; t++)
230.284 + { k = A_ind[t];
230.285 + /* walk through k-th column of A */
230.286 + for (tt = AT_ptr[k]; tt < AT_ptr[k+1]; tt++)
230.287 + { j = AT_ind[tt];
230.288 + jj = P_per[m+j]; /* j-th row of A = jj-th row of B */
230.289 + /* a[i,k] != 0 and a[j,k] != 0 ergo s[ii,jj] != 0 */
230.290 + if (ii < jj && !map[jj]) ind[++len] = jj, map[jj] = 1;
230.291 + }
230.292 + }
230.293 + /* now (ind) is pattern of ii-th row of S */
230.294 + S_ptr[ii+1] = S_ptr[ii] + len;
230.295 + /* at least (S_ptr[ii+1] - 1) locations should be available in
230.296 + the array S_ind */
230.297 + if (S_ptr[ii+1] - 1 > size)
230.298 + { temp = S_ind;
230.299 + size += size;
230.300 + S_ind = xcalloc(1+size, sizeof(int));
230.301 + memcpy(&S_ind[1], &temp[1], (S_ptr[ii] - 1) * sizeof(int));
230.302 + xfree(temp);
230.303 + }
230.304 + xassert(S_ptr[ii+1] - 1 <= size);
230.305 + /* (ii-th row of S) := (ind) */
230.306 + memcpy(&S_ind[S_ptr[ii]], &ind[1], len * sizeof(int));
230.307 + /* clear the row pattern map */
230.308 + for (t = 1; t <= len; t++) map[ind[t]] = 0;
230.309 + }
230.310 + /* free working arrays */
230.311 + xfree(AT_ptr);
230.312 + xfree(AT_ind);
230.313 + xfree(ind);
230.314 + xfree(map);
230.315 + /* reallocate the array S_ind to free unused locations */
230.316 + temp = S_ind;
230.317 + size = S_ptr[m+1] - 1;
230.318 + S_ind = xcalloc(1+size, sizeof(int));
230.319 + memcpy(&S_ind[1], &temp[1], size * sizeof(int));
230.320 + xfree(temp);
230.321 + return S_ind;
230.322 +}
230.323 +
230.324 +/*----------------------------------------------------------------------
230.325 +-- adat_numeric - compute S = P*A*D*A'*P' (numeric phase).
230.326 +--
230.327 +-- *Synopsis*
230.328 +--
230.329 +-- #include "glpmat.h"
230.330 +-- void adat_numeric(int m, int n, int P_per[],
230.331 +-- int A_ptr[], int A_ind[], double A_val[], double D_diag[],
230.332 +-- int S_ptr[], int S_ind[], double S_val[], double S_diag[]);
230.333 +--
230.334 +-- *Description*
230.335 +--
230.336 +-- The routine adat_numeric implements the numeric phase to compute
230.337 +-- symmetric matrix S = P*A*D*A'*P', where P is a permutation matrix,
230.338 +-- A is a given sparse matrix, D is a diagonal matrix, A' is a matrix
230.339 +-- transposed to A, P' is an inverse of P.
230.340 +--
230.341 +-- The parameter m is the number of rows in A and the order of P.
230.342 +--
230.343 +-- The parameter n is the number of columns in A and the order of D.
230.344 +--
230.345 +-- The matrix P is specified in the array P_per, which is not changed
230.346 +-- on exit.
230.347 +--
230.348 +-- The matrix A is specified in the arrays A_ptr, A_ind, and A_val in
230.349 +-- storage-by-rows format. These arrays are not changed on exit.
230.350 +--
230.351 +-- Diagonal elements of the matrix D are specified in the array D_diag,
230.352 +-- where D_diag[0] is not used, D_diag[i] = d[i,i] for i = 1, ..., n.
230.353 +-- The array D_diag is not changed on exit.
230.354 +--
230.355 +-- The pattern of the upper triangular part of the matrix S without
230.356 +-- diagonal elements (previously computed by the routine adat_symbolic)
230.357 +-- is specified in the arrays S_ptr and S_ind, which are not changed on
230.358 +-- exit. Numeric values of non-diagonal elements of S are stored in
230.359 +-- corresponding locations of the array S_val, and values of diagonal
230.360 +-- elements of S are stored in locations S_diag[1], ..., S_diag[n]. */
230.361 +
230.362 +void adat_numeric(int m, int n, int P_per[],
230.363 + int A_ptr[], int A_ind[], double A_val[], double D_diag[],
230.364 + int S_ptr[], int S_ind[], double S_val[], double S_diag[])
230.365 +{ int i, j, t, ii, jj, tt, beg, end, beg1, end1, k;
230.366 + double sum, *work;
230.367 + work = xcalloc(1+n, sizeof(double));
230.368 + for (j = 1; j <= n; j++) work[j] = 0.0;
230.369 + /* compute S = B*D*B', where B = P*A, B' is a matrix transposed
230.370 + to B */
230.371 + for (ii = 1; ii <= m; ii++)
230.372 + { i = P_per[ii]; /* i-th row of A = ii-th row of B */
230.373 + /* (work) := (i-th row of A) */
230.374 + beg = A_ptr[i], end = A_ptr[i+1];
230.375 + for (t = beg; t < end; t++)
230.376 + work[A_ind[t]] = A_val[t];
230.377 + /* compute ii-th row of S */
230.378 + beg = S_ptr[ii], end = S_ptr[ii+1];
230.379 + for (t = beg; t < end; t++)
230.380 + { jj = S_ind[t];
230.381 + j = P_per[jj]; /* j-th row of A = jj-th row of B */
230.382 + /* s[ii,jj] := sum a[i,k] * d[k,k] * a[j,k] */
230.383 + sum = 0.0;
230.384 + beg1 = A_ptr[j], end1 = A_ptr[j+1];
230.385 + for (tt = beg1; tt < end1; tt++)
230.386 + { k = A_ind[tt];
230.387 + sum += work[k] * D_diag[k] * A_val[tt];
230.388 + }
230.389 + S_val[t] = sum;
230.390 + }
230.391 + /* s[ii,ii] := sum a[i,k] * d[k,k] * a[i,k] */
230.392 + sum = 0.0;
230.393 + beg = A_ptr[i], end = A_ptr[i+1];
230.394 + for (t = beg; t < end; t++)
230.395 + { k = A_ind[t];
230.396 + sum += A_val[t] * D_diag[k] * A_val[t];
230.397 + work[k] = 0.0;
230.398 + }
230.399 + S_diag[ii] = sum;
230.400 + }
230.401 + xfree(work);
230.402 + return;
230.403 +}
230.404 +
230.405 +/*----------------------------------------------------------------------
230.406 +-- min_degree - minimum degree ordering.
230.407 +--
230.408 +-- *Synopsis*
230.409 +--
230.410 +-- #include "glpmat.h"
230.411 +-- void min_degree(int n, int A_ptr[], int A_ind[], int P_per[]);
230.412 +--
230.413 +-- *Description*
230.414 +--
230.415 +-- The routine min_degree uses the minimum degree ordering algorithm
230.416 +-- to find a permutation matrix P for a given sparse symmetric positive
230.417 +-- matrix A which minimizes the number of non-zeros in upper triangular
230.418 +-- factor U for Cholesky factorization P*A*P' = U'*U.
230.419 +--
230.420 +-- The parameter n is the order of matrices A and P.
230.421 +--
230.422 +-- The pattern of the given matrix A is specified on entry in the arrays
230.423 +-- A_ptr and A_ind in storage-by-rows format. Only the upper triangular
230.424 +-- part without diagonal elements (which all are assumed to be non-zero)
230.425 +-- should be specified as if A were upper triangular. The arrays A_ptr
230.426 +-- and A_ind are not changed on exit.
230.427 +--
230.428 +-- The permutation matrix P is stored by the routine in the array P_per
230.429 +-- on exit.
230.430 +--
230.431 +-- *Algorithm*
230.432 +--
230.433 +-- The routine min_degree is based on some subroutines from the package
230.434 +-- SPARSPAK (see comments in the module glpqmd). */
230.435 +
230.436 +void min_degree(int n, int A_ptr[], int A_ind[], int P_per[])
230.437 +{ int i, j, ne, t, pos, len;
230.438 + int *xadj, *adjncy, *deg, *marker, *rchset, *nbrhd, *qsize,
230.439 + *qlink, nofsub;
230.440 + /* determine number of non-zeros in complete pattern */
230.441 + ne = A_ptr[n+1] - 1;
230.442 + ne += ne;
230.443 + /* allocate working arrays */
230.444 + xadj = xcalloc(1+n+1, sizeof(int));
230.445 + adjncy = xcalloc(1+ne, sizeof(int));
230.446 + deg = xcalloc(1+n, sizeof(int));
230.447 + marker = xcalloc(1+n, sizeof(int));
230.448 + rchset = xcalloc(1+n, sizeof(int));
230.449 + nbrhd = xcalloc(1+n, sizeof(int));
230.450 + qsize = xcalloc(1+n, sizeof(int));
230.451 + qlink = xcalloc(1+n, sizeof(int));
230.452 + /* determine row lengths in complete pattern */
230.453 + for (i = 1; i <= n; i++) xadj[i] = 0;
230.454 + for (i = 1; i <= n; i++)
230.455 + { for (t = A_ptr[i]; t < A_ptr[i+1]; t++)
230.456 + { j = A_ind[t];
230.457 + xassert(i < j && j <= n);
230.458 + xadj[i]++, xadj[j]++;
230.459 + }
230.460 + }
230.461 + /* set up row pointers for complete pattern */
230.462 + pos = 1;
230.463 + for (i = 1; i <= n; i++)
230.464 + len = xadj[i], pos += len, xadj[i] = pos;
230.465 + xadj[n+1] = pos;
230.466 + xassert(pos - 1 == ne);
230.467 + /* construct complete pattern */
230.468 + for (i = 1; i <= n; i++)
230.469 + { for (t = A_ptr[i]; t < A_ptr[i+1]; t++)
230.470 + { j = A_ind[t];
230.471 + adjncy[--xadj[i]] = j, adjncy[--xadj[j]] = i;
230.472 + }
230.473 + }
230.474 + /* call the main minimimum degree ordering routine */
230.475 + genqmd(&n, xadj, adjncy, P_per, P_per + n, deg, marker, rchset,
230.476 + nbrhd, qsize, qlink, &nofsub);
230.477 + /* make sure that permutation matrix P is correct */
230.478 + for (i = 1; i <= n; i++)
230.479 + { j = P_per[i];
230.480 + xassert(1 <= j && j <= n);
230.481 + xassert(P_per[n+j] == i);
230.482 + }
230.483 + /* free working arrays */
230.484 + xfree(xadj);
230.485 + xfree(adjncy);
230.486 + xfree(deg);
230.487 + xfree(marker);
230.488 + xfree(rchset);
230.489 + xfree(nbrhd);
230.490 + xfree(qsize);
230.491 + xfree(qlink);
230.492 + return;
230.493 +}
230.494 +
230.495 +/**********************************************************************/
230.496 +
230.497 +void amd_order1(int n, int A_ptr[], int A_ind[], int P_per[])
230.498 +{ /* approximate minimum degree ordering (AMD) */
230.499 + int k, ret;
230.500 + double Control[AMD_CONTROL], Info[AMD_INFO];
230.501 + /* get the default parameters */
230.502 + amd_defaults(Control);
230.503 +#if 0
230.504 + /* and print them */
230.505 + amd_control(Control);
230.506 +#endif
230.507 + /* make all indices 0-based */
230.508 + for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]--;
230.509 + for (k = 1; k <= n+1; k++) A_ptr[k]--;
230.510 + /* call the ordering routine */
230.511 + ret = amd_order(n, &A_ptr[1], &A_ind[1], &P_per[1], Control, Info)
230.512 + ;
230.513 +#if 0
230.514 + amd_info(Info);
230.515 +#endif
230.516 + xassert(ret == AMD_OK || ret == AMD_OK_BUT_JUMBLED);
230.517 + /* retsore 1-based indices */
230.518 + for (k = 1; k <= n+1; k++) A_ptr[k]++;
230.519 + for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]++;
230.520 + /* patch up permutation matrix */
230.521 + memset(&P_per[n+1], 0, n * sizeof(int));
230.522 + for (k = 1; k <= n; k++)
230.523 + { P_per[k]++;
230.524 + xassert(1 <= P_per[k] && P_per[k] <= n);
230.525 + xassert(P_per[n+P_per[k]] == 0);
230.526 + P_per[n+P_per[k]] = k;
230.527 + }
230.528 + return;
230.529 +}
230.530 +
230.531 +/**********************************************************************/
230.532 +
230.533 +static void *allocate(size_t n, size_t size)
230.534 +{ void *ptr;
230.535 + ptr = xcalloc(n, size);
230.536 + memset(ptr, 0, n * size);
230.537 + return ptr;
230.538 +}
230.539 +
230.540 +static void release(void *ptr)
230.541 +{ xfree(ptr);
230.542 + return;
230.543 +}
230.544 +
230.545 +void symamd_ord(int n, int A_ptr[], int A_ind[], int P_per[])
230.546 +{ /* approximate minimum degree ordering (SYMAMD) */
230.547 + int k, ok;
230.548 + int stats[COLAMD_STATS];
230.549 + /* make all indices 0-based */
230.550 + for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]--;
230.551 + for (k = 1; k <= n+1; k++) A_ptr[k]--;
230.552 + /* call the ordering routine */
230.553 + ok = symamd(n, &A_ind[1], &A_ptr[1], &P_per[1], NULL, stats,
230.554 + allocate, release);
230.555 +#if 0
230.556 + symamd_report(stats);
230.557 +#endif
230.558 + xassert(ok);
230.559 + /* restore 1-based indices */
230.560 + for (k = 1; k <= n+1; k++) A_ptr[k]++;
230.561 + for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]++;
230.562 + /* patch up permutation matrix */
230.563 + memset(&P_per[n+1], 0, n * sizeof(int));
230.564 + for (k = 1; k <= n; k++)
230.565 + { P_per[k]++;
230.566 + xassert(1 <= P_per[k] && P_per[k] <= n);
230.567 + xassert(P_per[n+P_per[k]] == 0);
230.568 + P_per[n+P_per[k]] = k;
230.569 + }
230.570 + return;
230.571 +}
230.572 +
230.573 +/*----------------------------------------------------------------------
230.574 +-- chol_symbolic - compute Cholesky factorization (symbolic phase).
230.575 +--
230.576 +-- *Synopsis*
230.577 +--
230.578 +-- #include "glpmat.h"
230.579 +-- int *chol_symbolic(int n, int A_ptr[], int A_ind[], int U_ptr[]);
230.580 +--
230.581 +-- *Description*
230.582 +--
230.583 +-- The routine chol_symbolic implements the symbolic phase of Cholesky
230.584 +-- factorization A = U'*U, where A is a given sparse symmetric positive
230.585 +-- definite matrix, U is a resultant upper triangular factor, U' is a
230.586 +-- matrix transposed to U.
230.587 +--
230.588 +-- The parameter n is the order of matrices A and U.
230.589 +--
230.590 +-- The pattern of the given matrix A is specified on entry in the arrays
230.591 +-- A_ptr and A_ind in storage-by-rows format. Only the upper triangular
230.592 +-- part without diagonal elements (which all are assumed to be non-zero)
230.593 +-- should be specified as if A were upper triangular. The arrays A_ptr
230.594 +-- and A_ind are not changed on exit.
230.595 +--
230.596 +-- The pattern of the matrix U without diagonal elements (which all are
230.597 +-- assumed to be non-zero) is stored on exit from the routine in the
230.598 +-- arrays U_ptr and U_ind in storage-by-rows format. The array U_ptr
230.599 +-- should be allocated on entry, however, its content is ignored. The
230.600 +-- array U_ind is allocated by the routine which returns a pointer to it
230.601 +-- on exit.
230.602 +--
230.603 +-- *Returns*
230.604 +--
230.605 +-- The routine returns a pointer to the array U_ind.
230.606 +--
230.607 +-- *Method*
230.608 +--
230.609 +-- The routine chol_symbolic computes the pattern of the matrix U in a
230.610 +-- row-wise manner. No pivoting is used.
230.611 +--
230.612 +-- It is known that to compute the pattern of row k of the matrix U we
230.613 +-- need to merge the pattern of row k of the matrix A and the patterns
230.614 +-- of each row i of U, where u[i,k] is non-zero (these rows are already
230.615 +-- computed and placed above row k).
230.616 +--
230.617 +-- However, to reduce the number of rows to be merged the routine uses
230.618 +-- an advanced algorithm proposed in:
230.619 +--
230.620 +-- D.J.Rose, R.E.Tarjan, and G.S.Lueker. Algorithmic aspects of vertex
230.621 +-- elimination on graphs. SIAM J. Comput. 5, 1976, 266-83.
230.622 +--
230.623 +-- The authors of the cited paper show that we have the same result if
230.624 +-- we merge row k of the matrix A and such rows of the matrix U (among
230.625 +-- rows 1, ..., k-1) whose leftmost non-diagonal non-zero element is
230.626 +-- placed in k-th column. This feature signficantly reduces the number
230.627 +-- of rows to be merged, especially on the final steps, where rows of
230.628 +-- the matrix U become quite dense.
230.629 +--
230.630 +-- To determine rows, which should be merged on k-th step, for a fixed
230.631 +-- time the routine uses linked lists of row numbers of the matrix U.
230.632 +-- Location head[k] contains the number of a first row, whose leftmost
230.633 +-- non-diagonal non-zero element is placed in column k, and location
230.634 +-- next[i] contains the number of a next row with the same property as
230.635 +-- row i. */
230.636 +
230.637 +int *chol_symbolic(int n, int A_ptr[], int A_ind[], int U_ptr[])
230.638 +{ int i, j, k, t, len, size, beg, end, min_j, *U_ind, *head, *next,
230.639 + *ind, *map, *temp;
230.640 + /* initially we assume that on computing the pattern of U fill-in
230.641 + will double the number of non-zeros in A */
230.642 + size = A_ptr[n+1] - 1;
230.643 + if (size < n) size = n;
230.644 + size += size;
230.645 + U_ind = xcalloc(1+size, sizeof(int));
230.646 + /* allocate and initialize working arrays */
230.647 + head = xcalloc(1+n, sizeof(int));
230.648 + for (i = 1; i <= n; i++) head[i] = 0;
230.649 + next = xcalloc(1+n, sizeof(int));
230.650 + ind = xcalloc(1+n, sizeof(int));
230.651 + map = xcalloc(1+n, sizeof(int));
230.652 + for (j = 1; j <= n; j++) map[j] = 0;
230.653 + /* compute the pattern of matrix U */
230.654 + U_ptr[1] = 1;
230.655 + for (k = 1; k <= n; k++)
230.656 + { /* compute the pattern of k-th row of U, which is the union of
230.657 + k-th row of A and those rows of U (among 1, ..., k-1) whose
230.658 + leftmost non-diagonal non-zero is placed in k-th column */
230.659 + /* (ind) := (k-th row of A) */
230.660 + len = A_ptr[k+1] - A_ptr[k];
230.661 + memcpy(&ind[1], &A_ind[A_ptr[k]], len * sizeof(int));
230.662 + for (t = 1; t <= len; t++)
230.663 + { j = ind[t];
230.664 + xassert(k < j && j <= n);
230.665 + map[j] = 1;
230.666 + }
230.667 + /* walk through rows of U whose leftmost non-diagonal non-zero
230.668 + is placed in k-th column */
230.669 + for (i = head[k]; i != 0; i = next[i])
230.670 + { /* (ind) := (ind) union (i-th row of U) */
230.671 + beg = U_ptr[i], end = U_ptr[i+1];
230.672 + for (t = beg; t < end; t++)
230.673 + { j = U_ind[t];
230.674 + if (j > k && !map[j]) ind[++len] = j, map[j] = 1;
230.675 + }
230.676 + }
230.677 + /* now (ind) is the pattern of k-th row of U */
230.678 + U_ptr[k+1] = U_ptr[k] + len;
230.679 + /* at least (U_ptr[k+1] - 1) locations should be available in
230.680 + the array U_ind */
230.681 + if (U_ptr[k+1] - 1 > size)
230.682 + { temp = U_ind;
230.683 + size += size;
230.684 + U_ind = xcalloc(1+size, sizeof(int));
230.685 + memcpy(&U_ind[1], &temp[1], (U_ptr[k] - 1) * sizeof(int));
230.686 + xfree(temp);
230.687 + }
230.688 + xassert(U_ptr[k+1] - 1 <= size);
230.689 + /* (k-th row of U) := (ind) */
230.690 + memcpy(&U_ind[U_ptr[k]], &ind[1], len * sizeof(int));
230.691 + /* determine column index of leftmost non-diagonal non-zero in
230.692 + k-th row of U and clear the row pattern map */
230.693 + min_j = n + 1;
230.694 + for (t = 1; t <= len; t++)
230.695 + { j = ind[t], map[j] = 0;
230.696 + if (min_j > j) min_j = j;
230.697 + }
230.698 + /* include k-th row into corresponding linked list */
230.699 + if (min_j <= n) next[k] = head[min_j], head[min_j] = k;
230.700 + }
230.701 + /* free working arrays */
230.702 + xfree(head);
230.703 + xfree(next);
230.704 + xfree(ind);
230.705 + xfree(map);
230.706 + /* reallocate the array U_ind to free unused locations */
230.707 + temp = U_ind;
230.708 + size = U_ptr[n+1] - 1;
230.709 + U_ind = xcalloc(1+size, sizeof(int));
230.710 + memcpy(&U_ind[1], &temp[1], size * sizeof(int));
230.711 + xfree(temp);
230.712 + return U_ind;
230.713 +}
230.714 +
230.715 +/*----------------------------------------------------------------------
230.716 +-- chol_numeric - compute Cholesky factorization (numeric phase).
230.717 +--
230.718 +-- *Synopsis*
230.719 +--
230.720 +-- #include "glpmat.h"
230.721 +-- int chol_numeric(int n,
230.722 +-- int A_ptr[], int A_ind[], double A_val[], double A_diag[],
230.723 +-- int U_ptr[], int U_ind[], double U_val[], double U_diag[]);
230.724 +--
230.725 +-- *Description*
230.726 +--
230.727 +-- The routine chol_symbolic implements the numeric phase of Cholesky
230.728 +-- factorization A = U'*U, where A is a given sparse symmetric positive
230.729 +-- definite matrix, U is a resultant upper triangular factor, U' is a
230.730 +-- matrix transposed to U.
230.731 +--
230.732 +-- The parameter n is the order of matrices A and U.
230.733 +--
230.734 +-- Upper triangular part of the matrix A without diagonal elements is
230.735 +-- specified in the arrays A_ptr, A_ind, and A_val in storage-by-rows
230.736 +-- format. Diagonal elements of A are specified in the array A_diag,
230.737 +-- where A_diag[0] is not used, A_diag[i] = a[i,i] for i = 1, ..., n.
230.738 +-- The arrays A_ptr, A_ind, A_val, and A_diag are not changed on exit.
230.739 +--
230.740 +-- The pattern of the matrix U without diagonal elements (previously
230.741 +-- computed with the routine chol_symbolic) is specified in the arrays
230.742 +-- U_ptr and U_ind, which are not changed on exit. Numeric values of
230.743 +-- non-diagonal elements of U are stored in corresponding locations of
230.744 +-- the array U_val, and values of diagonal elements of U are stored in
230.745 +-- locations U_diag[1], ..., U_diag[n].
230.746 +--
230.747 +-- *Returns*
230.748 +--
230.749 +-- The routine returns the number of non-positive diagonal elements of
230.750 +-- the matrix U which have been replaced by a huge positive number (see
230.751 +-- the method description below). Zero return code means the matrix A
230.752 +-- has been successfully factorized.
230.753 +--
230.754 +-- *Method*
230.755 +--
230.756 +-- The routine chol_numeric computes the matrix U in a row-wise manner
230.757 +-- using standard gaussian elimination technique. No pivoting is used.
230.758 +--
230.759 +-- Initially the routine sets U = A, and before k-th elimination step
230.760 +-- the matrix U is the following:
230.761 +--
230.762 +-- 1 k n
230.763 +-- 1 x x x x x x x x x x
230.764 +-- . x x x x x x x x x
230.765 +-- . . x x x x x x x x
230.766 +-- . . . x x x x x x x
230.767 +-- k . . . . * * * * * *
230.768 +-- . . . . * * * * * *
230.769 +-- . . . . * * * * * *
230.770 +-- . . . . * * * * * *
230.771 +-- . . . . * * * * * *
230.772 +-- n . . . . * * * * * *
230.773 +--
230.774 +-- where 'x' are elements of already computed rows, '*' are elements of
230.775 +-- the active submatrix. (Note that the lower triangular part of the
230.776 +-- active submatrix being symmetric is not stored and diagonal elements
230.777 +-- are stored separately in the array U_diag.)
230.778 +--
230.779 +-- The matrix A is assumed to be positive definite. However, if it is
230.780 +-- close to semi-definite, on some elimination step a pivot u[k,k] may
230.781 +-- happen to be non-positive due to round-off errors. In this case the
230.782 +-- routine uses a technique proposed in:
230.783 +--
230.784 +-- S.J.Wright. The Cholesky factorization in interior-point and barrier
230.785 +-- methods. Preprint MCS-P600-0596, Mathematics and Computer Science
230.786 +-- Division, Argonne National Laboratory, Argonne, Ill., May 1996.
230.787 +--
230.788 +-- The routine just replaces non-positive u[k,k] by a huge positive
230.789 +-- number. This involves non-diagonal elements in k-th row of U to be
230.790 +-- close to zero that, in turn, involves k-th component of a solution
230.791 +-- vector to be close to zero. Note, however, that this technique works
230.792 +-- only if the system A*x = b is consistent. */
230.793 +
230.794 +int chol_numeric(int n,
230.795 + int A_ptr[], int A_ind[], double A_val[], double A_diag[],
230.796 + int U_ptr[], int U_ind[], double U_val[], double U_diag[])
230.797 +{ int i, j, k, t, t1, beg, end, beg1, end1, count = 0;
230.798 + double ukk, uki, *work;
230.799 + work = xcalloc(1+n, sizeof(double));
230.800 + for (j = 1; j <= n; j++) work[j] = 0.0;
230.801 + /* U := (upper triangle of A) */
230.802 + /* note that the upper traingle of A is a subset of U */
230.803 + for (i = 1; i <= n; i++)
230.804 + { beg = A_ptr[i], end = A_ptr[i+1];
230.805 + for (t = beg; t < end; t++)
230.806 + j = A_ind[t], work[j] = A_val[t];
230.807 + beg = U_ptr[i], end = U_ptr[i+1];
230.808 + for (t = beg; t < end; t++)
230.809 + j = U_ind[t], U_val[t] = work[j], work[j] = 0.0;
230.810 + U_diag[i] = A_diag[i];
230.811 + }
230.812 + /* main elimination loop */
230.813 + for (k = 1; k <= n; k++)
230.814 + { /* transform k-th row of U */
230.815 + ukk = U_diag[k];
230.816 + if (ukk > 0.0)
230.817 + U_diag[k] = ukk = sqrt(ukk);
230.818 + else
230.819 + U_diag[k] = ukk = DBL_MAX, count++;
230.820 + /* (work) := (transformed k-th row) */
230.821 + beg = U_ptr[k], end = U_ptr[k+1];
230.822 + for (t = beg; t < end; t++)
230.823 + work[U_ind[t]] = (U_val[t] /= ukk);
230.824 + /* transform other rows of U */
230.825 + for (t = beg; t < end; t++)
230.826 + { i = U_ind[t];
230.827 + xassert(i > k);
230.828 + /* (i-th row) := (i-th row) - u[k,i] * (k-th row) */
230.829 + uki = work[i];
230.830 + beg1 = U_ptr[i], end1 = U_ptr[i+1];
230.831 + for (t1 = beg1; t1 < end1; t1++)
230.832 + U_val[t1] -= uki * work[U_ind[t1]];
230.833 + U_diag[i] -= uki * uki;
230.834 + }
230.835 + /* (work) := 0 */
230.836 + for (t = beg; t < end; t++)
230.837 + work[U_ind[t]] = 0.0;
230.838 + }
230.839 + xfree(work);
230.840 + return count;
230.841 +}
230.842 +
230.843 +/*----------------------------------------------------------------------
230.844 +-- u_solve - solve upper triangular system U*x = b.
230.845 +--
230.846 +-- *Synopsis*
230.847 +--
230.848 +-- #include "glpmat.h"
230.849 +-- void u_solve(int n, int U_ptr[], int U_ind[], double U_val[],
230.850 +-- double U_diag[], double x[]);
230.851 +--
230.852 +-- *Description*
230.853 +--
230.854 +-- The routine u_solve solves an linear system U*x = b, where U is an
230.855 +-- upper triangular matrix.
230.856 +--
230.857 +-- The parameter n is the order of matrix U.
230.858 +--
230.859 +-- The matrix U without diagonal elements is specified in the arrays
230.860 +-- U_ptr, U_ind, and U_val in storage-by-rows format. Diagonal elements
230.861 +-- of U are specified in the array U_diag, where U_diag[0] is not used,
230.862 +-- U_diag[i] = u[i,i] for i = 1, ..., n. All these four arrays are not
230.863 +-- changed on exit.
230.864 +--
230.865 +-- The right-hand side vector b is specified on entry in the array x,
230.866 +-- where x[0] is not used, and x[i] = b[i] for i = 1, ..., n. On exit
230.867 +-- the routine stores computed components of the vector of unknowns x
230.868 +-- in the array x in the same manner. */
230.869 +
230.870 +void u_solve(int n, int U_ptr[], int U_ind[], double U_val[],
230.871 + double U_diag[], double x[])
230.872 +{ int i, t, beg, end;
230.873 + double temp;
230.874 + for (i = n; i >= 1; i--)
230.875 + { temp = x[i];
230.876 + beg = U_ptr[i], end = U_ptr[i+1];
230.877 + for (t = beg; t < end; t++)
230.878 + temp -= U_val[t] * x[U_ind[t]];
230.879 + xassert(U_diag[i] != 0.0);
230.880 + x[i] = temp / U_diag[i];
230.881 + }
230.882 + return;
230.883 +}
230.884 +
230.885 +/*----------------------------------------------------------------------
230.886 +-- ut_solve - solve lower triangular system U'*x = b.
230.887 +--
230.888 +-- *Synopsis*
230.889 +--
230.890 +-- #include "glpmat.h"
230.891 +-- void ut_solve(int n, int U_ptr[], int U_ind[], double U_val[],
230.892 +-- double U_diag[], double x[]);
230.893 +--
230.894 +-- *Description*
230.895 +--
230.896 +-- The routine ut_solve solves an linear system U'*x = b, where U is a
230.897 +-- matrix transposed to an upper triangular matrix.
230.898 +--
230.899 +-- The parameter n is the order of matrix U.
230.900 +--
230.901 +-- The matrix U without diagonal elements is specified in the arrays
230.902 +-- U_ptr, U_ind, and U_val in storage-by-rows format. Diagonal elements
230.903 +-- of U are specified in the array U_diag, where U_diag[0] is not used,
230.904 +-- U_diag[i] = u[i,i] for i = 1, ..., n. All these four arrays are not
230.905 +-- changed on exit.
230.906 +--
230.907 +-- The right-hand side vector b is specified on entry in the array x,
230.908 +-- where x[0] is not used, and x[i] = b[i] for i = 1, ..., n. On exit
230.909 +-- the routine stores computed components of the vector of unknowns x
230.910 +-- in the array x in the same manner. */
230.911 +
230.912 +void ut_solve(int n, int U_ptr[], int U_ind[], double U_val[],
230.913 + double U_diag[], double x[])
230.914 +{ int i, t, beg, end;
230.915 + double temp;
230.916 + for (i = 1; i <= n; i++)
230.917 + { xassert(U_diag[i] != 0.0);
230.918 + temp = (x[i] /= U_diag[i]);
230.919 + if (temp == 0.0) continue;
230.920 + beg = U_ptr[i], end = U_ptr[i+1];
230.921 + for (t = beg; t < end; t++)
230.922 + x[U_ind[t]] -= U_val[t] * temp;
230.923 + }
230.924 + return;
230.925 +}
230.926 +
230.927 +/* eof */
231.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
231.2 +++ b/src/glpmat.h Mon Dec 06 13:09:21 2010 +0100
231.3 @@ -0,0 +1,198 @@
231.4 +/* glpmat.h (linear algebra routines) */
231.5 +
231.6 +/***********************************************************************
231.7 +* This code is part of GLPK (GNU Linear Programming Kit).
231.8 +*
231.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
231.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
231.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
231.12 +* E-mail: <mao@gnu.org>.
231.13 +*
231.14 +* GLPK is free software: you can redistribute it and/or modify it
231.15 +* under the terms of the GNU General Public License as published by
231.16 +* the Free Software Foundation, either version 3 of the License, or
231.17 +* (at your option) any later version.
231.18 +*
231.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
231.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
231.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
231.22 +* License for more details.
231.23 +*
231.24 +* You should have received a copy of the GNU General Public License
231.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
231.26 +***********************************************************************/
231.27 +
231.28 +#ifndef GLPMAT_H
231.29 +#define GLPMAT_H
231.30 +
231.31 +/***********************************************************************
231.32 +* FULL-VECTOR STORAGE
231.33 +*
231.34 +* For a sparse vector x having n elements, ne of which are non-zero,
231.35 +* the full-vector storage format uses two arrays x_ind and x_vec, which
231.36 +* are set up as follows:
231.37 +*
231.38 +* x_ind is an integer array of length [1+ne]. Location x_ind[0] is
231.39 +* not used, and locations x_ind[1], ..., x_ind[ne] contain indices of
231.40 +* non-zero elements in vector x.
231.41 +*
231.42 +* x_vec is a floating-point array of length [1+n]. Location x_vec[0]
231.43 +* is not used, and locations x_vec[1], ..., x_vec[n] contain numeric
231.44 +* values of ALL elements in vector x, including its zero elements.
231.45 +*
231.46 +* Let, for example, the following sparse vector x be given:
231.47 +*
231.48 +* (0, 1, 0, 0, 2, 3, 0, 4)
231.49 +*
231.50 +* Then the arrays are:
231.51 +*
231.52 +* x_ind = { X; 2, 5, 6, 8 }
231.53 +*
231.54 +* x_vec = { X; 0, 1, 0, 0, 2, 3, 0, 4 }
231.55 +*
231.56 +* COMPRESSED-VECTOR STORAGE
231.57 +*
231.58 +* For a sparse vector x having n elements, ne of which are non-zero,
231.59 +* the compressed-vector storage format uses two arrays x_ind and x_vec,
231.60 +* which are set up as follows:
231.61 +*
231.62 +* x_ind is an integer array of length [1+ne]. Location x_ind[0] is
231.63 +* not used, and locations x_ind[1], ..., x_ind[ne] contain indices of
231.64 +* non-zero elements in vector x.
231.65 +*
231.66 +* x_vec is a floating-point array of length [1+ne]. Location x_vec[0]
231.67 +* is not used, and locations x_vec[1], ..., x_vec[ne] contain numeric
231.68 +* values of corresponding non-zero elements in vector x.
231.69 +*
231.70 +* Let, for example, the following sparse vector x be given:
231.71 +*
231.72 +* (0, 1, 0, 0, 2, 3, 0, 4)
231.73 +*
231.74 +* Then the arrays are:
231.75 +*
231.76 +* x_ind = { X; 2, 5, 6, 8 }
231.77 +*
231.78 +* x_vec = { X; 1, 2, 3, 4 }
231.79 +*
231.80 +* STORAGE-BY-ROWS
231.81 +*
231.82 +* For a sparse matrix A, which has m rows, n columns, and ne non-zero
231.83 +* elements the storage-by-rows format uses three arrays A_ptr, A_ind,
231.84 +* and A_val, which are set up as follows:
231.85 +*
231.86 +* A_ptr is an integer array of length [1+m+1] also called "row pointer
231.87 +* array". It contains the relative starting positions of each row of A
231.88 +* in the arrays A_ind and A_val, i.e. element A_ptr[i], 1 <= i <= m,
231.89 +* indicates where row i begins in the arrays A_ind and A_val. If all
231.90 +* elements in row i are zero, then A_ptr[i] = A_ptr[i+1]. Location
231.91 +* A_ptr[0] is not used, location A_ptr[1] must contain 1, and location
231.92 +* A_ptr[m+1] must contain ne+1 that indicates the position after the
231.93 +* last element in the arrays A_ind and A_val.
231.94 +*
231.95 +* A_ind is an integer array of length [1+ne]. Location A_ind[0] is not
231.96 +* used, and locations A_ind[1], ..., A_ind[ne] contain column indices
231.97 +* of (non-zero) elements in matrix A.
231.98 +*
231.99 +* A_val is a floating-point array of length [1+ne]. Location A_val[0]
231.100 +* is not used, and locations A_val[1], ..., A_val[ne] contain numeric
231.101 +* values of non-zero elements in matrix A.
231.102 +*
231.103 +* Non-zero elements of matrix A are stored contiguously, and the rows
231.104 +* of matrix A are stored consecutively from 1 to m in the arrays A_ind
231.105 +* and A_val. The elements in each row of A may be stored in any order
231.106 +* in A_ind and A_val. Note that elements with duplicate column indices
231.107 +* are not allowed.
231.108 +*
231.109 +* Let, for example, the following sparse matrix A be given:
231.110 +*
231.111 +* | 11 . 13 . . . |
231.112 +* | 21 22 . 24 . . |
231.113 +* | . 32 33 . . . |
231.114 +* | . . 43 44 . 46 |
231.115 +* | . . . . . . |
231.116 +* | 61 62 . . . 66 |
231.117 +*
231.118 +* Then the arrays are:
231.119 +*
231.120 +* A_ptr = { X; 1, 3, 6, 8, 11, 11; 14 }
231.121 +*
231.122 +* A_ind = { X; 1, 3; 4, 2, 1; 2, 3; 4, 3, 6; 1, 2, 6 }
231.123 +*
231.124 +* A_val = { X; 11, 13; 24, 22, 21; 32, 33; 44, 43, 46; 61, 62, 66 }
231.125 +*
231.126 +* PERMUTATION MATRICES
231.127 +*
231.128 +* Let P be a permutation matrix of the order n. It is represented as
231.129 +* an integer array P_per of length [1+n+n] as follows: if p[i,j] = 1,
231.130 +* then P_per[i] = j and P_per[n+j] = i. Location P_per[0] is not used.
231.131 +*
231.132 +* Let A' = P*A. If i-th row of A corresponds to i'-th row of A', then
231.133 +* P_per[i'] = i and P_per[n+i] = i'.
231.134 +*
231.135 +* References:
231.136 +*
231.137 +* 1. Gustavson F.G. Some basic techniques for solving sparse systems of
231.138 +* linear equations. In Rose and Willoughby (1972), pp. 41-52.
231.139 +*
231.140 +* 2. Basic Linear Algebra Subprograms Technical (BLAST) Forum Standard.
231.141 +* University of Tennessee (2001). */
231.142 +
231.143 +#define check_fvs _glp_mat_check_fvs
231.144 +int check_fvs(int n, int nnz, int ind[], double vec[]);
231.145 +/* check sparse vector in full-vector storage format */
231.146 +
231.147 +#define check_pattern _glp_mat_check_pattern
231.148 +int check_pattern(int m, int n, int A_ptr[], int A_ind[]);
231.149 +/* check pattern of sparse matrix */
231.150 +
231.151 +#define transpose _glp_mat_transpose
231.152 +void transpose(int m, int n, int A_ptr[], int A_ind[], double A_val[],
231.153 + int AT_ptr[], int AT_ind[], double AT_val[]);
231.154 +/* transpose sparse matrix */
231.155 +
231.156 +#define adat_symbolic _glp_mat_adat_symbolic
231.157 +int *adat_symbolic(int m, int n, int P_per[], int A_ptr[], int A_ind[],
231.158 + int S_ptr[]);
231.159 +/* compute S = P*A*D*A'*P' (symbolic phase) */
231.160 +
231.161 +#define adat_numeric _glp_mat_adat_numeric
231.162 +void adat_numeric(int m, int n, int P_per[],
231.163 + int A_ptr[], int A_ind[], double A_val[], double D_diag[],
231.164 + int S_ptr[], int S_ind[], double S_val[], double S_diag[]);
231.165 +/* compute S = P*A*D*A'*P' (numeric phase) */
231.166 +
231.167 +#define min_degree _glp_mat_min_degree
231.168 +void min_degree(int n, int A_ptr[], int A_ind[], int P_per[]);
231.169 +/* minimum degree ordering */
231.170 +
231.171 +#define amd_order1 _glp_mat_amd_order1
231.172 +void amd_order1(int n, int A_ptr[], int A_ind[], int P_per[]);
231.173 +/* approximate minimum degree ordering (AMD) */
231.174 +
231.175 +#define symamd_ord _glp_mat_symamd_ord
231.176 +void symamd_ord(int n, int A_ptr[], int A_ind[], int P_per[]);
231.177 +/* approximate minimum degree ordering (SYMAMD) */
231.178 +
231.179 +#define chol_symbolic _glp_mat_chol_symbolic
231.180 +int *chol_symbolic(int n, int A_ptr[], int A_ind[], int U_ptr[]);
231.181 +/* compute Cholesky factorization (symbolic phase) */
231.182 +
231.183 +#define chol_numeric _glp_mat_chol_numeric
231.184 +int chol_numeric(int n,
231.185 + int A_ptr[], int A_ind[], double A_val[], double A_diag[],
231.186 + int U_ptr[], int U_ind[], double U_val[], double U_diag[]);
231.187 +/* compute Cholesky factorization (numeric phase) */
231.188 +
231.189 +#define u_solve _glp_mat_u_solve
231.190 +void u_solve(int n, int U_ptr[], int U_ind[], double U_val[],
231.191 + double U_diag[], double x[]);
231.192 +/* solve upper triangular system U*x = b */
231.193 +
231.194 +#define ut_solve _glp_mat_ut_solve
231.195 +void ut_solve(int n, int U_ptr[], int U_ind[], double U_val[],
231.196 + double U_diag[], double x[]);
231.197 +/* solve lower triangular system U'*x = b */
231.198 +
231.199 +#endif
231.200 +
231.201 +/* eof */
232.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
232.2 +++ b/src/glpmpl.h Mon Dec 06 13:09:21 2010 +0100
232.3 @@ -0,0 +1,2583 @@
232.4 +/* glpmpl.h (GNU MathProg translator) */
232.5 +
232.6 +/***********************************************************************
232.7 +* This code is part of GLPK (GNU Linear Programming Kit).
232.8 +*
232.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
232.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
232.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
232.12 +* E-mail: <mao@gnu.org>.
232.13 +*
232.14 +* GLPK is free software: you can redistribute it and/or modify it
232.15 +* under the terms of the GNU General Public License as published by
232.16 +* the Free Software Foundation, either version 3 of the License, or
232.17 +* (at your option) any later version.
232.18 +*
232.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
232.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
232.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
232.22 +* License for more details.
232.23 +*
232.24 +* You should have received a copy of the GNU General Public License
232.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
232.26 +***********************************************************************/
232.27 +
232.28 +#ifndef GLPMPL_H
232.29 +#define GLPMPL_H
232.30 +
232.31 +#include "glpavl.h"
232.32 +#include "glprng.h"
232.33 +
232.34 +typedef struct MPL MPL;
232.35 +typedef char STRING;
232.36 +typedef struct SYMBOL SYMBOL;
232.37 +typedef struct TUPLE TUPLE;
232.38 +typedef struct ARRAY ELEMSET;
232.39 +typedef struct ELEMVAR ELEMVAR;
232.40 +typedef struct FORMULA FORMULA;
232.41 +typedef struct ELEMCON ELEMCON;
232.42 +typedef union VALUE VALUE;
232.43 +typedef struct ARRAY ARRAY;
232.44 +typedef struct MEMBER MEMBER;
232.45 +#if 1
232.46 +/* many C compilers have DOMAIN declared in <math.h> :( */
232.47 +#undef DOMAIN
232.48 +#define DOMAIN DOMAIN1
232.49 +#endif
232.50 +typedef struct DOMAIN DOMAIN;
232.51 +typedef struct DOMAIN_BLOCK DOMAIN_BLOCK;
232.52 +typedef struct DOMAIN_SLOT DOMAIN_SLOT;
232.53 +typedef struct SET SET;
232.54 +typedef struct WITHIN WITHIN;
232.55 +typedef struct GADGET GADGET;
232.56 +typedef struct PARAMETER PARAMETER;
232.57 +typedef struct CONDITION CONDITION;
232.58 +typedef struct VARIABLE VARIABLE;
232.59 +typedef struct CONSTRAINT CONSTRAINT;
232.60 +typedef struct TABLE TABLE;
232.61 +typedef struct TABARG TABARG;
232.62 +typedef struct TABFLD TABFLD;
232.63 +typedef struct TABIN TABIN;
232.64 +typedef struct TABOUT TABOUT;
232.65 +typedef struct TABDCA TABDCA;
232.66 +typedef union OPERANDS OPERANDS;
232.67 +typedef struct ARG_LIST ARG_LIST;
232.68 +typedef struct CODE CODE;
232.69 +typedef struct CHECK CHECK;
232.70 +typedef struct DISPLAY DISPLAY;
232.71 +typedef struct DISPLAY1 DISPLAY1;
232.72 +typedef struct PRINTF PRINTF;
232.73 +typedef struct PRINTF1 PRINTF1;
232.74 +typedef struct FOR FOR;
232.75 +typedef struct STATEMENT STATEMENT;
232.76 +typedef struct TUPLE SLICE;
232.77 +
232.78 +/**********************************************************************/
232.79 +/* * * TRANSLATOR DATABASE * * */
232.80 +/**********************************************************************/
232.81 +
232.82 +#define A_BINARY 101 /* something binary */
232.83 +#define A_CHECK 102 /* check statement */
232.84 +#define A_CONSTRAINT 103 /* model constraint */
232.85 +#define A_DISPLAY 104 /* display statement */
232.86 +#define A_ELEMCON 105 /* elemental constraint/objective */
232.87 +#define A_ELEMSET 106 /* elemental set */
232.88 +#define A_ELEMVAR 107 /* elemental variable */
232.89 +#define A_EXPRESSION 108 /* expression */
232.90 +#define A_FOR 109 /* for statement */
232.91 +#define A_FORMULA 110 /* formula */
232.92 +#define A_INDEX 111 /* dummy index */
232.93 +#define A_INPUT 112 /* input table */
232.94 +#define A_INTEGER 113 /* something integer */
232.95 +#define A_LOGICAL 114 /* something logical */
232.96 +#define A_MAXIMIZE 115 /* objective has to be maximized */
232.97 +#define A_MINIMIZE 116 /* objective has to be minimized */
232.98 +#define A_NONE 117 /* nothing */
232.99 +#define A_NUMERIC 118 /* something numeric */
232.100 +#define A_OUTPUT 119 /* output table */
232.101 +#define A_PARAMETER 120 /* model parameter */
232.102 +#define A_PRINTF 121 /* printf statement */
232.103 +#define A_SET 122 /* model set */
232.104 +#define A_SOLVE 123 /* solve statement */
232.105 +#define A_SYMBOLIC 124 /* something symbolic */
232.106 +#define A_TABLE 125 /* data table */
232.107 +#define A_TUPLE 126 /* n-tuple */
232.108 +#define A_VARIABLE 127 /* model variable */
232.109 +
232.110 +#define MAX_LENGTH 100
232.111 +/* maximal length of any symbolic value (this includes symbolic names,
232.112 + numeric and string literals, and all symbolic values that may appear
232.113 + during the evaluation phase) */
232.114 +
232.115 +#define CONTEXT_SIZE 60
232.116 +/* size of the context queue, in characters */
232.117 +
232.118 +#define OUTBUF_SIZE 1024
232.119 +/* size of the output buffer, in characters */
232.120 +
232.121 +struct MPL
232.122 +{ /* translator database */
232.123 + /*--------------------------------------------------------------*/
232.124 + /* scanning segment */
232.125 + int line;
232.126 + /* number of the current text line */
232.127 + int c;
232.128 + /* the current character or EOF */
232.129 + int token;
232.130 + /* the current token: */
232.131 +#define T_EOF 201 /* end of file */
232.132 +#define T_NAME 202 /* symbolic name (model section only) */
232.133 +#define T_SYMBOL 203 /* symbol (data section only) */
232.134 +#define T_NUMBER 204 /* numeric literal */
232.135 +#define T_STRING 205 /* string literal */
232.136 +#define T_AND 206 /* and && */
232.137 +#define T_BY 207 /* by */
232.138 +#define T_CROSS 208 /* cross */
232.139 +#define T_DIFF 209 /* diff */
232.140 +#define T_DIV 210 /* div */
232.141 +#define T_ELSE 211 /* else */
232.142 +#define T_IF 212 /* if */
232.143 +#define T_IN 213 /* in */
232.144 +#define T_INFINITY 214 /* Infinity */
232.145 +#define T_INTER 215 /* inter */
232.146 +#define T_LESS 216 /* less */
232.147 +#define T_MOD 217 /* mod */
232.148 +#define T_NOT 218 /* not ! */
232.149 +#define T_OR 219 /* or || */
232.150 +#define T_SPTP 220 /* s.t. */
232.151 +#define T_SYMDIFF 221 /* symdiff */
232.152 +#define T_THEN 222 /* then */
232.153 +#define T_UNION 223 /* union */
232.154 +#define T_WITHIN 224 /* within */
232.155 +#define T_PLUS 225 /* + */
232.156 +#define T_MINUS 226 /* - */
232.157 +#define T_ASTERISK 227 /* * */
232.158 +#define T_SLASH 228 /* / */
232.159 +#define T_POWER 229 /* ^ ** */
232.160 +#define T_LT 230 /* < */
232.161 +#define T_LE 231 /* <= */
232.162 +#define T_EQ 232 /* = == */
232.163 +#define T_GE 233 /* >= */
232.164 +#define T_GT 234 /* > */
232.165 +#define T_NE 235 /* <> != */
232.166 +#define T_CONCAT 236 /* & */
232.167 +#define T_BAR 237 /* | */
232.168 +#define T_POINT 238 /* . */
232.169 +#define T_COMMA 239 /* , */
232.170 +#define T_COLON 240 /* : */
232.171 +#define T_SEMICOLON 241 /* ; */
232.172 +#define T_ASSIGN 242 /* := */
232.173 +#define T_DOTS 243 /* .. */
232.174 +#define T_LEFT 244 /* ( */
232.175 +#define T_RIGHT 245 /* ) */
232.176 +#define T_LBRACKET 246 /* [ */
232.177 +#define T_RBRACKET 247 /* ] */
232.178 +#define T_LBRACE 248 /* { */
232.179 +#define T_RBRACE 249 /* } */
232.180 +#define T_APPEND 250 /* >> */
232.181 +#define T_TILDE 251 /* ~ */
232.182 +#define T_INPUT 252 /* <- */
232.183 + int imlen;
232.184 + /* length of the current token */
232.185 + char *image; /* char image[MAX_LENGTH+1]; */
232.186 + /* image of the current token */
232.187 + double value;
232.188 + /* value of the current token (for T_NUMBER only) */
232.189 + int b_token;
232.190 + /* the previous token */
232.191 + int b_imlen;
232.192 + /* length of the previous token */
232.193 + char *b_image; /* char b_image[MAX_LENGTH+1]; */
232.194 + /* image of the previous token */
232.195 + double b_value;
232.196 + /* value of the previous token (if token is T_NUMBER) */
232.197 + int f_dots;
232.198 + /* if this flag is set, the next token should be recognized as
232.199 + T_DOTS, not as T_POINT */
232.200 + int f_scan;
232.201 + /* if this flag is set, the next token is already scanned */
232.202 + int f_token;
232.203 + /* the next token */
232.204 + int f_imlen;
232.205 + /* length of the next token */
232.206 + char *f_image; /* char f_image[MAX_LENGTH+1]; */
232.207 + /* image of the next token */
232.208 + double f_value;
232.209 + /* value of the next token (if token is T_NUMBER) */
232.210 + char *context; /* char context[CONTEXT_SIZE]; */
232.211 + /* context circular queue (not null-terminated!) */
232.212 + int c_ptr;
232.213 + /* pointer to the current position in the context queue */
232.214 + int flag_d;
232.215 + /* if this flag is set, the data section is being processed */
232.216 + /*--------------------------------------------------------------*/
232.217 + /* translating segment */
232.218 + DMP *pool;
232.219 + /* memory pool used to allocate all data instances created during
232.220 + the translation phase */
232.221 + AVL *tree;
232.222 + /* symbolic name table:
232.223 + node.type = A_INDEX => node.link -> DOMAIN_SLOT
232.224 + node.type = A_SET => node.link -> SET
232.225 + node.type = A_PARAMETER => node.link -> PARAMETER
232.226 + node.type = A_VARIABLE => node.link -> VARIABLE
232.227 + node.type = A_CONSTRANT => node.link -> CONSTRAINT */
232.228 + STATEMENT *model;
232.229 + /* linked list of model statements in the original order */
232.230 + int flag_x;
232.231 + /* if this flag is set, the current token being left parenthesis
232.232 + begins a slice that allows recognizing any undeclared symbolic
232.233 + names as dummy indices; this flag is automatically reset once
232.234 + the next token has been scanned */
232.235 + int as_within;
232.236 + /* the warning "in understood as within" has been issued */
232.237 + int as_in;
232.238 + /* the warning "within understood as in" has been issued */
232.239 + int as_binary;
232.240 + /* the warning "logical understood as binary" has been issued */
232.241 + int flag_s;
232.242 + /* if this flag is set, the solve statement has been parsed */
232.243 + /*--------------------------------------------------------------*/
232.244 + /* common segment */
232.245 + DMP *strings;
232.246 + /* memory pool to allocate STRING data structures */
232.247 + DMP *symbols;
232.248 + /* memory pool to allocate SYMBOL data structures */
232.249 + DMP *tuples;
232.250 + /* memory pool to allocate TUPLE data structures */
232.251 + DMP *arrays;
232.252 + /* memory pool to allocate ARRAY data structures */
232.253 + DMP *members;
232.254 + /* memory pool to allocate MEMBER data structures */
232.255 + DMP *elemvars;
232.256 + /* memory pool to allocate ELEMVAR data structures */
232.257 + DMP *formulae;
232.258 + /* memory pool to allocate FORMULA data structures */
232.259 + DMP *elemcons;
232.260 + /* memory pool to allocate ELEMCON data structures */
232.261 + ARRAY *a_list;
232.262 + /* linked list of all arrays in the database */
232.263 + char *sym_buf; /* char sym_buf[255+1]; */
232.264 + /* working buffer used by the routine format_symbol */
232.265 + char *tup_buf; /* char tup_buf[255+1]; */
232.266 + /* working buffer used by the routine format_tuple */
232.267 + /*--------------------------------------------------------------*/
232.268 + /* generating/postsolving segment */
232.269 + RNG *rand;
232.270 + /* pseudo-random number generator */
232.271 + int flag_p;
232.272 + /* if this flag is set, the postsolving phase is in effect */
232.273 + STATEMENT *stmt;
232.274 + /* model statement being currently executed */
232.275 + TABDCA *dca;
232.276 + /* pointer to table driver communication area for table statement
232.277 + currently executed */
232.278 + int m;
232.279 + /* number of rows in the problem, m >= 0 */
232.280 + int n;
232.281 + /* number of columns in the problem, n >= 0 */
232.282 + ELEMCON **row; /* ELEMCON *row[1+m]; */
232.283 + /* row[0] is not used;
232.284 + row[i] is elemental constraint or objective, which corresponds
232.285 + to i-th row of the problem, 1 <= i <= m */
232.286 + ELEMVAR **col; /* ELEMVAR *col[1+n]; */
232.287 + /* col[0] is not used;
232.288 + col[j] is elemental variable, which corresponds to j-th column
232.289 + of the problem, 1 <= j <= n */
232.290 + /*--------------------------------------------------------------*/
232.291 + /* input/output segment */
232.292 + XFILE *in_fp;
232.293 + /* stream assigned to the input text file */
232.294 + char *in_file;
232.295 + /* name of the input text file */
232.296 + XFILE *out_fp;
232.297 + /* stream assigned to the output text file used to write all data
232.298 + produced by display and printf statements; NULL means the data
232.299 + should be sent to stdout via the routine xprintf */
232.300 + char *out_file;
232.301 + /* name of the output text file */
232.302 +#if 0 /* 08/XI-2009 */
232.303 + char *out_buf; /* char out_buf[OUTBUF_SIZE] */
232.304 + /* buffer to accumulate output data */
232.305 + int out_cnt;
232.306 + /* count of data bytes stored in the output buffer */
232.307 +#endif
232.308 + XFILE *prt_fp;
232.309 + /* stream assigned to the print text file; may be NULL */
232.310 + char *prt_file;
232.311 + /* name of the output print file */
232.312 + /*--------------------------------------------------------------*/
232.313 + /* solver interface segment */
232.314 + jmp_buf jump;
232.315 + /* jump address for non-local go to in case of error */
232.316 + int phase;
232.317 + /* phase of processing:
232.318 + 0 - database is being or has been initialized
232.319 + 1 - model section is being or has been read
232.320 + 2 - data section is being or has been read
232.321 + 3 - model is being or has been generated/postsolved
232.322 + 4 - model processing error has occurred */
232.323 + char *mod_file;
232.324 + /* name of the input text file, which contains model section */
232.325 + char *mpl_buf; /* char mpl_buf[255+1]; */
232.326 + /* working buffer used by some interface routines */
232.327 +};
232.328 +
232.329 +/**********************************************************************/
232.330 +/* * * PROCESSING MODEL SECTION * * */
232.331 +/**********************************************************************/
232.332 +
232.333 +#define alloc(type) ((type *)dmp_get_atomv(mpl->pool, sizeof(type)))
232.334 +/* allocate atom of given type */
232.335 +
232.336 +#define enter_context _glp_mpl_enter_context
232.337 +void enter_context(MPL *mpl);
232.338 +/* enter current token into context queue */
232.339 +
232.340 +#define print_context _glp_mpl_print_context
232.341 +void print_context(MPL *mpl);
232.342 +/* print current content of context queue */
232.343 +
232.344 +#define get_char _glp_mpl_get_char
232.345 +void get_char(MPL *mpl);
232.346 +/* scan next character from input text file */
232.347 +
232.348 +#define append_char _glp_mpl_append_char
232.349 +void append_char(MPL *mpl);
232.350 +/* append character to current token */
232.351 +
232.352 +#define get_token _glp_mpl_get_token
232.353 +void get_token(MPL *mpl);
232.354 +/* scan next token from input text file */
232.355 +
232.356 +#define unget_token _glp_mpl_unget_token
232.357 +void unget_token(MPL *mpl);
232.358 +/* return current token back to input stream */
232.359 +
232.360 +#define is_keyword _glp_mpl_is_keyword
232.361 +int is_keyword(MPL *mpl, char *keyword);
232.362 +/* check if current token is given non-reserved keyword */
232.363 +
232.364 +#define is_reserved _glp_mpl_is_reserved
232.365 +int is_reserved(MPL *mpl);
232.366 +/* check if current token is reserved keyword */
232.367 +
232.368 +#define make_code _glp_mpl_make_code
232.369 +CODE *make_code(MPL *mpl, int op, OPERANDS *arg, int type, int dim);
232.370 +/* generate pseudo-code (basic routine) */
232.371 +
232.372 +#define make_unary _glp_mpl_make_unary
232.373 +CODE *make_unary(MPL *mpl, int op, CODE *x, int type, int dim);
232.374 +/* generate pseudo-code for unary operation */
232.375 +
232.376 +#define make_binary _glp_mpl_make_binary
232.377 +CODE *make_binary(MPL *mpl, int op, CODE *x, CODE *y, int type,
232.378 + int dim);
232.379 +/* generate pseudo-code for binary operation */
232.380 +
232.381 +#define make_ternary _glp_mpl_make_ternary
232.382 +CODE *make_ternary(MPL *mpl, int op, CODE *x, CODE *y, CODE *z,
232.383 + int type, int dim);
232.384 +/* generate pseudo-code for ternary operation */
232.385 +
232.386 +#define numeric_literal _glp_mpl_numeric_literal
232.387 +CODE *numeric_literal(MPL *mpl);
232.388 +/* parse reference to numeric literal */
232.389 +
232.390 +#define string_literal _glp_mpl_string_literal
232.391 +CODE *string_literal(MPL *mpl);
232.392 +/* parse reference to string literal */
232.393 +
232.394 +#define create_arg_list _glp_mpl_create_arg_list
232.395 +ARG_LIST *create_arg_list(MPL *mpl);
232.396 +/* create empty operands list */
232.397 +
232.398 +#define expand_arg_list _glp_mpl_expand_arg_list
232.399 +ARG_LIST *expand_arg_list(MPL *mpl, ARG_LIST *list, CODE *x);
232.400 +/* append operand to operands list */
232.401 +
232.402 +#define arg_list_len _glp_mpl_arg_list_len
232.403 +int arg_list_len(MPL *mpl, ARG_LIST *list);
232.404 +/* determine length of operands list */
232.405 +
232.406 +#define subscript_list _glp_mpl_subscript_list
232.407 +ARG_LIST *subscript_list(MPL *mpl);
232.408 +/* parse subscript list */
232.409 +
232.410 +#define object_reference _glp_mpl_object_reference
232.411 +CODE *object_reference(MPL *mpl);
232.412 +/* parse reference to named object */
232.413 +
232.414 +#define numeric_argument _glp_mpl_numeric_argument
232.415 +CODE *numeric_argument(MPL *mpl, char *func);
232.416 +/* parse argument passed to built-in function */
232.417 +
232.418 +#define symbolic_argument _glp_mpl_symbolic_argument
232.419 +CODE *symbolic_argument(MPL *mpl, char *func);
232.420 +
232.421 +#define elemset_argument _glp_mpl_elemset_argument
232.422 +CODE *elemset_argument(MPL *mpl, char *func);
232.423 +
232.424 +#define function_reference _glp_mpl_function_reference
232.425 +CODE *function_reference(MPL *mpl);
232.426 +/* parse reference to built-in function */
232.427 +
232.428 +#define create_domain _glp_mpl_create_domain
232.429 +DOMAIN *create_domain(MPL *mpl);
232.430 +/* create empty domain */
232.431 +
232.432 +#define create_block _glp_mpl_create_block
232.433 +DOMAIN_BLOCK *create_block(MPL *mpl);
232.434 +/* create empty domain block */
232.435 +
232.436 +#define append_block _glp_mpl_append_block
232.437 +void append_block(MPL *mpl, DOMAIN *domain, DOMAIN_BLOCK *block);
232.438 +/* append domain block to specified domain */
232.439 +
232.440 +#define append_slot _glp_mpl_append_slot
232.441 +DOMAIN_SLOT *append_slot(MPL *mpl, DOMAIN_BLOCK *block, char *name,
232.442 + CODE *code);
232.443 +/* create and append new slot to domain block */
232.444 +
232.445 +#define expression_list _glp_mpl_expression_list
232.446 +CODE *expression_list(MPL *mpl);
232.447 +/* parse expression list */
232.448 +
232.449 +#define literal_set _glp_mpl_literal_set
232.450 +CODE *literal_set(MPL *mpl, CODE *code);
232.451 +/* parse literal set */
232.452 +
232.453 +#define indexing_expression _glp_mpl_indexing_expression
232.454 +DOMAIN *indexing_expression(MPL *mpl);
232.455 +/* parse indexing expression */
232.456 +
232.457 +#define close_scope _glp_mpl_close_scope
232.458 +void close_scope(MPL *mpl, DOMAIN *domain);
232.459 +/* close scope of indexing expression */
232.460 +
232.461 +#define iterated_expression _glp_mpl_iterated_expression
232.462 +CODE *iterated_expression(MPL *mpl);
232.463 +/* parse iterated expression */
232.464 +
232.465 +#define domain_arity _glp_mpl_domain_arity
232.466 +int domain_arity(MPL *mpl, DOMAIN *domain);
232.467 +/* determine arity of domain */
232.468 +
232.469 +#define set_expression _glp_mpl_set_expression
232.470 +CODE *set_expression(MPL *mpl);
232.471 +/* parse set expression */
232.472 +
232.473 +#define branched_expression _glp_mpl_branched_expression
232.474 +CODE *branched_expression(MPL *mpl);
232.475 +/* parse conditional expression */
232.476 +
232.477 +#define primary_expression _glp_mpl_primary_expression
232.478 +CODE *primary_expression(MPL *mpl);
232.479 +/* parse primary expression */
232.480 +
232.481 +#define error_preceding _glp_mpl_error_preceding
232.482 +void error_preceding(MPL *mpl, char *opstr);
232.483 +/* raise error if preceding operand has wrong type */
232.484 +
232.485 +#define error_following _glp_mpl_error_following
232.486 +void error_following(MPL *mpl, char *opstr);
232.487 +/* raise error if following operand has wrong type */
232.488 +
232.489 +#define error_dimension _glp_mpl_error_dimension
232.490 +void error_dimension(MPL *mpl, char *opstr, int dim1, int dim2);
232.491 +/* raise error if operands have different dimension */
232.492 +
232.493 +#define expression_0 _glp_mpl_expression_0
232.494 +CODE *expression_0(MPL *mpl);
232.495 +/* parse expression of level 0 */
232.496 +
232.497 +#define expression_1 _glp_mpl_expression_1
232.498 +CODE *expression_1(MPL *mpl);
232.499 +/* parse expression of level 1 */
232.500 +
232.501 +#define expression_2 _glp_mpl_expression_2
232.502 +CODE *expression_2(MPL *mpl);
232.503 +/* parse expression of level 2 */
232.504 +
232.505 +#define expression_3 _glp_mpl_expression_3
232.506 +CODE *expression_3(MPL *mpl);
232.507 +/* parse expression of level 3 */
232.508 +
232.509 +#define expression_4 _glp_mpl_expression_4
232.510 +CODE *expression_4(MPL *mpl);
232.511 +/* parse expression of level 4 */
232.512 +
232.513 +#define expression_5 _glp_mpl_expression_5
232.514 +CODE *expression_5(MPL *mpl);
232.515 +/* parse expression of level 5 */
232.516 +
232.517 +#define expression_6 _glp_mpl_expression_6
232.518 +CODE *expression_6(MPL *mpl);
232.519 +/* parse expression of level 6 */
232.520 +
232.521 +#define expression_7 _glp_mpl_expression_7
232.522 +CODE *expression_7(MPL *mpl);
232.523 +/* parse expression of level 7 */
232.524 +
232.525 +#define expression_8 _glp_mpl_expression_8
232.526 +CODE *expression_8(MPL *mpl);
232.527 +/* parse expression of level 8 */
232.528 +
232.529 +#define expression_9 _glp_mpl_expression_9
232.530 +CODE *expression_9(MPL *mpl);
232.531 +/* parse expression of level 9 */
232.532 +
232.533 +#define expression_10 _glp_mpl_expression_10
232.534 +CODE *expression_10(MPL *mpl);
232.535 +/* parse expression of level 10 */
232.536 +
232.537 +#define expression_11 _glp_mpl_expression_11
232.538 +CODE *expression_11(MPL *mpl);
232.539 +/* parse expression of level 11 */
232.540 +
232.541 +#define expression_12 _glp_mpl_expression_12
232.542 +CODE *expression_12(MPL *mpl);
232.543 +/* parse expression of level 12 */
232.544 +
232.545 +#define expression_13 _glp_mpl_expression_13
232.546 +CODE *expression_13(MPL *mpl);
232.547 +/* parse expression of level 13 */
232.548 +
232.549 +#define set_statement _glp_mpl_set_statement
232.550 +SET *set_statement(MPL *mpl);
232.551 +/* parse set statement */
232.552 +
232.553 +#define parameter_statement _glp_mpl_parameter_statement
232.554 +PARAMETER *parameter_statement(MPL *mpl);
232.555 +/* parse parameter statement */
232.556 +
232.557 +#define variable_statement _glp_mpl_variable_statement
232.558 +VARIABLE *variable_statement(MPL *mpl);
232.559 +/* parse variable statement */
232.560 +
232.561 +#define constraint_statement _glp_mpl_constraint_statement
232.562 +CONSTRAINT *constraint_statement(MPL *mpl);
232.563 +/* parse constraint statement */
232.564 +
232.565 +#define objective_statement _glp_mpl_objective_statement
232.566 +CONSTRAINT *objective_statement(MPL *mpl);
232.567 +/* parse objective statement */
232.568 +
232.569 +#define table_statement _glp_mpl_table_statement
232.570 +TABLE *table_statement(MPL *mpl);
232.571 +/* parse table statement */
232.572 +
232.573 +#define solve_statement _glp_mpl_solve_statement
232.574 +void *solve_statement(MPL *mpl);
232.575 +/* parse solve statement */
232.576 +
232.577 +#define check_statement _glp_mpl_check_statement
232.578 +CHECK *check_statement(MPL *mpl);
232.579 +/* parse check statement */
232.580 +
232.581 +#define display_statement _glp_mpl_display_statement
232.582 +DISPLAY *display_statement(MPL *mpl);
232.583 +/* parse display statement */
232.584 +
232.585 +#define printf_statement _glp_mpl_printf_statement
232.586 +PRINTF *printf_statement(MPL *mpl);
232.587 +/* parse printf statement */
232.588 +
232.589 +#define for_statement _glp_mpl_for_statement
232.590 +FOR *for_statement(MPL *mpl);
232.591 +/* parse for statement */
232.592 +
232.593 +#define end_statement _glp_mpl_end_statement
232.594 +void end_statement(MPL *mpl);
232.595 +/* parse end statement */
232.596 +
232.597 +#define simple_statement _glp_mpl_simple_statement
232.598 +STATEMENT *simple_statement(MPL *mpl, int spec);
232.599 +/* parse simple statement */
232.600 +
232.601 +#define model_section _glp_mpl_model_section
232.602 +void model_section(MPL *mpl);
232.603 +/* parse model section */
232.604 +
232.605 +/**********************************************************************/
232.606 +/* * * PROCESSING DATA SECTION * * */
232.607 +/**********************************************************************/
232.608 +
232.609 +#if 2 + 2 == 5
232.610 +struct SLICE /* see TUPLE */
232.611 +{ /* component of slice; the slice itself is associated with its
232.612 + first component; slices are similar to n-tuples with exception
232.613 + that some slice components (which are indicated by asterisks)
232.614 + don't refer to any symbols */
232.615 + SYMBOL *sym;
232.616 + /* symbol, which this component refers to; can be NULL */
232.617 + SLICE *next;
232.618 + /* the next component of slice */
232.619 +};
232.620 +#endif
232.621 +
232.622 +#define create_slice _glp_mpl_create_slice
232.623 +SLICE *create_slice(MPL *mpl);
232.624 +/* create slice */
232.625 +
232.626 +#define expand_slice _glp_mpl_expand_slice
232.627 +SLICE *expand_slice
232.628 +( MPL *mpl,
232.629 + SLICE *slice, /* destroyed */
232.630 + SYMBOL *sym /* destroyed */
232.631 +);
232.632 +/* append new component to slice */
232.633 +
232.634 +#define slice_dimen _glp_mpl_slice_dimen
232.635 +int slice_dimen
232.636 +( MPL *mpl,
232.637 + SLICE *slice /* not changed */
232.638 +);
232.639 +/* determine dimension of slice */
232.640 +
232.641 +#define slice_arity _glp_mpl_slice_arity
232.642 +int slice_arity
232.643 +( MPL *mpl,
232.644 + SLICE *slice /* not changed */
232.645 +);
232.646 +/* determine arity of slice */
232.647 +
232.648 +#define fake_slice _glp_mpl_fake_slice
232.649 +SLICE *fake_slice(MPL *mpl, int dim);
232.650 +/* create fake slice of all asterisks */
232.651 +
232.652 +#define delete_slice _glp_mpl_delete_slice
232.653 +void delete_slice
232.654 +( MPL *mpl,
232.655 + SLICE *slice /* destroyed */
232.656 +);
232.657 +/* delete slice */
232.658 +
232.659 +#define is_number _glp_mpl_is_number
232.660 +int is_number(MPL *mpl);
232.661 +/* check if current token is number */
232.662 +
232.663 +#define is_symbol _glp_mpl_is_symbol
232.664 +int is_symbol(MPL *mpl);
232.665 +/* check if current token is symbol */
232.666 +
232.667 +#define is_literal _glp_mpl_is_literal
232.668 +int is_literal(MPL *mpl, char *literal);
232.669 +/* check if current token is given symbolic literal */
232.670 +
232.671 +#define read_number _glp_mpl_read_number
232.672 +double read_number(MPL *mpl);
232.673 +/* read number */
232.674 +
232.675 +#define read_symbol _glp_mpl_read_symbol
232.676 +SYMBOL *read_symbol(MPL *mpl);
232.677 +/* read symbol */
232.678 +
232.679 +#define read_slice _glp_mpl_read_slice
232.680 +SLICE *read_slice
232.681 +( MPL *mpl,
232.682 + char *name, /* not changed */
232.683 + int dim
232.684 +);
232.685 +/* read slice */
232.686 +
232.687 +#define select_set _glp_mpl_select_set
232.688 +SET *select_set
232.689 +( MPL *mpl,
232.690 + char *name /* not changed */
232.691 +);
232.692 +/* select set to saturate it with elemental sets */
232.693 +
232.694 +#define simple_format _glp_mpl_simple_format
232.695 +void simple_format
232.696 +( MPL *mpl,
232.697 + SET *set, /* not changed */
232.698 + MEMBER *memb, /* modified */
232.699 + SLICE *slice /* not changed */
232.700 +);
232.701 +/* read set data block in simple format */
232.702 +
232.703 +#define matrix_format _glp_mpl_matrix_format
232.704 +void matrix_format
232.705 +( MPL *mpl,
232.706 + SET *set, /* not changed */
232.707 + MEMBER *memb, /* modified */
232.708 + SLICE *slice, /* not changed */
232.709 + int tr
232.710 +);
232.711 +/* read set data block in matrix format */
232.712 +
232.713 +#define set_data _glp_mpl_set_data
232.714 +void set_data(MPL *mpl);
232.715 +/* read set data */
232.716 +
232.717 +#define select_parameter _glp_mpl_select_parameter
232.718 +PARAMETER *select_parameter
232.719 +( MPL *mpl,
232.720 + char *name /* not changed */
232.721 +);
232.722 +/* select parameter to saturate it with data */
232.723 +
232.724 +#define set_default _glp_mpl_set_default
232.725 +void set_default
232.726 +( MPL *mpl,
232.727 + PARAMETER *par, /* not changed */
232.728 + SYMBOL *altval /* destroyed */
232.729 +);
232.730 +/* set default parameter value */
232.731 +
232.732 +#define read_value _glp_mpl_read_value
232.733 +MEMBER *read_value
232.734 +( MPL *mpl,
232.735 + PARAMETER *par, /* not changed */
232.736 + TUPLE *tuple /* destroyed */
232.737 +);
232.738 +/* read value and assign it to parameter member */
232.739 +
232.740 +#define plain_format _glp_mpl_plain_format
232.741 +void plain_format
232.742 +( MPL *mpl,
232.743 + PARAMETER *par, /* not changed */
232.744 + SLICE *slice /* not changed */
232.745 +);
232.746 +/* read parameter data block in plain format */
232.747 +
232.748 +#define tabular_format _glp_mpl_tabular_format
232.749 +void tabular_format
232.750 +( MPL *mpl,
232.751 + PARAMETER *par, /* not changed */
232.752 + SLICE *slice, /* not changed */
232.753 + int tr
232.754 +);
232.755 +/* read parameter data block in tabular format */
232.756 +
232.757 +#define tabbing_format _glp_mpl_tabbing_format
232.758 +void tabbing_format
232.759 +( MPL *mpl,
232.760 + SYMBOL *altval /* not changed */
232.761 +);
232.762 +/* read parameter data block in tabbing format */
232.763 +
232.764 +#define parameter_data _glp_mpl_parameter_data
232.765 +void parameter_data(MPL *mpl);
232.766 +/* read parameter data */
232.767 +
232.768 +#define data_section _glp_mpl_data_section
232.769 +void data_section(MPL *mpl);
232.770 +/* read data section */
232.771 +
232.772 +/**********************************************************************/
232.773 +/* * * FLOATING-POINT NUMBERS * * */
232.774 +/**********************************************************************/
232.775 +
232.776 +#define fp_add _glp_mpl_fp_add
232.777 +double fp_add(MPL *mpl, double x, double y);
232.778 +/* floating-point addition */
232.779 +
232.780 +#define fp_sub _glp_mpl_fp_sub
232.781 +double fp_sub(MPL *mpl, double x, double y);
232.782 +/* floating-point subtraction */
232.783 +
232.784 +#define fp_less _glp_mpl_fp_less
232.785 +double fp_less(MPL *mpl, double x, double y);
232.786 +/* floating-point non-negative subtraction */
232.787 +
232.788 +#define fp_mul _glp_mpl_fp_mul
232.789 +double fp_mul(MPL *mpl, double x, double y);
232.790 +/* floating-point multiplication */
232.791 +
232.792 +#define fp_div _glp_mpl_fp_div
232.793 +double fp_div(MPL *mpl, double x, double y);
232.794 +/* floating-point division */
232.795 +
232.796 +#define fp_idiv _glp_mpl_fp_idiv
232.797 +double fp_idiv(MPL *mpl, double x, double y);
232.798 +/* floating-point quotient of exact division */
232.799 +
232.800 +#define fp_mod _glp_mpl_fp_mod
232.801 +double fp_mod(MPL *mpl, double x, double y);
232.802 +/* floating-point remainder of exact division */
232.803 +
232.804 +#define fp_power _glp_mpl_fp_power
232.805 +double fp_power(MPL *mpl, double x, double y);
232.806 +/* floating-point exponentiation (raise to power) */
232.807 +
232.808 +#define fp_exp _glp_mpl_fp_exp
232.809 +double fp_exp(MPL *mpl, double x);
232.810 +/* floating-point base-e exponential */
232.811 +
232.812 +#define fp_log _glp_mpl_fp_log
232.813 +double fp_log(MPL *mpl, double x);
232.814 +/* floating-point natural logarithm */
232.815 +
232.816 +#define fp_log10 _glp_mpl_fp_log10
232.817 +double fp_log10(MPL *mpl, double x);
232.818 +/* floating-point common (decimal) logarithm */
232.819 +
232.820 +#define fp_sqrt _glp_mpl_fp_sqrt
232.821 +double fp_sqrt(MPL *mpl, double x);
232.822 +/* floating-point square root */
232.823 +
232.824 +#define fp_sin _glp_mpl_fp_sin
232.825 +double fp_sin(MPL *mpl, double x);
232.826 +/* floating-point trigonometric sine */
232.827 +
232.828 +#define fp_cos _glp_mpl_fp_cos
232.829 +double fp_cos(MPL *mpl, double x);
232.830 +/* floating-point trigonometric cosine */
232.831 +
232.832 +#define fp_atan _glp_mpl_fp_atan
232.833 +double fp_atan(MPL *mpl, double x);
232.834 +/* floating-point trigonometric arctangent */
232.835 +
232.836 +#define fp_atan2 _glp_mpl_fp_atan2
232.837 +double fp_atan2(MPL *mpl, double y, double x);
232.838 +/* floating-point trigonometric arctangent */
232.839 +
232.840 +#define fp_round _glp_mpl_fp_round
232.841 +double fp_round(MPL *mpl, double x, double n);
232.842 +/* round floating-point value to n fractional digits */
232.843 +
232.844 +#define fp_trunc _glp_mpl_fp_trunc
232.845 +double fp_trunc(MPL *mpl, double x, double n);
232.846 +/* truncate floating-point value to n fractional digits */
232.847 +
232.848 +/**********************************************************************/
232.849 +/* * * PSEUDO-RANDOM NUMBER GENERATORS * * */
232.850 +/**********************************************************************/
232.851 +
232.852 +#define fp_irand224 _glp_mpl_fp_irand224
232.853 +double fp_irand224(MPL *mpl);
232.854 +/* pseudo-random integer in the range [0, 2^24) */
232.855 +
232.856 +#define fp_uniform01 _glp_mpl_fp_uniform01
232.857 +double fp_uniform01(MPL *mpl);
232.858 +/* pseudo-random number in the range [0, 1) */
232.859 +
232.860 +#define fp_uniform _glp_mpl_uniform
232.861 +double fp_uniform(MPL *mpl, double a, double b);
232.862 +/* pseudo-random number in the range [a, b) */
232.863 +
232.864 +#define fp_normal01 _glp_mpl_fp_normal01
232.865 +double fp_normal01(MPL *mpl);
232.866 +/* Gaussian random variate with mu = 0 and sigma = 1 */
232.867 +
232.868 +#define fp_normal _glp_mpl_fp_normal
232.869 +double fp_normal(MPL *mpl, double mu, double sigma);
232.870 +/* Gaussian random variate with specified mu and sigma */
232.871 +
232.872 +/**********************************************************************/
232.873 +/* * * DATE/TIME * * */
232.874 +/**********************************************************************/
232.875 +
232.876 +#define fn_gmtime _glp_mpl_fn_gmtime
232.877 +double fn_gmtime(MPL *mpl);
232.878 +/* obtain the current calendar time (UTC) */
232.879 +
232.880 +#define fn_str2time _glp_mpl_fn_str2time
232.881 +double fn_str2time(MPL *mpl, const char *str, const char *fmt);
232.882 +/* convert character string to the calendar time */
232.883 +
232.884 +#define fn_time2str _glp_mpl_fn_time2str
232.885 +void fn_time2str(MPL *mpl, char *str, double t, const char *fmt);
232.886 +/* convert the calendar time to character string */
232.887 +
232.888 +/**********************************************************************/
232.889 +/* * * CHARACTER STRINGS * * */
232.890 +/**********************************************************************/
232.891 +
232.892 +#define create_string _glp_mpl_create_string
232.893 +STRING *create_string
232.894 +( MPL *mpl,
232.895 + char buf[MAX_LENGTH+1] /* not changed */
232.896 +);
232.897 +/* create character string */
232.898 +
232.899 +#define copy_string _glp_mpl_copy_string
232.900 +STRING *copy_string
232.901 +( MPL *mpl,
232.902 + STRING *str /* not changed */
232.903 +);
232.904 +/* make copy of character string */
232.905 +
232.906 +#define compare_strings _glp_mpl_compare_strings
232.907 +int compare_strings
232.908 +( MPL *mpl,
232.909 + STRING *str1, /* not changed */
232.910 + STRING *str2 /* not changed */
232.911 +);
232.912 +/* compare one character string with another */
232.913 +
232.914 +#define fetch_string _glp_mpl_fetch_string
232.915 +char *fetch_string
232.916 +( MPL *mpl,
232.917 + STRING *str, /* not changed */
232.918 + char buf[MAX_LENGTH+1] /* modified */
232.919 +);
232.920 +/* extract content of character string */
232.921 +
232.922 +#define delete_string _glp_mpl_delete_string
232.923 +void delete_string
232.924 +( MPL *mpl,
232.925 + STRING *str /* destroyed */
232.926 +);
232.927 +/* delete character string */
232.928 +
232.929 +/**********************************************************************/
232.930 +/* * * SYMBOLS * * */
232.931 +/**********************************************************************/
232.932 +
232.933 +struct SYMBOL
232.934 +{ /* symbol (numeric or abstract quantity) */
232.935 + double num;
232.936 + /* numeric value of symbol (used only if str == NULL) */
232.937 + STRING *str;
232.938 + /* abstract value of symbol (used only if str != NULL) */
232.939 +};
232.940 +
232.941 +#define create_symbol_num _glp_mpl_create_symbol_num
232.942 +SYMBOL *create_symbol_num(MPL *mpl, double num);
232.943 +/* create symbol of numeric type */
232.944 +
232.945 +#define create_symbol_str _glp_mpl_create_symbol_str
232.946 +SYMBOL *create_symbol_str
232.947 +( MPL *mpl,
232.948 + STRING *str /* destroyed */
232.949 +);
232.950 +/* create symbol of abstract type */
232.951 +
232.952 +#define copy_symbol _glp_mpl_copy_symbol
232.953 +SYMBOL *copy_symbol
232.954 +( MPL *mpl,
232.955 + SYMBOL *sym /* not changed */
232.956 +);
232.957 +/* make copy of symbol */
232.958 +
232.959 +#define compare_symbols _glp_mpl_compare_symbols
232.960 +int compare_symbols
232.961 +( MPL *mpl,
232.962 + SYMBOL *sym1, /* not changed */
232.963 + SYMBOL *sym2 /* not changed */
232.964 +);
232.965 +/* compare one symbol with another */
232.966 +
232.967 +#define delete_symbol _glp_mpl_delete_symbol
232.968 +void delete_symbol
232.969 +( MPL *mpl,
232.970 + SYMBOL *sym /* destroyed */
232.971 +);
232.972 +/* delete symbol */
232.973 +
232.974 +#define format_symbol _glp_mpl_format_symbol
232.975 +char *format_symbol
232.976 +( MPL *mpl,
232.977 + SYMBOL *sym /* not changed */
232.978 +);
232.979 +/* format symbol for displaying or printing */
232.980 +
232.981 +#define concat_symbols _glp_mpl_concat_symbols
232.982 +SYMBOL *concat_symbols
232.983 +( MPL *mpl,
232.984 + SYMBOL *sym1, /* destroyed */
232.985 + SYMBOL *sym2 /* destroyed */
232.986 +);
232.987 +/* concatenate one symbol with another */
232.988 +
232.989 +/**********************************************************************/
232.990 +/* * * N-TUPLES * * */
232.991 +/**********************************************************************/
232.992 +
232.993 +struct TUPLE
232.994 +{ /* component of n-tuple; the n-tuple itself is associated with
232.995 + its first component; (note that 0-tuple has no components) */
232.996 + SYMBOL *sym;
232.997 + /* symbol, which the component refers to; cannot be NULL */
232.998 + TUPLE *next;
232.999 + /* the next component of n-tuple */
232.1000 +};
232.1001 +
232.1002 +#define create_tuple _glp_mpl_create_tuple
232.1003 +TUPLE *create_tuple(MPL *mpl);
232.1004 +/* create n-tuple */
232.1005 +
232.1006 +#define expand_tuple _glp_mpl_expand_tuple
232.1007 +TUPLE *expand_tuple
232.1008 +( MPL *mpl,
232.1009 + TUPLE *tuple, /* destroyed */
232.1010 + SYMBOL *sym /* destroyed */
232.1011 +);
232.1012 +/* append symbol to n-tuple */
232.1013 +
232.1014 +#define tuple_dimen _glp_mpl_tuple_dimen
232.1015 +int tuple_dimen
232.1016 +( MPL *mpl,
232.1017 + TUPLE *tuple /* not changed */
232.1018 +);
232.1019 +/* determine dimension of n-tuple */
232.1020 +
232.1021 +#define copy_tuple _glp_mpl_copy_tuple
232.1022 +TUPLE *copy_tuple
232.1023 +( MPL *mpl,
232.1024 + TUPLE *tuple /* not changed */
232.1025 +);
232.1026 +/* make copy of n-tuple */
232.1027 +
232.1028 +#define compare_tuples _glp_mpl_compare_tuples
232.1029 +int compare_tuples
232.1030 +( MPL *mpl,
232.1031 + TUPLE *tuple1, /* not changed */
232.1032 + TUPLE *tuple2 /* not changed */
232.1033 +);
232.1034 +/* compare one n-tuple with another */
232.1035 +
232.1036 +#define build_subtuple _glp_mpl_build_subtuple
232.1037 +TUPLE *build_subtuple
232.1038 +( MPL *mpl,
232.1039 + TUPLE *tuple, /* not changed */
232.1040 + int dim
232.1041 +);
232.1042 +/* build subtuple of given n-tuple */
232.1043 +
232.1044 +#define delete_tuple _glp_mpl_delete_tuple
232.1045 +void delete_tuple
232.1046 +( MPL *mpl,
232.1047 + TUPLE *tuple /* destroyed */
232.1048 +);
232.1049 +/* delete n-tuple */
232.1050 +
232.1051 +#define format_tuple _glp_mpl_format_tuple
232.1052 +char *format_tuple
232.1053 +( MPL *mpl,
232.1054 + int c,
232.1055 + TUPLE *tuple /* not changed */
232.1056 +);
232.1057 +/* format n-tuple for displaying or printing */
232.1058 +
232.1059 +/**********************************************************************/
232.1060 +/* * * ELEMENTAL SETS * * */
232.1061 +/**********************************************************************/
232.1062 +
232.1063 +#if 2 + 2 == 5
232.1064 +struct ELEMSET /* see ARRAY */
232.1065 +{ /* elemental set of n-tuples; formally it is a "value" assigned
232.1066 + to members of model sets (like numbers and symbols, which are
232.1067 + values assigned to members of model parameters); note that a
232.1068 + simple model set is not an elemental set, it is 0-dimensional
232.1069 + array, the only member of which (if it exists) is assigned an
232.1070 + elemental set */
232.1071 +#endif
232.1072 +
232.1073 +#define create_elemset _glp_mpl_create_elemset
232.1074 +ELEMSET *create_elemset(MPL *mpl, int dim);
232.1075 +/* create elemental set */
232.1076 +
232.1077 +#define find_tuple _glp_mpl_find_tuple
232.1078 +MEMBER *find_tuple
232.1079 +( MPL *mpl,
232.1080 + ELEMSET *set, /* not changed */
232.1081 + TUPLE *tuple /* not changed */
232.1082 +);
232.1083 +/* check if elemental set contains given n-tuple */
232.1084 +
232.1085 +#define add_tuple _glp_mpl_add_tuple
232.1086 +MEMBER *add_tuple
232.1087 +( MPL *mpl,
232.1088 + ELEMSET *set, /* modified */
232.1089 + TUPLE *tuple /* destroyed */
232.1090 +);
232.1091 +/* add new n-tuple to elemental set */
232.1092 +
232.1093 +#define check_then_add _glp_mpl_check_then_add
232.1094 +MEMBER *check_then_add
232.1095 +( MPL *mpl,
232.1096 + ELEMSET *set, /* modified */
232.1097 + TUPLE *tuple /* destroyed */
232.1098 +);
232.1099 +/* check and add new n-tuple to elemental set */
232.1100 +
232.1101 +#define copy_elemset _glp_mpl_copy_elemset
232.1102 +ELEMSET *copy_elemset
232.1103 +( MPL *mpl,
232.1104 + ELEMSET *set /* not changed */
232.1105 +);
232.1106 +/* make copy of elemental set */
232.1107 +
232.1108 +#define delete_elemset _glp_mpl_delete_elemset
232.1109 +void delete_elemset
232.1110 +( MPL *mpl,
232.1111 + ELEMSET *set /* destroyed */
232.1112 +);
232.1113 +/* delete elemental set */
232.1114 +
232.1115 +#define arelset_size _glp_mpl_arelset_size
232.1116 +int arelset_size(MPL *mpl, double t0, double tf, double dt);
232.1117 +/* compute size of "arithmetic" elemental set */
232.1118 +
232.1119 +#define arelset_member _glp_mpl_arelset_member
232.1120 +double arelset_member(MPL *mpl, double t0, double tf, double dt, int j);
232.1121 +/* compute member of "arithmetic" elemental set */
232.1122 +
232.1123 +#define create_arelset _glp_mpl_create_arelset
232.1124 +ELEMSET *create_arelset(MPL *mpl, double t0, double tf, double dt);
232.1125 +/* create "arithmetic" elemental set */
232.1126 +
232.1127 +#define set_union _glp_mpl_set_union
232.1128 +ELEMSET *set_union
232.1129 +( MPL *mpl,
232.1130 + ELEMSET *X, /* destroyed */
232.1131 + ELEMSET *Y /* destroyed */
232.1132 +);
232.1133 +/* union of two elemental sets */
232.1134 +
232.1135 +#define set_diff _glp_mpl_set_diff
232.1136 +ELEMSET *set_diff
232.1137 +( MPL *mpl,
232.1138 + ELEMSET *X, /* destroyed */
232.1139 + ELEMSET *Y /* destroyed */
232.1140 +);
232.1141 +/* difference between two elemental sets */
232.1142 +
232.1143 +#define set_symdiff _glp_mpl_set_symdiff
232.1144 +ELEMSET *set_symdiff
232.1145 +( MPL *mpl,
232.1146 + ELEMSET *X, /* destroyed */
232.1147 + ELEMSET *Y /* destroyed */
232.1148 +);
232.1149 +/* symmetric difference between two elemental sets */
232.1150 +
232.1151 +#define set_inter _glp_mpl_set_inter
232.1152 +ELEMSET *set_inter
232.1153 +( MPL *mpl,
232.1154 + ELEMSET *X, /* destroyed */
232.1155 + ELEMSET *Y /* destroyed */
232.1156 +);
232.1157 +/* intersection of two elemental sets */
232.1158 +
232.1159 +#define set_cross _glp_mpl_set_cross
232.1160 +ELEMSET *set_cross
232.1161 +( MPL *mpl,
232.1162 + ELEMSET *X, /* destroyed */
232.1163 + ELEMSET *Y /* destroyed */
232.1164 +);
232.1165 +/* cross (Cartesian) product of two elemental sets */
232.1166 +
232.1167 +/**********************************************************************/
232.1168 +/* * * ELEMENTAL VARIABLES * * */
232.1169 +/**********************************************************************/
232.1170 +
232.1171 +struct ELEMVAR
232.1172 +{ /* elemental variable; formally it is a "value" assigned to
232.1173 + members of model variables (like numbers and symbols, which
232.1174 + are values assigned to members of model parameters) */
232.1175 + int j;
232.1176 + /* LP column number assigned to this elemental variable */
232.1177 + VARIABLE *var;
232.1178 + /* model variable, which contains this elemental variable */
232.1179 + MEMBER *memb;
232.1180 + /* array member, which is assigned this elemental variable */
232.1181 + double lbnd;
232.1182 + /* lower bound */
232.1183 + double ubnd;
232.1184 + /* upper bound */
232.1185 + double temp;
232.1186 + /* working quantity used in operations on linear forms; normally
232.1187 + it contains floating-point zero */
232.1188 +#if 1 /* 15/V-2010 */
232.1189 + int stat;
232.1190 + double prim, dual;
232.1191 + /* solution components provided by the solver */
232.1192 +#endif
232.1193 +};
232.1194 +
232.1195 +/**********************************************************************/
232.1196 +/* * * LINEAR FORMS * * */
232.1197 +/**********************************************************************/
232.1198 +
232.1199 +struct FORMULA
232.1200 +{ /* term of linear form c * x, where c is a coefficient, x is an
232.1201 + elemental variable; the linear form itself is the sum of terms
232.1202 + and is associated with its first term; (note that the linear
232.1203 + form may be empty that means the sum is equal to zero) */
232.1204 + double coef;
232.1205 + /* coefficient at elemental variable or constant term */
232.1206 + ELEMVAR *var;
232.1207 + /* reference to elemental variable; NULL means constant term */
232.1208 + FORMULA *next;
232.1209 + /* the next term of linear form */
232.1210 +};
232.1211 +
232.1212 +#define constant_term _glp_mpl_constant_term
232.1213 +FORMULA *constant_term(MPL *mpl, double coef);
232.1214 +/* create constant term */
232.1215 +
232.1216 +#define single_variable _glp_mpl_single_variable
232.1217 +FORMULA *single_variable
232.1218 +( MPL *mpl,
232.1219 + ELEMVAR *var /* referenced */
232.1220 +);
232.1221 +/* create single variable */
232.1222 +
232.1223 +#define copy_formula _glp_mpl_copy_formula
232.1224 +FORMULA *copy_formula
232.1225 +( MPL *mpl,
232.1226 + FORMULA *form /* not changed */
232.1227 +);
232.1228 +/* make copy of linear form */
232.1229 +
232.1230 +#define delete_formula _glp_mpl_delete_formula
232.1231 +void delete_formula
232.1232 +( MPL *mpl,
232.1233 + FORMULA *form /* destroyed */
232.1234 +);
232.1235 +/* delete linear form */
232.1236 +
232.1237 +#define linear_comb _glp_mpl_linear_comb
232.1238 +FORMULA *linear_comb
232.1239 +( MPL *mpl,
232.1240 + double a, FORMULA *fx, /* destroyed */
232.1241 + double b, FORMULA *fy /* destroyed */
232.1242 +);
232.1243 +/* linear combination of two linear forms */
232.1244 +
232.1245 +#define remove_constant _glp_mpl_remove_constant
232.1246 +FORMULA *remove_constant
232.1247 +( MPL *mpl,
232.1248 + FORMULA *form, /* destroyed */
232.1249 + double *coef /* modified */
232.1250 +);
232.1251 +/* remove constant term from linear form */
232.1252 +
232.1253 +#define reduce_terms _glp_mpl_reduce_terms
232.1254 +FORMULA *reduce_terms
232.1255 +( MPL *mpl,
232.1256 + FORMULA *form /* destroyed */
232.1257 +);
232.1258 +/* reduce identical terms in linear form */
232.1259 +
232.1260 +/**********************************************************************/
232.1261 +/* * * ELEMENTAL CONSTRAINTS * * */
232.1262 +/**********************************************************************/
232.1263 +
232.1264 +struct ELEMCON
232.1265 +{ /* elemental constraint; formally it is a "value" assigned to
232.1266 + members of model constraints (like numbers or symbols, which
232.1267 + are values assigned to members of model parameters) */
232.1268 + int i;
232.1269 + /* LP row number assigned to this elemental constraint */
232.1270 + CONSTRAINT *con;
232.1271 + /* model constraint, which contains this elemental constraint */
232.1272 + MEMBER *memb;
232.1273 + /* array member, which is assigned this elemental constraint */
232.1274 + FORMULA *form;
232.1275 + /* linear form */
232.1276 + double lbnd;
232.1277 + /* lower bound */
232.1278 + double ubnd;
232.1279 + /* upper bound */
232.1280 +#if 1 /* 15/V-2010 */
232.1281 + int stat;
232.1282 + double prim, dual;
232.1283 + /* solution components provided by the solver */
232.1284 +#endif
232.1285 +};
232.1286 +
232.1287 +/**********************************************************************/
232.1288 +/* * * GENERIC VALUES * * */
232.1289 +/**********************************************************************/
232.1290 +
232.1291 +union VALUE
232.1292 +{ /* generic value, which can be assigned to object member or be a
232.1293 + result of evaluation of expression */
232.1294 + /* indicator that specifies the particular type of generic value
232.1295 + is stored in the corresponding array or pseudo-code descriptor
232.1296 + and can be one of the following:
232.1297 + A_NONE - no value
232.1298 + A_NUMERIC - floating-point number
232.1299 + A_SYMBOLIC - symbol
232.1300 + A_LOGICAL - logical value
232.1301 + A_TUPLE - n-tuple
232.1302 + A_ELEMSET - elemental set
232.1303 + A_ELEMVAR - elemental variable
232.1304 + A_FORMULA - linear form
232.1305 + A_ELEMCON - elemental constraint */
232.1306 + void *none; /* null */
232.1307 + double num; /* value */
232.1308 + SYMBOL *sym; /* value */
232.1309 + int bit; /* value */
232.1310 + TUPLE *tuple; /* value */
232.1311 + ELEMSET *set; /* value */
232.1312 + ELEMVAR *var; /* reference */
232.1313 + FORMULA *form; /* value */
232.1314 + ELEMCON *con; /* reference */
232.1315 +};
232.1316 +
232.1317 +#define delete_value _glp_mpl_delete_value
232.1318 +void delete_value
232.1319 +( MPL *mpl,
232.1320 + int type,
232.1321 + VALUE *value /* content destroyed */
232.1322 +);
232.1323 +/* delete generic value */
232.1324 +
232.1325 +/**********************************************************************/
232.1326 +/* * * SYMBOLICALLY INDEXED ARRAYS * * */
232.1327 +/**********************************************************************/
232.1328 +
232.1329 +struct ARRAY
232.1330 +{ /* multi-dimensional array, a set of members indexed over simple
232.1331 + or compound sets of symbols; arrays are used to represent the
232.1332 + contents of model objects (i.e. sets, parameters, variables,
232.1333 + constraints, and objectives); arrays also are used as "values"
232.1334 + that are assigned to members of set objects, in which case the
232.1335 + array itself represents an elemental set */
232.1336 + int type;
232.1337 + /* type of generic values assigned to the array members:
232.1338 + A_NONE - none (members have no assigned values)
232.1339 + A_NUMERIC - floating-point numbers
232.1340 + A_SYMBOLIC - symbols
232.1341 + A_ELEMSET - elemental sets
232.1342 + A_ELEMVAR - elemental variables
232.1343 + A_ELEMCON - elemental constraints */
232.1344 + int dim;
232.1345 + /* dimension of the array that determines number of components in
232.1346 + n-tuples for all members of the array, dim >= 0; dim = 0 means
232.1347 + the array is 0-dimensional */
232.1348 + int size;
232.1349 + /* size of the array, i.e. number of its members */
232.1350 + MEMBER *head;
232.1351 + /* the first array member; NULL means the array is empty */
232.1352 + MEMBER *tail;
232.1353 + /* the last array member; NULL means the array is empty */
232.1354 + AVL *tree;
232.1355 + /* the search tree intended to find array members for logarithmic
232.1356 + time; NULL means the search tree doesn't exist */
232.1357 + ARRAY *prev;
232.1358 + /* the previous array in the translator database */
232.1359 + ARRAY *next;
232.1360 + /* the next array in the translator database */
232.1361 +};
232.1362 +
232.1363 +struct MEMBER
232.1364 +{ /* array member */
232.1365 + TUPLE *tuple;
232.1366 + /* n-tuple, which identifies the member; number of its components
232.1367 + is the same for all members within the array and determined by
232.1368 + the array dimension; duplicate members are not allowed */
232.1369 + MEMBER *next;
232.1370 + /* the next array member */
232.1371 + VALUE value;
232.1372 + /* generic value assigned to the member */
232.1373 +};
232.1374 +
232.1375 +#define create_array _glp_mpl_create_array
232.1376 +ARRAY *create_array(MPL *mpl, int type, int dim);
232.1377 +/* create array */
232.1378 +
232.1379 +#define find_member _glp_mpl_find_member
232.1380 +MEMBER *find_member
232.1381 +( MPL *mpl,
232.1382 + ARRAY *array, /* not changed */
232.1383 + TUPLE *tuple /* not changed */
232.1384 +);
232.1385 +/* find array member with given n-tuple */
232.1386 +
232.1387 +#define add_member _glp_mpl_add_member
232.1388 +MEMBER *add_member
232.1389 +( MPL *mpl,
232.1390 + ARRAY *array, /* modified */
232.1391 + TUPLE *tuple /* destroyed */
232.1392 +);
232.1393 +/* add new member to array */
232.1394 +
232.1395 +#define delete_array _glp_mpl_delete_array
232.1396 +void delete_array
232.1397 +( MPL *mpl,
232.1398 + ARRAY *array /* destroyed */
232.1399 +);
232.1400 +/* delete array */
232.1401 +
232.1402 +/**********************************************************************/
232.1403 +/* * * DOMAINS AND DUMMY INDICES * * */
232.1404 +/**********************************************************************/
232.1405 +
232.1406 +struct DOMAIN
232.1407 +{ /* domain (a simple or compound set); syntactically domain looks
232.1408 + like '{ i in I, (j,k) in S, t in T : <predicate> }'; domains
232.1409 + are used to define sets, over which model objects are indexed,
232.1410 + and also as constituents of iterated operators */
232.1411 + DOMAIN_BLOCK *list;
232.1412 + /* linked list of domain blocks (in the example above such blocks
232.1413 + are 'i in I', '(j,k) in S', and 't in T'); this list cannot be
232.1414 + empty */
232.1415 + CODE *code;
232.1416 + /* pseudo-code for computing the logical predicate, which follows
232.1417 + the colon; NULL means no predicate is specified */
232.1418 +};
232.1419 +
232.1420 +struct DOMAIN_BLOCK
232.1421 +{ /* domain block; syntactically domain blocks look like 'i in I',
232.1422 + '(j,k) in S', and 't in T' in the example above (in the sequel
232.1423 + sets like I, S, and T are called basic sets) */
232.1424 + DOMAIN_SLOT *list;
232.1425 + /* linked list of domain slots (i.e. indexing positions); number
232.1426 + of slots in this list is the same as dimension of n-tuples in
232.1427 + the basic set; this list cannot be empty */
232.1428 + CODE *code;
232.1429 + /* pseudo-code for computing basic set; cannot be NULL */
232.1430 + TUPLE *backup;
232.1431 + /* if this n-tuple is not empty, current values of dummy indices
232.1432 + in the domain block are the same as components of this n-tuple
232.1433 + (note that this n-tuple may have larger dimension than number
232.1434 + of dummy indices in this block, in which case extra components
232.1435 + are ignored); this n-tuple is used to restore former values of
232.1436 + dummy indices, if they were changed due to recursive calls to
232.1437 + the domain block */
232.1438 + DOMAIN_BLOCK *next;
232.1439 + /* the next block in the same domain */
232.1440 +};
232.1441 +
232.1442 +struct DOMAIN_SLOT
232.1443 +{ /* domain slot; it specifies an individual indexing position and
232.1444 + defines the corresponding dummy index */
232.1445 + char *name;
232.1446 + /* symbolic name of the dummy index; null pointer means the dummy
232.1447 + index is not explicitly specified */
232.1448 + CODE *code;
232.1449 + /* pseudo-code for computing symbolic value, at which the dummy
232.1450 + index is bound; NULL means the dummy index is free within the
232.1451 + domain scope */
232.1452 + SYMBOL *value;
232.1453 + /* current value assigned to the dummy index; NULL means no value
232.1454 + is assigned at the moment */
232.1455 + CODE *list;
232.1456 + /* linked list of pseudo-codes with operation O_INDEX referring
232.1457 + to this slot; this linked list is used to invalidate resultant
232.1458 + values of the operation, which depend on this dummy index */
232.1459 + DOMAIN_SLOT *next;
232.1460 + /* the next slot in the same domain block */
232.1461 +};
232.1462 +
232.1463 +#define assign_dummy_index _glp_mpl_assign_dummy_index
232.1464 +void assign_dummy_index
232.1465 +( MPL *mpl,
232.1466 + DOMAIN_SLOT *slot, /* modified */
232.1467 + SYMBOL *value /* not changed */
232.1468 +);
232.1469 +/* assign new value to dummy index */
232.1470 +
232.1471 +#define update_dummy_indices _glp_mpl_update_dummy_indices
232.1472 +void update_dummy_indices
232.1473 +( MPL *mpl,
232.1474 + DOMAIN_BLOCK *block /* not changed */
232.1475 +);
232.1476 +/* update current values of dummy indices */
232.1477 +
232.1478 +#define enter_domain_block _glp_mpl_enter_domain_block
232.1479 +int enter_domain_block
232.1480 +( MPL *mpl,
232.1481 + DOMAIN_BLOCK *block, /* not changed */
232.1482 + TUPLE *tuple, /* not changed */
232.1483 + void *info, void (*func)(MPL *mpl, void *info)
232.1484 +);
232.1485 +/* enter domain block */
232.1486 +
232.1487 +#define eval_within_domain _glp_mpl_eval_within_domain
232.1488 +int eval_within_domain
232.1489 +( MPL *mpl,
232.1490 + DOMAIN *domain, /* not changed */
232.1491 + TUPLE *tuple, /* not changed */
232.1492 + void *info, void (*func)(MPL *mpl, void *info)
232.1493 +);
232.1494 +/* perform evaluation within domain scope */
232.1495 +
232.1496 +#define loop_within_domain _glp_mpl_loop_within_domain
232.1497 +void loop_within_domain
232.1498 +( MPL *mpl,
232.1499 + DOMAIN *domain, /* not changed */
232.1500 + void *info, int (*func)(MPL *mpl, void *info)
232.1501 +);
232.1502 +/* perform iterations within domain scope */
232.1503 +
232.1504 +#define out_of_domain _glp_mpl_out_of_domain
232.1505 +void out_of_domain
232.1506 +( MPL *mpl,
232.1507 + char *name, /* not changed */
232.1508 + TUPLE *tuple /* not changed */
232.1509 +);
232.1510 +/* raise domain exception */
232.1511 +
232.1512 +#define get_domain_tuple _glp_mpl_get_domain_tuple
232.1513 +TUPLE *get_domain_tuple
232.1514 +( MPL *mpl,
232.1515 + DOMAIN *domain /* not changed */
232.1516 +);
232.1517 +/* obtain current n-tuple from domain */
232.1518 +
232.1519 +#define clean_domain _glp_mpl_clean_domain
232.1520 +void clean_domain(MPL *mpl, DOMAIN *domain);
232.1521 +/* clean domain */
232.1522 +
232.1523 +/**********************************************************************/
232.1524 +/* * * MODEL SETS * * */
232.1525 +/**********************************************************************/
232.1526 +
232.1527 +struct SET
232.1528 +{ /* model set */
232.1529 + char *name;
232.1530 + /* symbolic name; cannot be NULL */
232.1531 + char *alias;
232.1532 + /* alias; NULL means alias is not specified */
232.1533 + int dim; /* aka arity */
232.1534 + /* dimension (number of subscripts); dim = 0 means 0-dimensional
232.1535 + (unsubscripted) set, dim > 0 means set of sets */
232.1536 + DOMAIN *domain;
232.1537 + /* subscript domain; NULL for 0-dimensional set */
232.1538 + int dimen;
232.1539 + /* dimension of n-tuples, which members of this set consist of
232.1540 + (note that the model set itself is an array of elemental sets,
232.1541 + which are its members; so, don't confuse this dimension with
232.1542 + dimension of the model set); always non-zero */
232.1543 + WITHIN *within;
232.1544 + /* list of supersets, which restrict each member of the set to be
232.1545 + in every superset from this list; this list can be empty */
232.1546 + CODE *assign;
232.1547 + /* pseudo-code for computing assigned value; can be NULL */
232.1548 + CODE *option;
232.1549 + /* pseudo-code for computing default value; can be NULL */
232.1550 + GADGET *gadget;
232.1551 + /* plain set used to initialize the array of sets; can be NULL */
232.1552 + int data;
232.1553 + /* data status flag:
232.1554 + 0 - no data are provided in the data section
232.1555 + 1 - data are provided, but not checked yet
232.1556 + 2 - data are provided and have been checked */
232.1557 + ARRAY *array;
232.1558 + /* array of members, which are assigned elemental sets */
232.1559 +};
232.1560 +
232.1561 +struct WITHIN
232.1562 +{ /* restricting superset list entry */
232.1563 + CODE *code;
232.1564 + /* pseudo-code for computing the superset; cannot be NULL */
232.1565 + WITHIN *next;
232.1566 + /* the next entry for the same set or parameter */
232.1567 +};
232.1568 +
232.1569 +struct GADGET
232.1570 +{ /* plain set used to initialize the array of sets with data */
232.1571 + SET *set;
232.1572 + /* pointer to plain set; cannot be NULL */
232.1573 + int ind[20]; /* ind[dim+dimen]; */
232.1574 + /* permutation of integers 1, 2, ..., dim+dimen */
232.1575 +};
232.1576 +
232.1577 +#define check_elem_set _glp_mpl_check_elem_set
232.1578 +void check_elem_set
232.1579 +( MPL *mpl,
232.1580 + SET *set, /* not changed */
232.1581 + TUPLE *tuple, /* not changed */
232.1582 + ELEMSET *refer /* not changed */
232.1583 +);
232.1584 +/* check elemental set assigned to set member */
232.1585 +
232.1586 +#define take_member_set _glp_mpl_take_member_set
232.1587 +ELEMSET *take_member_set /* returns reference, not value */
232.1588 +( MPL *mpl,
232.1589 + SET *set, /* not changed */
232.1590 + TUPLE *tuple /* not changed */
232.1591 +);
232.1592 +/* obtain elemental set assigned to set member */
232.1593 +
232.1594 +#define eval_member_set _glp_mpl_eval_member_set
232.1595 +ELEMSET *eval_member_set /* returns reference, not value */
232.1596 +( MPL *mpl,
232.1597 + SET *set, /* not changed */
232.1598 + TUPLE *tuple /* not changed */
232.1599 +);
232.1600 +/* evaluate elemental set assigned to set member */
232.1601 +
232.1602 +#define eval_whole_set _glp_mpl_eval_whole_set
232.1603 +void eval_whole_set(MPL *mpl, SET *set);
232.1604 +/* evaluate model set over entire domain */
232.1605 +
232.1606 +#define clean_set _glp_mpl_clean_set
232.1607 +void clean_set(MPL *mpl, SET *set);
232.1608 +/* clean model set */
232.1609 +
232.1610 +/**********************************************************************/
232.1611 +/* * * MODEL PARAMETERS * * */
232.1612 +/**********************************************************************/
232.1613 +
232.1614 +struct PARAMETER
232.1615 +{ /* model parameter */
232.1616 + char *name;
232.1617 + /* symbolic name; cannot be NULL */
232.1618 + char *alias;
232.1619 + /* alias; NULL means alias is not specified */
232.1620 + int dim; /* aka arity */
232.1621 + /* dimension (number of subscripts); dim = 0 means 0-dimensional
232.1622 + (unsubscripted) parameter */
232.1623 + DOMAIN *domain;
232.1624 + /* subscript domain; NULL for 0-dimensional parameter */
232.1625 + int type;
232.1626 + /* parameter type:
232.1627 + A_NUMERIC - numeric
232.1628 + A_INTEGER - integer
232.1629 + A_BINARY - binary
232.1630 + A_SYMBOLIC - symbolic */
232.1631 + CONDITION *cond;
232.1632 + /* list of conditions, which restrict each parameter member to
232.1633 + satisfy to every condition from this list; this list is used
232.1634 + only for numeric parameters and can be empty */
232.1635 + WITHIN *in;
232.1636 + /* list of supersets, which restrict each parameter member to be
232.1637 + in every superset from this list; this list is used only for
232.1638 + symbolic parameters and can be empty */
232.1639 + CODE *assign;
232.1640 + /* pseudo-code for computing assigned value; can be NULL */
232.1641 + CODE *option;
232.1642 + /* pseudo-code for computing default value; can be NULL */
232.1643 + int data;
232.1644 + /* data status flag:
232.1645 + 0 - no data are provided in the data section
232.1646 + 1 - data are provided, but not checked yet
232.1647 + 2 - data are provided and have been checked */
232.1648 + SYMBOL *defval;
232.1649 + /* default value provided in the data section; can be NULL */
232.1650 + ARRAY *array;
232.1651 + /* array of members, which are assigned numbers or symbols */
232.1652 +};
232.1653 +
232.1654 +struct CONDITION
232.1655 +{ /* restricting condition list entry */
232.1656 + int rho;
232.1657 + /* flag that specifies the form of the condition:
232.1658 + O_LT - less than
232.1659 + O_LE - less than or equal to
232.1660 + O_EQ - equal to
232.1661 + O_GE - greater than or equal to
232.1662 + O_GT - greater than
232.1663 + O_NE - not equal to */
232.1664 + CODE *code;
232.1665 + /* pseudo-code for computing the reference value */
232.1666 + CONDITION *next;
232.1667 + /* the next entry for the same parameter */
232.1668 +};
232.1669 +
232.1670 +#define check_value_num _glp_mpl_check_value_num
232.1671 +void check_value_num
232.1672 +( MPL *mpl,
232.1673 + PARAMETER *par, /* not changed */
232.1674 + TUPLE *tuple, /* not changed */
232.1675 + double value
232.1676 +);
232.1677 +/* check numeric value assigned to parameter member */
232.1678 +
232.1679 +#define take_member_num _glp_mpl_take_member_num
232.1680 +double take_member_num
232.1681 +( MPL *mpl,
232.1682 + PARAMETER *par, /* not changed */
232.1683 + TUPLE *tuple /* not changed */
232.1684 +);
232.1685 +/* obtain numeric value assigned to parameter member */
232.1686 +
232.1687 +#define eval_member_num _glp_mpl_eval_member_num
232.1688 +double eval_member_num
232.1689 +( MPL *mpl,
232.1690 + PARAMETER *par, /* not changed */
232.1691 + TUPLE *tuple /* not changed */
232.1692 +);
232.1693 +/* evaluate numeric value assigned to parameter member */
232.1694 +
232.1695 +#define check_value_sym _glp_mpl_check_value_sym
232.1696 +void check_value_sym
232.1697 +( MPL *mpl,
232.1698 + PARAMETER *par, /* not changed */
232.1699 + TUPLE *tuple, /* not changed */
232.1700 + SYMBOL *value /* not changed */
232.1701 +);
232.1702 +/* check symbolic value assigned to parameter member */
232.1703 +
232.1704 +#define take_member_sym _glp_mpl_take_member_sym
232.1705 +SYMBOL *take_member_sym /* returns value, not reference */
232.1706 +( MPL *mpl,
232.1707 + PARAMETER *par, /* not changed */
232.1708 + TUPLE *tuple /* not changed */
232.1709 +);
232.1710 +/* obtain symbolic value assigned to parameter member */
232.1711 +
232.1712 +#define eval_member_sym _glp_mpl_eval_member_sym
232.1713 +SYMBOL *eval_member_sym /* returns value, not reference */
232.1714 +( MPL *mpl,
232.1715 + PARAMETER *par, /* not changed */
232.1716 + TUPLE *tuple /* not changed */
232.1717 +);
232.1718 +/* evaluate symbolic value assigned to parameter member */
232.1719 +
232.1720 +#define eval_whole_par _glp_mpl_eval_whole_par
232.1721 +void eval_whole_par(MPL *mpl, PARAMETER *par);
232.1722 +/* evaluate model parameter over entire domain */
232.1723 +
232.1724 +#define clean_parameter _glp_mpl_clean_parameter
232.1725 +void clean_parameter(MPL *mpl, PARAMETER *par);
232.1726 +/* clean model parameter */
232.1727 +
232.1728 +/**********************************************************************/
232.1729 +/* * * MODEL VARIABLES * * */
232.1730 +/**********************************************************************/
232.1731 +
232.1732 +struct VARIABLE
232.1733 +{ /* model variable */
232.1734 + char *name;
232.1735 + /* symbolic name; cannot be NULL */
232.1736 + char *alias;
232.1737 + /* alias; NULL means alias is not specified */
232.1738 + int dim; /* aka arity */
232.1739 + /* dimension (number of subscripts); dim = 0 means 0-dimensional
232.1740 + (unsubscripted) variable */
232.1741 + DOMAIN *domain;
232.1742 + /* subscript domain; NULL for 0-dimensional variable */
232.1743 + int type;
232.1744 + /* variable type:
232.1745 + A_NUMERIC - continuous
232.1746 + A_INTEGER - integer
232.1747 + A_BINARY - binary */
232.1748 + CODE *lbnd;
232.1749 + /* pseudo-code for computing lower bound; NULL means lower bound
232.1750 + is not specified */
232.1751 + CODE *ubnd;
232.1752 + /* pseudo-code for computing upper bound; NULL means upper bound
232.1753 + is not specified */
232.1754 + /* if both the pointers lbnd and ubnd refer to the same code, the
232.1755 + variable is fixed at the corresponding value */
232.1756 + ARRAY *array;
232.1757 + /* array of members, which are assigned elemental variables */
232.1758 +};
232.1759 +
232.1760 +#define take_member_var _glp_mpl_take_member_var
232.1761 +ELEMVAR *take_member_var /* returns reference */
232.1762 +( MPL *mpl,
232.1763 + VARIABLE *var, /* not changed */
232.1764 + TUPLE *tuple /* not changed */
232.1765 +);
232.1766 +/* obtain reference to elemental variable */
232.1767 +
232.1768 +#define eval_member_var _glp_mpl_eval_member_var
232.1769 +ELEMVAR *eval_member_var /* returns reference */
232.1770 +( MPL *mpl,
232.1771 + VARIABLE *var, /* not changed */
232.1772 + TUPLE *tuple /* not changed */
232.1773 +);
232.1774 +/* evaluate reference to elemental variable */
232.1775 +
232.1776 +#define eval_whole_var _glp_mpl_eval_whole_var
232.1777 +void eval_whole_var(MPL *mpl, VARIABLE *var);
232.1778 +/* evaluate model variable over entire domain */
232.1779 +
232.1780 +#define clean_variable _glp_mpl_clean_variable
232.1781 +void clean_variable(MPL *mpl, VARIABLE *var);
232.1782 +/* clean model variable */
232.1783 +
232.1784 +/**********************************************************************/
232.1785 +/* * * MODEL CONSTRAINTS AND OBJECTIVES * * */
232.1786 +/**********************************************************************/
232.1787 +
232.1788 +struct CONSTRAINT
232.1789 +{ /* model constraint or objective */
232.1790 + char *name;
232.1791 + /* symbolic name; cannot be NULL */
232.1792 + char *alias;
232.1793 + /* alias; NULL means alias is not specified */
232.1794 + int dim; /* aka arity */
232.1795 + /* dimension (number of subscripts); dim = 0 means 0-dimensional
232.1796 + (unsubscripted) constraint */
232.1797 + DOMAIN *domain;
232.1798 + /* subscript domain; NULL for 0-dimensional constraint */
232.1799 + int type;
232.1800 + /* constraint type:
232.1801 + A_CONSTRAINT - constraint
232.1802 + A_MINIMIZE - objective (minimization)
232.1803 + A_MAXIMIZE - objective (maximization) */
232.1804 + CODE *code;
232.1805 + /* pseudo-code for computing main linear form; cannot be NULL */
232.1806 + CODE *lbnd;
232.1807 + /* pseudo-code for computing lower bound; NULL means lower bound
232.1808 + is not specified */
232.1809 + CODE *ubnd;
232.1810 + /* pseudo-code for computing upper bound; NULL means upper bound
232.1811 + is not specified */
232.1812 + /* if both the pointers lbnd and ubnd refer to the same code, the
232.1813 + constraint has the form of equation */
232.1814 + ARRAY *array;
232.1815 + /* array of members, which are assigned elemental constraints */
232.1816 +};
232.1817 +
232.1818 +#define take_member_con _glp_mpl_take_member_con
232.1819 +ELEMCON *take_member_con /* returns reference */
232.1820 +( MPL *mpl,
232.1821 + CONSTRAINT *con, /* not changed */
232.1822 + TUPLE *tuple /* not changed */
232.1823 +);
232.1824 +/* obtain reference to elemental constraint */
232.1825 +
232.1826 +#define eval_member_con _glp_mpl_eval_member_con
232.1827 +ELEMCON *eval_member_con /* returns reference */
232.1828 +( MPL *mpl,
232.1829 + CONSTRAINT *con, /* not changed */
232.1830 + TUPLE *tuple /* not changed */
232.1831 +);
232.1832 +/* evaluate reference to elemental constraint */
232.1833 +
232.1834 +#define eval_whole_con _glp_mpl_eval_whole_con
232.1835 +void eval_whole_con(MPL *mpl, CONSTRAINT *con);
232.1836 +/* evaluate model constraint over entire domain */
232.1837 +
232.1838 +#define clean_constraint _glp_mpl_clean_constraint
232.1839 +void clean_constraint(MPL *mpl, CONSTRAINT *con);
232.1840 +/* clean model constraint */
232.1841 +
232.1842 +/**********************************************************************/
232.1843 +/* * * DATA TABLES * * */
232.1844 +/**********************************************************************/
232.1845 +
232.1846 +struct TABLE
232.1847 +{ /* data table */
232.1848 + char *name;
232.1849 + /* symbolic name; cannot be NULL */
232.1850 + char *alias;
232.1851 + /* alias; NULL means alias is not specified */
232.1852 + int type;
232.1853 + /* table type:
232.1854 + A_INPUT - input table
232.1855 + A_OUTPUT - output table */
232.1856 + TABARG *arg;
232.1857 + /* argument list; cannot be empty */
232.1858 + union
232.1859 + { struct
232.1860 + { SET *set;
232.1861 + /* input set; NULL means the set is not specified */
232.1862 + TABFLD *fld;
232.1863 + /* field list; cannot be empty */
232.1864 + TABIN *list;
232.1865 + /* input list; can be empty */
232.1866 + } in;
232.1867 + struct
232.1868 + { DOMAIN *domain;
232.1869 + /* subscript domain; cannot be NULL */
232.1870 + TABOUT *list;
232.1871 + /* output list; cannot be empty */
232.1872 + } out;
232.1873 + } u;
232.1874 +};
232.1875 +
232.1876 +struct TABARG
232.1877 +{ /* table argument list entry */
232.1878 + CODE *code;
232.1879 + /* pseudo-code for computing the argument */
232.1880 + TABARG *next;
232.1881 + /* next entry for the same table */
232.1882 +};
232.1883 +
232.1884 +struct TABFLD
232.1885 +{ /* table field list entry */
232.1886 + char *name;
232.1887 + /* field name; cannot be NULL */
232.1888 + TABFLD *next;
232.1889 + /* next entry for the same table */
232.1890 +};
232.1891 +
232.1892 +struct TABIN
232.1893 +{ /* table input list entry */
232.1894 + PARAMETER *par;
232.1895 + /* parameter to be read; cannot be NULL */
232.1896 + char *name;
232.1897 + /* column name; cannot be NULL */
232.1898 + TABIN *next;
232.1899 + /* next entry for the same table */
232.1900 +};
232.1901 +
232.1902 +struct TABOUT
232.1903 +{ /* table output list entry */
232.1904 + CODE *code;
232.1905 + /* pseudo-code for computing the value to be written */
232.1906 + char *name;
232.1907 + /* column name; cannot be NULL */
232.1908 + TABOUT *next;
232.1909 + /* next entry for the same table */
232.1910 +};
232.1911 +
232.1912 +struct TABDCA
232.1913 +{ /* table driver communication area */
232.1914 + int id;
232.1915 + /* driver identifier (set by mpl_tab_drv_open) */
232.1916 + void *link;
232.1917 + /* driver link pointer (set by mpl_tab_drv_open) */
232.1918 + int na;
232.1919 + /* number of arguments */
232.1920 + char **arg; /* char *arg[1+ns]; */
232.1921 + /* arg[k], 1 <= k <= ns, is pointer to k-th argument */
232.1922 + int nf;
232.1923 + /* number of fields */
232.1924 + char **name; /* char *name[1+nc]; */
232.1925 + /* name[k], 1 <= k <= nc, is name of k-th field */
232.1926 + int *type; /* int type[1+nc]; */
232.1927 + /* type[k], 1 <= k <= nc, is type of k-th field:
232.1928 + '?' - value not assigned
232.1929 + 'N' - number
232.1930 + 'S' - character string */
232.1931 + double *num; /* double num[1+nc]; */
232.1932 + /* num[k], 1 <= k <= nc, is numeric value of k-th field */
232.1933 + char **str;
232.1934 + /* str[k], 1 <= k <= nc, is string value of k-th field */
232.1935 +};
232.1936 +
232.1937 +#define mpl_tab_num_args _glp_mpl_tab_num_args
232.1938 +int mpl_tab_num_args(TABDCA *dca);
232.1939 +
232.1940 +#define mpl_tab_get_arg _glp_mpl_tab_get_arg
232.1941 +const char *mpl_tab_get_arg(TABDCA *dca, int k);
232.1942 +
232.1943 +#define mpl_tab_num_flds _glp_mpl_tab_num_flds
232.1944 +int mpl_tab_num_flds(TABDCA *dca);
232.1945 +
232.1946 +#define mpl_tab_get_name _glp_mpl_tab_get_name
232.1947 +const char *mpl_tab_get_name(TABDCA *dca, int k);
232.1948 +
232.1949 +#define mpl_tab_get_type _glp_mpl_tab_get_type
232.1950 +int mpl_tab_get_type(TABDCA *dca, int k);
232.1951 +
232.1952 +#define mpl_tab_get_num _glp_mpl_tab_get_num
232.1953 +double mpl_tab_get_num(TABDCA *dca, int k);
232.1954 +
232.1955 +#define mpl_tab_get_str _glp_mpl_tab_get_str
232.1956 +const char *mpl_tab_get_str(TABDCA *dca, int k);
232.1957 +
232.1958 +#define mpl_tab_set_num _glp_mpl_tab_set_num
232.1959 +void mpl_tab_set_num(TABDCA *dca, int k, double num);
232.1960 +
232.1961 +#define mpl_tab_set_str _glp_mpl_tab_set_str
232.1962 +void mpl_tab_set_str(TABDCA *dca, int k, const char *str);
232.1963 +
232.1964 +#define mpl_tab_drv_open _glp_mpl_tab_drv_open
232.1965 +void mpl_tab_drv_open(MPL *mpl, int mode);
232.1966 +
232.1967 +#define mpl_tab_drv_read _glp_mpl_tab_drv_read
232.1968 +int mpl_tab_drv_read(MPL *mpl);
232.1969 +
232.1970 +#define mpl_tab_drv_write _glp_mpl_tab_drv_write
232.1971 +void mpl_tab_drv_write(MPL *mpl);
232.1972 +
232.1973 +#define mpl_tab_drv_close _glp_mpl_tab_drv_close
232.1974 +void mpl_tab_drv_close(MPL *mpl);
232.1975 +
232.1976 +/**********************************************************************/
232.1977 +/* * * PSEUDO-CODE * * */
232.1978 +/**********************************************************************/
232.1979 +
232.1980 +union OPERANDS
232.1981 +{ /* operands that participate in pseudo-code operation (choice of
232.1982 + particular operands depends on the operation code) */
232.1983 + /*--------------------------------------------------------------*/
232.1984 + double num; /* O_NUMBER */
232.1985 + /* floaing-point number to be taken */
232.1986 + /*--------------------------------------------------------------*/
232.1987 + char *str; /* O_STRING */
232.1988 + /* character string to be taken */
232.1989 + /*--------------------------------------------------------------*/
232.1990 + struct /* O_INDEX */
232.1991 + { DOMAIN_SLOT *slot;
232.1992 + /* domain slot, which contains dummy index to be taken */
232.1993 + CODE *next;
232.1994 + /* the next pseudo-code with op = O_INDEX, which refers to the
232.1995 + same slot as this one; pointer to the beginning of this list
232.1996 + is stored in the corresponding domain slot */
232.1997 + } index;
232.1998 + /*--------------------------------------------------------------*/
232.1999 + struct /* O_MEMNUM, O_MEMSYM */
232.2000 + { PARAMETER *par;
232.2001 + /* model parameter, which contains member to be taken */
232.2002 + ARG_LIST *list;
232.2003 + /* list of subscripts; NULL for 0-dimensional parameter */
232.2004 + } par;
232.2005 + /*--------------------------------------------------------------*/
232.2006 + struct /* O_MEMSET */
232.2007 + { SET *set;
232.2008 + /* model set, which contains member to be taken */
232.2009 + ARG_LIST *list;
232.2010 + /* list of subscripts; NULL for 0-dimensional set */
232.2011 + } set;
232.2012 + /*--------------------------------------------------------------*/
232.2013 + struct /* O_MEMVAR */
232.2014 + { VARIABLE *var;
232.2015 + /* model variable, which contains member to be taken */
232.2016 + ARG_LIST *list;
232.2017 + /* list of subscripts; NULL for 0-dimensional variable */
232.2018 +#if 1 /* 15/V-2010 */
232.2019 + int suff;
232.2020 + /* suffix specified: */
232.2021 +#define DOT_NONE 0x00 /* none (means variable itself) */
232.2022 +#define DOT_LB 0x01 /* .lb (lower bound) */
232.2023 +#define DOT_UB 0x02 /* .ub (upper bound) */
232.2024 +#define DOT_STATUS 0x03 /* .status (status) */
232.2025 +#define DOT_VAL 0x04 /* .val (primal value) */
232.2026 +#define DOT_DUAL 0x05 /* .dual (dual value) */
232.2027 +#endif
232.2028 + } var;
232.2029 +#if 1 /* 15/V-2010 */
232.2030 + /*--------------------------------------------------------------*/
232.2031 + struct /* O_MEMCON */
232.2032 + { CONSTRAINT *con;
232.2033 + /* model constraint, which contains member to be taken */
232.2034 + ARG_LIST *list;
232.2035 + /* list of subscripys; NULL for 0-dimensional constraint */
232.2036 + int suff;
232.2037 + /* suffix specified (see O_MEMVAR above) */
232.2038 + } con;
232.2039 +#endif
232.2040 + /*--------------------------------------------------------------*/
232.2041 + ARG_LIST *list; /* O_TUPLE, O_MAKE, n-ary operations */
232.2042 + /* list of operands */
232.2043 + /*--------------------------------------------------------------*/
232.2044 + DOMAIN_BLOCK *slice; /* O_SLICE */
232.2045 + /* domain block, which specifies slice (i.e. n-tuple that contains
232.2046 + free dummy indices); this operation is never evaluated */
232.2047 + /*--------------------------------------------------------------*/
232.2048 + struct /* unary, binary, ternary operations */
232.2049 + { CODE *x;
232.2050 + /* pseudo-code for computing first operand */
232.2051 + CODE *y;
232.2052 + /* pseudo-code for computing second operand */
232.2053 + CODE *z;
232.2054 + /* pseudo-code for computing third operand */
232.2055 + } arg;
232.2056 + /*--------------------------------------------------------------*/
232.2057 + struct /* iterated operations */
232.2058 + { DOMAIN *domain;
232.2059 + /* domain, over which the operation is performed */
232.2060 + CODE *x;
232.2061 + /* pseudo-code for computing "integrand" */
232.2062 + } loop;
232.2063 + /*--------------------------------------------------------------*/
232.2064 +};
232.2065 +
232.2066 +struct ARG_LIST
232.2067 +{ /* operands list entry */
232.2068 + CODE *x;
232.2069 + /* pseudo-code for computing operand */
232.2070 + ARG_LIST *next;
232.2071 + /* the next operand of the same operation */
232.2072 +};
232.2073 +
232.2074 +struct CODE
232.2075 +{ /* pseudo-code (internal form of expressions) */
232.2076 + int op;
232.2077 + /* operation code: */
232.2078 +#define O_NUMBER 301 /* take floating-point number */
232.2079 +#define O_STRING 302 /* take character string */
232.2080 +#define O_INDEX 303 /* take dummy index */
232.2081 +#define O_MEMNUM 304 /* take member of numeric parameter */
232.2082 +#define O_MEMSYM 305 /* take member of symbolic parameter */
232.2083 +#define O_MEMSET 306 /* take member of set */
232.2084 +#define O_MEMVAR 307 /* take member of variable */
232.2085 +#define O_MEMCON 308 /* take member of constraint */
232.2086 +#define O_TUPLE 309 /* make n-tuple */
232.2087 +#define O_MAKE 310 /* make elemental set of n-tuples */
232.2088 +#define O_SLICE 311 /* define domain block (dummy op) */
232.2089 + /* 0-ary operations --------------------*/
232.2090 +#define O_IRAND224 312 /* pseudo-random in [0, 2^24-1] */
232.2091 +#define O_UNIFORM01 313 /* pseudo-random in [0, 1) */
232.2092 +#define O_NORMAL01 314 /* gaussian random, mu = 0, sigma = 1 */
232.2093 +#define O_GMTIME 315 /* current calendar time (UTC) */
232.2094 + /* unary operations --------------------*/
232.2095 +#define O_CVTNUM 316 /* conversion to numeric */
232.2096 +#define O_CVTSYM 317 /* conversion to symbolic */
232.2097 +#define O_CVTLOG 318 /* conversion to logical */
232.2098 +#define O_CVTTUP 319 /* conversion to 1-tuple */
232.2099 +#define O_CVTLFM 320 /* conversion to linear form */
232.2100 +#define O_PLUS 321 /* unary plus */
232.2101 +#define O_MINUS 322 /* unary minus */
232.2102 +#define O_NOT 323 /* negation (logical "not") */
232.2103 +#define O_ABS 324 /* absolute value */
232.2104 +#define O_CEIL 325 /* round upward ("ceiling of x") */
232.2105 +#define O_FLOOR 326 /* round downward ("floor of x") */
232.2106 +#define O_EXP 327 /* base-e exponential */
232.2107 +#define O_LOG 328 /* natural logarithm */
232.2108 +#define O_LOG10 329 /* common (decimal) logarithm */
232.2109 +#define O_SQRT 330 /* square root */
232.2110 +#define O_SIN 331 /* trigonometric sine */
232.2111 +#define O_COS 332 /* trigonometric cosine */
232.2112 +#define O_ATAN 333 /* trigonometric arctangent */
232.2113 +#define O_ROUND 334 /* round to nearest integer */
232.2114 +#define O_TRUNC 335 /* truncate to nearest integer */
232.2115 +#define O_CARD 336 /* cardinality of set */
232.2116 +#define O_LENGTH 337 /* length of symbolic value */
232.2117 + /* binary operations -------------------*/
232.2118 +#define O_ADD 338 /* addition */
232.2119 +#define O_SUB 339 /* subtraction */
232.2120 +#define O_LESS 340 /* non-negative subtraction */
232.2121 +#define O_MUL 341 /* multiplication */
232.2122 +#define O_DIV 342 /* division */
232.2123 +#define O_IDIV 343 /* quotient of exact division */
232.2124 +#define O_MOD 344 /* remainder of exact division */
232.2125 +#define O_POWER 345 /* exponentiation (raise to power) */
232.2126 +#define O_ATAN2 346 /* trigonometric arctangent */
232.2127 +#define O_ROUND2 347 /* round to n fractional digits */
232.2128 +#define O_TRUNC2 348 /* truncate to n fractional digits */
232.2129 +#define O_UNIFORM 349 /* pseudo-random in [a, b) */
232.2130 +#define O_NORMAL 350 /* gaussian random, given mu and sigma */
232.2131 +#define O_CONCAT 351 /* concatenation */
232.2132 +#define O_LT 352 /* comparison on 'less than' */
232.2133 +#define O_LE 353 /* comparison on 'not greater than' */
232.2134 +#define O_EQ 354 /* comparison on 'equal to' */
232.2135 +#define O_GE 355 /* comparison on 'not less than' */
232.2136 +#define O_GT 356 /* comparison on 'greater than' */
232.2137 +#define O_NE 357 /* comparison on 'not equal to' */
232.2138 +#define O_AND 358 /* conjunction (logical "and") */
232.2139 +#define O_OR 359 /* disjunction (logical "or") */
232.2140 +#define O_UNION 360 /* union */
232.2141 +#define O_DIFF 361 /* difference */
232.2142 +#define O_SYMDIFF 362 /* symmetric difference */
232.2143 +#define O_INTER 363 /* intersection */
232.2144 +#define O_CROSS 364 /* cross (Cartesian) product */
232.2145 +#define O_IN 365 /* test on 'x in Y' */
232.2146 +#define O_NOTIN 366 /* test on 'x not in Y' */
232.2147 +#define O_WITHIN 367 /* test on 'X within Y' */
232.2148 +#define O_NOTWITHIN 368 /* test on 'X not within Y' */
232.2149 +#define O_SUBSTR 369 /* substring */
232.2150 +#define O_STR2TIME 370 /* convert string to time */
232.2151 +#define O_TIME2STR 371 /* convert time to string */
232.2152 + /* ternary operations ------------------*/
232.2153 +#define O_DOTS 372 /* build "arithmetic" set */
232.2154 +#define O_FORK 373 /* if-then-else */
232.2155 +#define O_SUBSTR3 374 /* substring */
232.2156 + /* n-ary operations --------------------*/
232.2157 +#define O_MIN 375 /* minimal value (n-ary) */
232.2158 +#define O_MAX 376 /* maximal value (n-ary) */
232.2159 + /* iterated operations -----------------*/
232.2160 +#define O_SUM 377 /* summation */
232.2161 +#define O_PROD 378 /* multiplication */
232.2162 +#define O_MINIMUM 379 /* minimum */
232.2163 +#define O_MAXIMUM 380 /* maximum */
232.2164 +#define O_FORALL 381 /* conjunction (A-quantification) */
232.2165 +#define O_EXISTS 382 /* disjunction (E-quantification) */
232.2166 +#define O_SETOF 383 /* compute elemental set */
232.2167 +#define O_BUILD 384 /* build elemental set */
232.2168 + OPERANDS arg;
232.2169 + /* operands that participate in the operation */
232.2170 + int type;
232.2171 + /* type of the resultant value:
232.2172 + A_NUMERIC - numeric
232.2173 + A_SYMBOLIC - symbolic
232.2174 + A_LOGICAL - logical
232.2175 + A_TUPLE - n-tuple
232.2176 + A_ELEMSET - elemental set
232.2177 + A_FORMULA - linear form */
232.2178 + int dim;
232.2179 + /* dimension of the resultant value; for A_TUPLE and A_ELEMSET it
232.2180 + is the dimension of the corresponding n-tuple(s) and cannot be
232.2181 + zero; for other resultant types it is always zero */
232.2182 + CODE *up;
232.2183 + /* parent pseudo-code, which refers to this pseudo-code as to its
232.2184 + operand; NULL means this pseudo-code has no parent and defines
232.2185 + an expression, which is not contained in another expression */
232.2186 + int vflag;
232.2187 + /* volatile flag; being set this flag means that this operation
232.2188 + has a side effect; for primary expressions this flag is set
232.2189 + directly by corresponding parsing routines (for example, if
232.2190 + primary expression is a reference to a function that generates
232.2191 + pseudo-random numbers); in other cases this flag is inherited
232.2192 + from operands */
232.2193 + int valid;
232.2194 + /* if this flag is set, the resultant value, which is a temporary
232.2195 + result of evaluating this operation on particular values of
232.2196 + operands, is valid; if this flag is clear, the resultant value
232.2197 + doesn't exist and therefore not valid; having been evaluated
232.2198 + the resultant value is stored here and not destroyed until the
232.2199 + dummy indices, which this value depends on, have been changed
232.2200 + (and if it doesn't depend on dummy indices at all, it is never
232.2201 + destroyed); thus, if the resultant value is valid, evaluating
232.2202 + routine can immediately take its copy not computing the result
232.2203 + from scratch; this mechanism is similar to moving invariants
232.2204 + out of loops and allows improving efficiency at the expense of
232.2205 + some extra memory needed to keep temporary results */
232.2206 + /* however, if the volatile flag (see above) is set, even if the
232.2207 + resultant value is valid, evaluating routine computes it as if
232.2208 + it were not valid, i.e. caching is not used in this case */
232.2209 + VALUE value;
232.2210 + /* resultant value in generic format */
232.2211 +};
232.2212 +
232.2213 +#define eval_numeric _glp_mpl_eval_numeric
232.2214 +double eval_numeric(MPL *mpl, CODE *code);
232.2215 +/* evaluate pseudo-code to determine numeric value */
232.2216 +
232.2217 +#define eval_symbolic _glp_mpl_eval_symbolic
232.2218 +SYMBOL *eval_symbolic(MPL *mpl, CODE *code);
232.2219 +/* evaluate pseudo-code to determine symbolic value */
232.2220 +
232.2221 +#define eval_logical _glp_mpl_eval_logical
232.2222 +int eval_logical(MPL *mpl, CODE *code);
232.2223 +/* evaluate pseudo-code to determine logical value */
232.2224 +
232.2225 +#define eval_tuple _glp_mpl_eval_tuple
232.2226 +TUPLE *eval_tuple(MPL *mpl, CODE *code);
232.2227 +/* evaluate pseudo-code to construct n-tuple */
232.2228 +
232.2229 +#define eval_elemset _glp_mpl_eval_elemset
232.2230 +ELEMSET *eval_elemset(MPL *mpl, CODE *code);
232.2231 +/* evaluate pseudo-code to construct elemental set */
232.2232 +
232.2233 +#define is_member _glp_mpl_is_member
232.2234 +int is_member(MPL *mpl, CODE *code, TUPLE *tuple);
232.2235 +/* check if n-tuple is in set specified by pseudo-code */
232.2236 +
232.2237 +#define eval_formula _glp_mpl_eval_formula
232.2238 +FORMULA *eval_formula(MPL *mpl, CODE *code);
232.2239 +/* evaluate pseudo-code to construct linear form */
232.2240 +
232.2241 +#define clean_code _glp_mpl_clean_code
232.2242 +void clean_code(MPL *mpl, CODE *code);
232.2243 +/* clean pseudo-code */
232.2244 +
232.2245 +/**********************************************************************/
232.2246 +/* * * MODEL STATEMENTS * * */
232.2247 +/**********************************************************************/
232.2248 +
232.2249 +struct CHECK
232.2250 +{ /* check statement */
232.2251 + DOMAIN *domain;
232.2252 + /* subscript domain; NULL means domain is not used */
232.2253 + CODE *code;
232.2254 + /* code for computing the predicate to be checked */
232.2255 +};
232.2256 +
232.2257 +struct DISPLAY
232.2258 +{ /* display statement */
232.2259 + DOMAIN *domain;
232.2260 + /* subscript domain; NULL means domain is not used */
232.2261 + DISPLAY1 *list;
232.2262 + /* display list; cannot be empty */
232.2263 +};
232.2264 +
232.2265 +struct DISPLAY1
232.2266 +{ /* display list entry */
232.2267 + int type;
232.2268 + /* item type:
232.2269 + A_INDEX - dummy index
232.2270 + A_SET - model set
232.2271 + A_PARAMETER - model parameter
232.2272 + A_VARIABLE - model variable
232.2273 + A_CONSTRAINT - model constraint/objective
232.2274 + A_EXPRESSION - expression */
232.2275 + union
232.2276 + { DOMAIN_SLOT *slot;
232.2277 + SET *set;
232.2278 + PARAMETER *par;
232.2279 + VARIABLE *var;
232.2280 + CONSTRAINT *con;
232.2281 + CODE *code;
232.2282 + } u;
232.2283 + /* item to be displayed */
232.2284 +#if 0 /* 15/V-2010 */
232.2285 + ARG_LIST *list;
232.2286 + /* optional subscript list (for constraint/objective only) */
232.2287 +#endif
232.2288 + DISPLAY1 *next;
232.2289 + /* the next entry for the same statement */
232.2290 +};
232.2291 +
232.2292 +struct PRINTF
232.2293 +{ /* printf statement */
232.2294 + DOMAIN *domain;
232.2295 + /* subscript domain; NULL means domain is not used */
232.2296 + CODE *fmt;
232.2297 + /* pseudo-code for computing format string */
232.2298 + PRINTF1 *list;
232.2299 + /* printf list; can be empty */
232.2300 + CODE *fname;
232.2301 + /* pseudo-code for computing filename to redirect the output;
232.2302 + NULL means the output goes to stdout */
232.2303 + int app;
232.2304 + /* if this flag is set, the output is appended */
232.2305 +};
232.2306 +
232.2307 +struct PRINTF1
232.2308 +{ /* printf list entry */
232.2309 + CODE *code;
232.2310 + /* pseudo-code for computing value to be printed */
232.2311 + PRINTF1 *next;
232.2312 + /* the next entry for the same statement */
232.2313 +};
232.2314 +
232.2315 +struct FOR
232.2316 +{ /* for statement */
232.2317 + DOMAIN *domain;
232.2318 + /* subscript domain; cannot be NULL */
232.2319 + STATEMENT *list;
232.2320 + /* linked list of model statements within this for statement in
232.2321 + the original order */
232.2322 +};
232.2323 +
232.2324 +struct STATEMENT
232.2325 +{ /* model statement */
232.2326 + int line;
232.2327 + /* number of source text line, where statement begins */
232.2328 + int type;
232.2329 + /* statement type:
232.2330 + A_SET - set statement
232.2331 + A_PARAMETER - parameter statement
232.2332 + A_VARIABLE - variable statement
232.2333 + A_CONSTRAINT - constraint/objective statement
232.2334 + A_TABLE - table statement
232.2335 + A_SOLVE - solve statement
232.2336 + A_CHECK - check statement
232.2337 + A_DISPLAY - display statement
232.2338 + A_PRINTF - printf statement
232.2339 + A_FOR - for statement */
232.2340 + union
232.2341 + { SET *set;
232.2342 + PARAMETER *par;
232.2343 + VARIABLE *var;
232.2344 + CONSTRAINT *con;
232.2345 + TABLE *tab;
232.2346 + void *slv; /* currently not used (set to NULL) */
232.2347 + CHECK *chk;
232.2348 + DISPLAY *dpy;
232.2349 + PRINTF *prt;
232.2350 + FOR *fur;
232.2351 + } u;
232.2352 + /* specific part of statement */
232.2353 + STATEMENT *next;
232.2354 + /* the next statement; in this list statements follow in the same
232.2355 + order as they appear in the model section */
232.2356 +};
232.2357 +
232.2358 +#define execute_table _glp_mpl_execute_table
232.2359 +void execute_table(MPL *mpl, TABLE *tab);
232.2360 +/* execute table statement */
232.2361 +
232.2362 +#define free_dca _glp_mpl_free_dca
232.2363 +void free_dca(MPL *mpl);
232.2364 +/* free table driver communucation area */
232.2365 +
232.2366 +#define clean_table _glp_mpl_clean_table
232.2367 +void clean_table(MPL *mpl, TABLE *tab);
232.2368 +/* clean table statement */
232.2369 +
232.2370 +#define execute_check _glp_mpl_execute_check
232.2371 +void execute_check(MPL *mpl, CHECK *chk);
232.2372 +/* execute check statement */
232.2373 +
232.2374 +#define clean_check _glp_mpl_clean_check
232.2375 +void clean_check(MPL *mpl, CHECK *chk);
232.2376 +/* clean check statement */
232.2377 +
232.2378 +#define execute_display _glp_mpl_execute_display
232.2379 +void execute_display(MPL *mpl, DISPLAY *dpy);
232.2380 +/* execute display statement */
232.2381 +
232.2382 +#define clean_display _glp_mpl_clean_display
232.2383 +void clean_display(MPL *mpl, DISPLAY *dpy);
232.2384 +/* clean display statement */
232.2385 +
232.2386 +#define execute_printf _glp_mpl_execute_printf
232.2387 +void execute_printf(MPL *mpl, PRINTF *prt);
232.2388 +/* execute printf statement */
232.2389 +
232.2390 +#define clean_printf _glp_mpl_clean_printf
232.2391 +void clean_printf(MPL *mpl, PRINTF *prt);
232.2392 +/* clean printf statement */
232.2393 +
232.2394 +#define execute_for _glp_mpl_execute_for
232.2395 +void execute_for(MPL *mpl, FOR *fur);
232.2396 +/* execute for statement */
232.2397 +
232.2398 +#define clean_for _glp_mpl_clean_for
232.2399 +void clean_for(MPL *mpl, FOR *fur);
232.2400 +/* clean for statement */
232.2401 +
232.2402 +#define execute_statement _glp_mpl_execute_statement
232.2403 +void execute_statement(MPL *mpl, STATEMENT *stmt);
232.2404 +/* execute specified model statement */
232.2405 +
232.2406 +#define clean_statement _glp_mpl_clean_statement
232.2407 +void clean_statement(MPL *mpl, STATEMENT *stmt);
232.2408 +/* clean specified model statement */
232.2409 +
232.2410 +/**********************************************************************/
232.2411 +/* * * GENERATING AND POSTSOLVING MODEL * * */
232.2412 +/**********************************************************************/
232.2413 +
232.2414 +#define alloc_content _glp_mpl_alloc_content
232.2415 +void alloc_content(MPL *mpl);
232.2416 +/* allocate content arrays for all model objects */
232.2417 +
232.2418 +#define generate_model _glp_mpl_generate_model
232.2419 +void generate_model(MPL *mpl);
232.2420 +/* generate model */
232.2421 +
232.2422 +#define build_problem _glp_mpl_build_problem
232.2423 +void build_problem(MPL *mpl);
232.2424 +/* build problem instance */
232.2425 +
232.2426 +#define postsolve_model _glp_mpl_postsolve_model
232.2427 +void postsolve_model(MPL *mpl);
232.2428 +/* postsolve model */
232.2429 +
232.2430 +#define clean_model _glp_mpl_clean_model
232.2431 +void clean_model(MPL *mpl);
232.2432 +/* clean model content */
232.2433 +
232.2434 +/**********************************************************************/
232.2435 +/* * * INPUT/OUTPUT * * */
232.2436 +/**********************************************************************/
232.2437 +
232.2438 +#define open_input _glp_mpl_open_input
232.2439 +void open_input(MPL *mpl, char *file);
232.2440 +/* open input text file */
232.2441 +
232.2442 +#define read_char _glp_mpl_read_char
232.2443 +int read_char(MPL *mpl);
232.2444 +/* read next character from input text file */
232.2445 +
232.2446 +#define close_input _glp_mpl_close_input
232.2447 +void close_input(MPL *mpl);
232.2448 +/* close input text file */
232.2449 +
232.2450 +#define open_output _glp_mpl_open_output
232.2451 +void open_output(MPL *mpl, char *file);
232.2452 +/* open output text file */
232.2453 +
232.2454 +#define write_char _glp_mpl_write_char
232.2455 +void write_char(MPL *mpl, int c);
232.2456 +/* write next character to output text file */
232.2457 +
232.2458 +#define write_text _glp_mpl_write_text
232.2459 +void write_text(MPL *mpl, char *fmt, ...);
232.2460 +/* format and write text to output text file */
232.2461 +
232.2462 +#define flush_output _glp_mpl_flush_output
232.2463 +void flush_output(MPL *mpl);
232.2464 +/* finalize writing data to output text file */
232.2465 +
232.2466 +/**********************************************************************/
232.2467 +/* * * SOLVER INTERFACE * * */
232.2468 +/**********************************************************************/
232.2469 +
232.2470 +#define MPL_FR 401 /* free (unbounded) */
232.2471 +#define MPL_LO 402 /* lower bound */
232.2472 +#define MPL_UP 403 /* upper bound */
232.2473 +#define MPL_DB 404 /* both lower and upper bounds */
232.2474 +#define MPL_FX 405 /* fixed */
232.2475 +
232.2476 +#define MPL_ST 411 /* constraint */
232.2477 +#define MPL_MIN 412 /* objective (minimization) */
232.2478 +#define MPL_MAX 413 /* objective (maximization) */
232.2479 +
232.2480 +#define MPL_NUM 421 /* continuous */
232.2481 +#define MPL_INT 422 /* integer */
232.2482 +#define MPL_BIN 423 /* binary */
232.2483 +
232.2484 +#define error _glp_mpl_error
232.2485 +void error(MPL *mpl, char *fmt, ...);
232.2486 +/* print error message and terminate model processing */
232.2487 +
232.2488 +#define warning _glp_mpl_warning
232.2489 +void warning(MPL *mpl, char *fmt, ...);
232.2490 +/* print warning message and continue model processing */
232.2491 +
232.2492 +#define mpl_initialize _glp_mpl_initialize
232.2493 +MPL *mpl_initialize(void);
232.2494 +/* create and initialize translator database */
232.2495 +
232.2496 +#define mpl_read_model _glp_mpl_read_model
232.2497 +int mpl_read_model(MPL *mpl, char *file, int skip_data);
232.2498 +/* read model section and optional data section */
232.2499 +
232.2500 +#define mpl_read_data _glp_mpl_read_data
232.2501 +int mpl_read_data(MPL *mpl, char *file);
232.2502 +/* read data section */
232.2503 +
232.2504 +#define mpl_generate _glp_mpl_generate
232.2505 +int mpl_generate(MPL *mpl, char *file);
232.2506 +/* generate model */
232.2507 +
232.2508 +#define mpl_get_prob_name _glp_mpl_get_prob_name
232.2509 +char *mpl_get_prob_name(MPL *mpl);
232.2510 +/* obtain problem (model) name */
232.2511 +
232.2512 +#define mpl_get_num_rows _glp_mpl_get_num_rows
232.2513 +int mpl_get_num_rows(MPL *mpl);
232.2514 +/* determine number of rows */
232.2515 +
232.2516 +#define mpl_get_num_cols _glp_mpl_get_num_cols
232.2517 +int mpl_get_num_cols(MPL *mpl);
232.2518 +/* determine number of columns */
232.2519 +
232.2520 +#define mpl_get_row_name _glp_mpl_get_row_name
232.2521 +char *mpl_get_row_name(MPL *mpl, int i);
232.2522 +/* obtain row name */
232.2523 +
232.2524 +#define mpl_get_row_kind _glp_mpl_get_row_kind
232.2525 +int mpl_get_row_kind(MPL *mpl, int i);
232.2526 +/* determine row kind */
232.2527 +
232.2528 +#define mpl_get_row_bnds _glp_mpl_get_row_bnds
232.2529 +int mpl_get_row_bnds(MPL *mpl, int i, double *lb, double *ub);
232.2530 +/* obtain row bounds */
232.2531 +
232.2532 +#define mpl_get_mat_row _glp_mpl_get_mat_row
232.2533 +int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[]);
232.2534 +/* obtain row of the constraint matrix */
232.2535 +
232.2536 +#define mpl_get_row_c0 _glp_mpl_get_row_c0
232.2537 +double mpl_get_row_c0(MPL *mpl, int i);
232.2538 +/* obtain constant term of free row */
232.2539 +
232.2540 +#define mpl_get_col_name _glp_mpl_get_col_name
232.2541 +char *mpl_get_col_name(MPL *mpl, int j);
232.2542 +/* obtain column name */
232.2543 +
232.2544 +#define mpl_get_col_kind _glp_mpl_get_col_kind
232.2545 +int mpl_get_col_kind(MPL *mpl, int j);
232.2546 +/* determine column kind */
232.2547 +
232.2548 +#define mpl_get_col_bnds _glp_mpl_get_col_bnds
232.2549 +int mpl_get_col_bnds(MPL *mpl, int j, double *lb, double *ub);
232.2550 +/* obtain column bounds */
232.2551 +
232.2552 +#define mpl_has_solve_stmt _glp_mpl_has_solve_stmt
232.2553 +int mpl_has_solve_stmt(MPL *mpl);
232.2554 +/* check if model has solve statement */
232.2555 +
232.2556 +#if 1 /* 15/V-2010 */
232.2557 +#define mpl_put_row_soln _glp_mpl_put_row_soln
232.2558 +void mpl_put_row_soln(MPL *mpl, int i, int stat, double prim,
232.2559 + double dual);
232.2560 +/* store row (constraint/objective) solution components */
232.2561 +#endif
232.2562 +
232.2563 +#if 1 /* 15/V-2010 */
232.2564 +#define mpl_put_col_soln _glp_mpl_put_col_soln
232.2565 +void mpl_put_col_soln(MPL *mpl, int j, int stat, double prim,
232.2566 + double dual);
232.2567 +/* store column (variable) solution components */
232.2568 +#endif
232.2569 +
232.2570 +#if 0 /* 15/V-2010 */
232.2571 +#define mpl_put_col_value _glp_mpl_put_col_value
232.2572 +void mpl_put_col_value(MPL *mpl, int j, double val);
232.2573 +/* store column value */
232.2574 +#endif
232.2575 +
232.2576 +#define mpl_postsolve _glp_mpl_postsolve
232.2577 +int mpl_postsolve(MPL *mpl);
232.2578 +/* postsolve model */
232.2579 +
232.2580 +#define mpl_terminate _glp_mpl_terminate
232.2581 +void mpl_terminate(MPL *mpl);
232.2582 +/* free all resources used by translator */
232.2583 +
232.2584 +#endif
232.2585 +
232.2586 +/* eof */
233.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
233.2 +++ b/src/glpmpl01.c Mon Dec 06 13:09:21 2010 +0100
233.3 @@ -0,0 +1,4715 @@
233.4 +/* glpmpl01.c */
233.5 +
233.6 +/***********************************************************************
233.7 +* This code is part of GLPK (GNU Linear Programming Kit).
233.8 +*
233.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
233.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
233.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
233.12 +* E-mail: <mao@gnu.org>.
233.13 +*
233.14 +* GLPK is free software: you can redistribute it and/or modify it
233.15 +* under the terms of the GNU General Public License as published by
233.16 +* the Free Software Foundation, either version 3 of the License, or
233.17 +* (at your option) any later version.
233.18 +*
233.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
233.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
233.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
233.22 +* License for more details.
233.23 +*
233.24 +* You should have received a copy of the GNU General Public License
233.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
233.26 +***********************************************************************/
233.27 +
233.28 +#define _GLPSTD_STDIO
233.29 +#include "glpmpl.h"
233.30 +#define dmp_get_atomv dmp_get_atom
233.31 +
233.32 +/**********************************************************************/
233.33 +/* * * PROCESSING MODEL SECTION * * */
233.34 +/**********************************************************************/
233.35 +
233.36 +/*----------------------------------------------------------------------
233.37 +-- enter_context - enter current token into context queue.
233.38 +--
233.39 +-- This routine enters the current token into the context queue. */
233.40 +
233.41 +void enter_context(MPL *mpl)
233.42 +{ char *image, *s;
233.43 + if (mpl->token == T_EOF)
233.44 + image = "_|_";
233.45 + else if (mpl->token == T_STRING)
233.46 + image = "'...'";
233.47 + else
233.48 + image = mpl->image;
233.49 + xassert(0 <= mpl->c_ptr && mpl->c_ptr < CONTEXT_SIZE);
233.50 + mpl->context[mpl->c_ptr++] = ' ';
233.51 + if (mpl->c_ptr == CONTEXT_SIZE) mpl->c_ptr = 0;
233.52 + for (s = image; *s != '\0'; s++)
233.53 + { mpl->context[mpl->c_ptr++] = *s;
233.54 + if (mpl->c_ptr == CONTEXT_SIZE) mpl->c_ptr = 0;
233.55 + }
233.56 + return;
233.57 +}
233.58 +
233.59 +/*----------------------------------------------------------------------
233.60 +-- print_context - print current content of context queue.
233.61 +--
233.62 +-- This routine prints current content of the context queue. */
233.63 +
233.64 +void print_context(MPL *mpl)
233.65 +{ int c;
233.66 + while (mpl->c_ptr > 0)
233.67 + { mpl->c_ptr--;
233.68 + c = mpl->context[0];
233.69 + memmove(mpl->context, mpl->context+1, CONTEXT_SIZE-1);
233.70 + mpl->context[CONTEXT_SIZE-1] = (char)c;
233.71 + }
233.72 + xprintf("Context: %s%.*s\n", mpl->context[0] == ' ' ? "" : "...",
233.73 + CONTEXT_SIZE, mpl->context);
233.74 + return;
233.75 +}
233.76 +
233.77 +/*----------------------------------------------------------------------
233.78 +-- get_char - scan next character from input text file.
233.79 +--
233.80 +-- This routine scans a next ASCII character from the input text file.
233.81 +-- In case of end-of-file, the character is assigned EOF. */
233.82 +
233.83 +void get_char(MPL *mpl)
233.84 +{ int c;
233.85 + if (mpl->c == EOF) goto done;
233.86 + if (mpl->c == '\n') mpl->line++;
233.87 + c = read_char(mpl);
233.88 + if (c == EOF)
233.89 + { if (mpl->c == '\n')
233.90 + mpl->line--;
233.91 + else
233.92 + warning(mpl, "final NL missing before end of file");
233.93 + }
233.94 + else if (c == '\n')
233.95 + ;
233.96 + else if (isspace(c))
233.97 + c = ' ';
233.98 + else if (iscntrl(c))
233.99 + { enter_context(mpl);
233.100 + error(mpl, "control character 0x%02X not allowed", c);
233.101 + }
233.102 + mpl->c = c;
233.103 +done: return;
233.104 +}
233.105 +
233.106 +/*----------------------------------------------------------------------
233.107 +-- append_char - append character to current token.
233.108 +--
233.109 +-- This routine appends the current character to the current token and
233.110 +-- then scans a next character. */
233.111 +
233.112 +void append_char(MPL *mpl)
233.113 +{ xassert(0 <= mpl->imlen && mpl->imlen <= MAX_LENGTH);
233.114 + if (mpl->imlen == MAX_LENGTH)
233.115 + { switch (mpl->token)
233.116 + { case T_NAME:
233.117 + enter_context(mpl);
233.118 + error(mpl, "symbolic name %s... too long", mpl->image);
233.119 + case T_SYMBOL:
233.120 + enter_context(mpl);
233.121 + error(mpl, "symbol %s... too long", mpl->image);
233.122 + case T_NUMBER:
233.123 + enter_context(mpl);
233.124 + error(mpl, "numeric literal %s... too long", mpl->image);
233.125 + case T_STRING:
233.126 + enter_context(mpl);
233.127 + error(mpl, "string literal too long");
233.128 + default:
233.129 + xassert(mpl != mpl);
233.130 + }
233.131 + }
233.132 + mpl->image[mpl->imlen++] = (char)mpl->c;
233.133 + mpl->image[mpl->imlen] = '\0';
233.134 + get_char(mpl);
233.135 + return;
233.136 +}
233.137 +
233.138 +/*----------------------------------------------------------------------
233.139 +-- get_token - scan next token from input text file.
233.140 +--
233.141 +-- This routine scans a next token from the input text file using the
233.142 +-- standard finite automation technique. */
233.143 +
233.144 +void get_token(MPL *mpl)
233.145 +{ /* save the current token */
233.146 + mpl->b_token = mpl->token;
233.147 + mpl->b_imlen = mpl->imlen;
233.148 + strcpy(mpl->b_image, mpl->image);
233.149 + mpl->b_value = mpl->value;
233.150 + /* if the next token is already scanned, make it current */
233.151 + if (mpl->f_scan)
233.152 + { mpl->f_scan = 0;
233.153 + mpl->token = mpl->f_token;
233.154 + mpl->imlen = mpl->f_imlen;
233.155 + strcpy(mpl->image, mpl->f_image);
233.156 + mpl->value = mpl->f_value;
233.157 + goto done;
233.158 + }
233.159 +loop: /* nothing has been scanned so far */
233.160 + mpl->token = 0;
233.161 + mpl->imlen = 0;
233.162 + mpl->image[0] = '\0';
233.163 + mpl->value = 0.0;
233.164 + /* skip any uninteresting characters */
233.165 + while (mpl->c == ' ' || mpl->c == '\n') get_char(mpl);
233.166 + /* recognize and construct the token */
233.167 + if (mpl->c == EOF)
233.168 + { /* end-of-file reached */
233.169 + mpl->token = T_EOF;
233.170 + }
233.171 + else if (mpl->c == '#')
233.172 + { /* comment; skip anything until end-of-line */
233.173 + while (mpl->c != '\n' && mpl->c != EOF) get_char(mpl);
233.174 + goto loop;
233.175 + }
233.176 + else if (!mpl->flag_d && (isalpha(mpl->c) || mpl->c == '_'))
233.177 + { /* symbolic name or reserved keyword */
233.178 + mpl->token = T_NAME;
233.179 + while (isalnum(mpl->c) || mpl->c == '_') append_char(mpl);
233.180 + if (strcmp(mpl->image, "and") == 0)
233.181 + mpl->token = T_AND;
233.182 + else if (strcmp(mpl->image, "by") == 0)
233.183 + mpl->token = T_BY;
233.184 + else if (strcmp(mpl->image, "cross") == 0)
233.185 + mpl->token = T_CROSS;
233.186 + else if (strcmp(mpl->image, "diff") == 0)
233.187 + mpl->token = T_DIFF;
233.188 + else if (strcmp(mpl->image, "div") == 0)
233.189 + mpl->token = T_DIV;
233.190 + else if (strcmp(mpl->image, "else") == 0)
233.191 + mpl->token = T_ELSE;
233.192 + else if (strcmp(mpl->image, "if") == 0)
233.193 + mpl->token = T_IF;
233.194 + else if (strcmp(mpl->image, "in") == 0)
233.195 + mpl->token = T_IN;
233.196 +#if 1 /* 21/VII-2006 */
233.197 + else if (strcmp(mpl->image, "Infinity") == 0)
233.198 + mpl->token = T_INFINITY;
233.199 +#endif
233.200 + else if (strcmp(mpl->image, "inter") == 0)
233.201 + mpl->token = T_INTER;
233.202 + else if (strcmp(mpl->image, "less") == 0)
233.203 + mpl->token = T_LESS;
233.204 + else if (strcmp(mpl->image, "mod") == 0)
233.205 + mpl->token = T_MOD;
233.206 + else if (strcmp(mpl->image, "not") == 0)
233.207 + mpl->token = T_NOT;
233.208 + else if (strcmp(mpl->image, "or") == 0)
233.209 + mpl->token = T_OR;
233.210 + else if (strcmp(mpl->image, "s") == 0 && mpl->c == '.')
233.211 + { mpl->token = T_SPTP;
233.212 + append_char(mpl);
233.213 + if (mpl->c != 't')
233.214 +sptp: { enter_context(mpl);
233.215 + error(mpl, "keyword s.t. incomplete");
233.216 + }
233.217 + append_char(mpl);
233.218 + if (mpl->c != '.') goto sptp;
233.219 + append_char(mpl);
233.220 + }
233.221 + else if (strcmp(mpl->image, "symdiff") == 0)
233.222 + mpl->token = T_SYMDIFF;
233.223 + else if (strcmp(mpl->image, "then") == 0)
233.224 + mpl->token = T_THEN;
233.225 + else if (strcmp(mpl->image, "union") == 0)
233.226 + mpl->token = T_UNION;
233.227 + else if (strcmp(mpl->image, "within") == 0)
233.228 + mpl->token = T_WITHIN;
233.229 + }
233.230 + else if (!mpl->flag_d && isdigit(mpl->c))
233.231 + { /* numeric literal */
233.232 + mpl->token = T_NUMBER;
233.233 + /* scan integer part */
233.234 + while (isdigit(mpl->c)) append_char(mpl);
233.235 + /* scan optional fractional part */
233.236 + if (mpl->c == '.')
233.237 + { append_char(mpl);
233.238 + if (mpl->c == '.')
233.239 + { /* hmm, it is not the fractional part, it is dots that
233.240 + follow the integer part */
233.241 + mpl->imlen--;
233.242 + mpl->image[mpl->imlen] = '\0';
233.243 + mpl->f_dots = 1;
233.244 + goto conv;
233.245 + }
233.246 +frac: while (isdigit(mpl->c)) append_char(mpl);
233.247 + }
233.248 + /* scan optional decimal exponent */
233.249 + if (mpl->c == 'e' || mpl->c == 'E')
233.250 + { append_char(mpl);
233.251 + if (mpl->c == '+' || mpl->c == '-') append_char(mpl);
233.252 + if (!isdigit(mpl->c))
233.253 + { enter_context(mpl);
233.254 + error(mpl, "numeric literal %s incomplete", mpl->image);
233.255 + }
233.256 + while (isdigit(mpl->c)) append_char(mpl);
233.257 + }
233.258 + /* there must be no letter following the numeric literal */
233.259 + if (isalpha(mpl->c) || mpl->c == '_')
233.260 + { enter_context(mpl);
233.261 + error(mpl, "symbol %s%c... should be enclosed in quotes",
233.262 + mpl->image, mpl->c);
233.263 + }
233.264 +conv: /* convert numeric literal to floating-point */
233.265 + if (str2num(mpl->image, &mpl->value))
233.266 +err: { enter_context(mpl);
233.267 + error(mpl, "cannot convert numeric literal %s to floating-p"
233.268 + "oint number", mpl->image);
233.269 + }
233.270 + }
233.271 + else if (mpl->c == '\'' || mpl->c == '"')
233.272 + { /* character string */
233.273 + int quote = mpl->c;
233.274 + mpl->token = T_STRING;
233.275 + get_char(mpl);
233.276 + for (;;)
233.277 + { if (mpl->c == '\n' || mpl->c == EOF)
233.278 + { enter_context(mpl);
233.279 + error(mpl, "unexpected end of line; string literal incom"
233.280 + "plete");
233.281 + }
233.282 + if (mpl->c == quote)
233.283 + { get_char(mpl);
233.284 + if (mpl->c != quote) break;
233.285 + }
233.286 + append_char(mpl);
233.287 + }
233.288 + }
233.289 + else if (!mpl->flag_d && mpl->c == '+')
233.290 + mpl->token = T_PLUS, append_char(mpl);
233.291 + else if (!mpl->flag_d && mpl->c == '-')
233.292 + mpl->token = T_MINUS, append_char(mpl);
233.293 + else if (mpl->c == '*')
233.294 + { mpl->token = T_ASTERISK, append_char(mpl);
233.295 + if (mpl->c == '*')
233.296 + mpl->token = T_POWER, append_char(mpl);
233.297 + }
233.298 + else if (mpl->c == '/')
233.299 + { mpl->token = T_SLASH, append_char(mpl);
233.300 + if (mpl->c == '*')
233.301 + { /* comment sequence */
233.302 + get_char(mpl);
233.303 + for (;;)
233.304 + { if (mpl->c == EOF)
233.305 + { /* do not call enter_context at this point */
233.306 + error(mpl, "unexpected end of file; comment sequence "
233.307 + "incomplete");
233.308 + }
233.309 + else if (mpl->c == '*')
233.310 + { get_char(mpl);
233.311 + if (mpl->c == '/') break;
233.312 + }
233.313 + else
233.314 + get_char(mpl);
233.315 + }
233.316 + get_char(mpl);
233.317 + goto loop;
233.318 + }
233.319 + }
233.320 + else if (mpl->c == '^')
233.321 + mpl->token = T_POWER, append_char(mpl);
233.322 + else if (mpl->c == '<')
233.323 + { mpl->token = T_LT, append_char(mpl);
233.324 + if (mpl->c == '=')
233.325 + mpl->token = T_LE, append_char(mpl);
233.326 + else if (mpl->c == '>')
233.327 + mpl->token = T_NE, append_char(mpl);
233.328 +#if 1 /* 11/II-2008 */
233.329 + else if (mpl->c == '-')
233.330 + mpl->token = T_INPUT, append_char(mpl);
233.331 +#endif
233.332 + }
233.333 + else if (mpl->c == '=')
233.334 + { mpl->token = T_EQ, append_char(mpl);
233.335 + if (mpl->c == '=') append_char(mpl);
233.336 + }
233.337 + else if (mpl->c == '>')
233.338 + { mpl->token = T_GT, append_char(mpl);
233.339 + if (mpl->c == '=')
233.340 + mpl->token = T_GE, append_char(mpl);
233.341 +#if 1 /* 14/VII-2006 */
233.342 + else if (mpl->c == '>')
233.343 + mpl->token = T_APPEND, append_char(mpl);
233.344 +#endif
233.345 + }
233.346 + else if (mpl->c == '!')
233.347 + { mpl->token = T_NOT, append_char(mpl);
233.348 + if (mpl->c == '=')
233.349 + mpl->token = T_NE, append_char(mpl);
233.350 + }
233.351 + else if (mpl->c == '&')
233.352 + { mpl->token = T_CONCAT, append_char(mpl);
233.353 + if (mpl->c == '&')
233.354 + mpl->token = T_AND, append_char(mpl);
233.355 + }
233.356 + else if (mpl->c == '|')
233.357 + { mpl->token = T_BAR, append_char(mpl);
233.358 + if (mpl->c == '|')
233.359 + mpl->token = T_OR, append_char(mpl);
233.360 + }
233.361 + else if (!mpl->flag_d && mpl->c == '.')
233.362 + { mpl->token = T_POINT, append_char(mpl);
233.363 + if (mpl->f_dots)
233.364 + { /* dots; the first dot was read on the previous call to the
233.365 + scanner, so the current character is the second dot */
233.366 + mpl->token = T_DOTS;
233.367 + mpl->imlen = 2;
233.368 + strcpy(mpl->image, "..");
233.369 + mpl->f_dots = 0;
233.370 + }
233.371 + else if (mpl->c == '.')
233.372 + mpl->token = T_DOTS, append_char(mpl);
233.373 + else if (isdigit(mpl->c))
233.374 + { /* numeric literal that begins with the decimal point */
233.375 + mpl->token = T_NUMBER, append_char(mpl);
233.376 + goto frac;
233.377 + }
233.378 + }
233.379 + else if (mpl->c == ',')
233.380 + mpl->token = T_COMMA, append_char(mpl);
233.381 + else if (mpl->c == ':')
233.382 + { mpl->token = T_COLON, append_char(mpl);
233.383 + if (mpl->c == '=')
233.384 + mpl->token = T_ASSIGN, append_char(mpl);
233.385 + }
233.386 + else if (mpl->c == ';')
233.387 + mpl->token = T_SEMICOLON, append_char(mpl);
233.388 + else if (mpl->c == '(')
233.389 + mpl->token = T_LEFT, append_char(mpl);
233.390 + else if (mpl->c == ')')
233.391 + mpl->token = T_RIGHT, append_char(mpl);
233.392 + else if (mpl->c == '[')
233.393 + mpl->token = T_LBRACKET, append_char(mpl);
233.394 + else if (mpl->c == ']')
233.395 + mpl->token = T_RBRACKET, append_char(mpl);
233.396 + else if (mpl->c == '{')
233.397 + mpl->token = T_LBRACE, append_char(mpl);
233.398 + else if (mpl->c == '}')
233.399 + mpl->token = T_RBRACE, append_char(mpl);
233.400 +#if 1 /* 11/II-2008 */
233.401 + else if (mpl->c == '~')
233.402 + mpl->token = T_TILDE, append_char(mpl);
233.403 +#endif
233.404 + else if (isalnum(mpl->c) || strchr("+-._", mpl->c) != NULL)
233.405 + { /* symbol */
233.406 + xassert(mpl->flag_d);
233.407 + mpl->token = T_SYMBOL;
233.408 + while (isalnum(mpl->c) || strchr("+-._", mpl->c) != NULL)
233.409 + append_char(mpl);
233.410 + switch (str2num(mpl->image, &mpl->value))
233.411 + { case 0:
233.412 + mpl->token = T_NUMBER;
233.413 + break;
233.414 + case 1:
233.415 + goto err;
233.416 + case 2:
233.417 + break;
233.418 + default:
233.419 + xassert(mpl != mpl);
233.420 + }
233.421 + }
233.422 + else
233.423 + { enter_context(mpl);
233.424 + error(mpl, "character %c not allowed", mpl->c);
233.425 + }
233.426 + /* enter the current token into the context queue */
233.427 + enter_context(mpl);
233.428 + /* reset the flag, which may be set by indexing_expression() and
233.429 + is used by expression_list() */
233.430 + mpl->flag_x = 0;
233.431 +done: return;
233.432 +}
233.433 +
233.434 +/*----------------------------------------------------------------------
233.435 +-- unget_token - return current token back to input stream.
233.436 +--
233.437 +-- This routine returns the current token back to the input stream, so
233.438 +-- the previously scanned token becomes the current one. */
233.439 +
233.440 +void unget_token(MPL *mpl)
233.441 +{ /* save the current token, which becomes the next one */
233.442 + xassert(!mpl->f_scan);
233.443 + mpl->f_scan = 1;
233.444 + mpl->f_token = mpl->token;
233.445 + mpl->f_imlen = mpl->imlen;
233.446 + strcpy(mpl->f_image, mpl->image);
233.447 + mpl->f_value = mpl->value;
233.448 + /* restore the previous token, which becomes the current one */
233.449 + mpl->token = mpl->b_token;
233.450 + mpl->imlen = mpl->b_imlen;
233.451 + strcpy(mpl->image, mpl->b_image);
233.452 + mpl->value = mpl->b_value;
233.453 + return;
233.454 +}
233.455 +
233.456 +/*----------------------------------------------------------------------
233.457 +-- is_keyword - check if current token is given non-reserved keyword.
233.458 +--
233.459 +-- If the current token is given (non-reserved) keyword, this routine
233.460 +-- returns non-zero. Otherwise zero is returned. */
233.461 +
233.462 +int is_keyword(MPL *mpl, char *keyword)
233.463 +{ return
233.464 + mpl->token == T_NAME && strcmp(mpl->image, keyword) == 0;
233.465 +}
233.466 +
233.467 +/*----------------------------------------------------------------------
233.468 +-- is_reserved - check if current token is reserved keyword.
233.469 +--
233.470 +-- If the current token is a reserved keyword, this routine returns
233.471 +-- non-zero. Otherwise zero is returned. */
233.472 +
233.473 +int is_reserved(MPL *mpl)
233.474 +{ return
233.475 + mpl->token == T_AND && mpl->image[0] == 'a' ||
233.476 + mpl->token == T_BY ||
233.477 + mpl->token == T_CROSS ||
233.478 + mpl->token == T_DIFF ||
233.479 + mpl->token == T_DIV ||
233.480 + mpl->token == T_ELSE ||
233.481 + mpl->token == T_IF ||
233.482 + mpl->token == T_IN ||
233.483 + mpl->token == T_INTER ||
233.484 + mpl->token == T_LESS ||
233.485 + mpl->token == T_MOD ||
233.486 + mpl->token == T_NOT && mpl->image[0] == 'n' ||
233.487 + mpl->token == T_OR && mpl->image[0] == 'o' ||
233.488 + mpl->token == T_SYMDIFF ||
233.489 + mpl->token == T_THEN ||
233.490 + mpl->token == T_UNION ||
233.491 + mpl->token == T_WITHIN;
233.492 +}
233.493 +
233.494 +/*----------------------------------------------------------------------
233.495 +-- make_code - generate pseudo-code (basic routine).
233.496 +--
233.497 +-- This routine generates specified pseudo-code. It is assumed that all
233.498 +-- other translator routines use this basic routine. */
233.499 +
233.500 +CODE *make_code(MPL *mpl, int op, OPERANDS *arg, int type, int dim)
233.501 +{ CODE *code;
233.502 + DOMAIN *domain;
233.503 + DOMAIN_BLOCK *block;
233.504 + ARG_LIST *e;
233.505 + /* generate pseudo-code */
233.506 + code = alloc(CODE);
233.507 + code->op = op;
233.508 + code->vflag = 0; /* is inherited from operand(s) */
233.509 + /* copy operands and also make them referring to the pseudo-code
233.510 + being generated, because the latter becomes the parent for all
233.511 + its operands */
233.512 + memset(&code->arg, '?', sizeof(OPERANDS));
233.513 + switch (op)
233.514 + { case O_NUMBER:
233.515 + code->arg.num = arg->num;
233.516 + break;
233.517 + case O_STRING:
233.518 + code->arg.str = arg->str;
233.519 + break;
233.520 + case O_INDEX:
233.521 + code->arg.index.slot = arg->index.slot;
233.522 + code->arg.index.next = arg->index.next;
233.523 + break;
233.524 + case O_MEMNUM:
233.525 + case O_MEMSYM:
233.526 + for (e = arg->par.list; e != NULL; e = e->next)
233.527 + { xassert(e->x != NULL);
233.528 + xassert(e->x->up == NULL);
233.529 + e->x->up = code;
233.530 + code->vflag |= e->x->vflag;
233.531 + }
233.532 + code->arg.par.par = arg->par.par;
233.533 + code->arg.par.list = arg->par.list;
233.534 + break;
233.535 + case O_MEMSET:
233.536 + for (e = arg->set.list; e != NULL; e = e->next)
233.537 + { xassert(e->x != NULL);
233.538 + xassert(e->x->up == NULL);
233.539 + e->x->up = code;
233.540 + code->vflag |= e->x->vflag;
233.541 + }
233.542 + code->arg.set.set = arg->set.set;
233.543 + code->arg.set.list = arg->set.list;
233.544 + break;
233.545 + case O_MEMVAR:
233.546 + for (e = arg->var.list; e != NULL; e = e->next)
233.547 + { xassert(e->x != NULL);
233.548 + xassert(e->x->up == NULL);
233.549 + e->x->up = code;
233.550 + code->vflag |= e->x->vflag;
233.551 + }
233.552 + code->arg.var.var = arg->var.var;
233.553 + code->arg.var.list = arg->var.list;
233.554 +#if 1 /* 15/V-2010 */
233.555 + code->arg.var.suff = arg->var.suff;
233.556 +#endif
233.557 + break;
233.558 +#if 1 /* 15/V-2010 */
233.559 + case O_MEMCON:
233.560 + for (e = arg->con.list; e != NULL; e = e->next)
233.561 + { xassert(e->x != NULL);
233.562 + xassert(e->x->up == NULL);
233.563 + e->x->up = code;
233.564 + code->vflag |= e->x->vflag;
233.565 + }
233.566 + code->arg.con.con = arg->con.con;
233.567 + code->arg.con.list = arg->con.list;
233.568 + code->arg.con.suff = arg->con.suff;
233.569 + break;
233.570 +#endif
233.571 + case O_TUPLE:
233.572 + case O_MAKE:
233.573 + for (e = arg->list; e != NULL; e = e->next)
233.574 + { xassert(e->x != NULL);
233.575 + xassert(e->x->up == NULL);
233.576 + e->x->up = code;
233.577 + code->vflag |= e->x->vflag;
233.578 + }
233.579 + code->arg.list = arg->list;
233.580 + break;
233.581 + case O_SLICE:
233.582 + xassert(arg->slice != NULL);
233.583 + code->arg.slice = arg->slice;
233.584 + break;
233.585 + case O_IRAND224:
233.586 + case O_UNIFORM01:
233.587 + case O_NORMAL01:
233.588 + case O_GMTIME:
233.589 + code->vflag = 1;
233.590 + break;
233.591 + case O_CVTNUM:
233.592 + case O_CVTSYM:
233.593 + case O_CVTLOG:
233.594 + case O_CVTTUP:
233.595 + case O_CVTLFM:
233.596 + case O_PLUS:
233.597 + case O_MINUS:
233.598 + case O_NOT:
233.599 + case O_ABS:
233.600 + case O_CEIL:
233.601 + case O_FLOOR:
233.602 + case O_EXP:
233.603 + case O_LOG:
233.604 + case O_LOG10:
233.605 + case O_SQRT:
233.606 + case O_SIN:
233.607 + case O_COS:
233.608 + case O_ATAN:
233.609 + case O_ROUND:
233.610 + case O_TRUNC:
233.611 + case O_CARD:
233.612 + case O_LENGTH:
233.613 + /* unary operation */
233.614 + xassert(arg->arg.x != NULL);
233.615 + xassert(arg->arg.x->up == NULL);
233.616 + arg->arg.x->up = code;
233.617 + code->vflag |= arg->arg.x->vflag;
233.618 + code->arg.arg.x = arg->arg.x;
233.619 + break;
233.620 + case O_ADD:
233.621 + case O_SUB:
233.622 + case O_LESS:
233.623 + case O_MUL:
233.624 + case O_DIV:
233.625 + case O_IDIV:
233.626 + case O_MOD:
233.627 + case O_POWER:
233.628 + case O_ATAN2:
233.629 + case O_ROUND2:
233.630 + case O_TRUNC2:
233.631 + case O_UNIFORM:
233.632 + if (op == O_UNIFORM) code->vflag = 1;
233.633 + case O_NORMAL:
233.634 + if (op == O_NORMAL) code->vflag = 1;
233.635 + case O_CONCAT:
233.636 + case O_LT:
233.637 + case O_LE:
233.638 + case O_EQ:
233.639 + case O_GE:
233.640 + case O_GT:
233.641 + case O_NE:
233.642 + case O_AND:
233.643 + case O_OR:
233.644 + case O_UNION:
233.645 + case O_DIFF:
233.646 + case O_SYMDIFF:
233.647 + case O_INTER:
233.648 + case O_CROSS:
233.649 + case O_IN:
233.650 + case O_NOTIN:
233.651 + case O_WITHIN:
233.652 + case O_NOTWITHIN:
233.653 + case O_SUBSTR:
233.654 + case O_STR2TIME:
233.655 + case O_TIME2STR:
233.656 + /* binary operation */
233.657 + xassert(arg->arg.x != NULL);
233.658 + xassert(arg->arg.x->up == NULL);
233.659 + arg->arg.x->up = code;
233.660 + code->vflag |= arg->arg.x->vflag;
233.661 + xassert(arg->arg.y != NULL);
233.662 + xassert(arg->arg.y->up == NULL);
233.663 + arg->arg.y->up = code;
233.664 + code->vflag |= arg->arg.y->vflag;
233.665 + code->arg.arg.x = arg->arg.x;
233.666 + code->arg.arg.y = arg->arg.y;
233.667 + break;
233.668 + case O_DOTS:
233.669 + case O_FORK:
233.670 + case O_SUBSTR3:
233.671 + /* ternary operation */
233.672 + xassert(arg->arg.x != NULL);
233.673 + xassert(arg->arg.x->up == NULL);
233.674 + arg->arg.x->up = code;
233.675 + code->vflag |= arg->arg.x->vflag;
233.676 + xassert(arg->arg.y != NULL);
233.677 + xassert(arg->arg.y->up == NULL);
233.678 + arg->arg.y->up = code;
233.679 + code->vflag |= arg->arg.y->vflag;
233.680 + if (arg->arg.z != NULL)
233.681 + { xassert(arg->arg.z->up == NULL);
233.682 + arg->arg.z->up = code;
233.683 + code->vflag |= arg->arg.z->vflag;
233.684 + }
233.685 + code->arg.arg.x = arg->arg.x;
233.686 + code->arg.arg.y = arg->arg.y;
233.687 + code->arg.arg.z = arg->arg.z;
233.688 + break;
233.689 + case O_MIN:
233.690 + case O_MAX:
233.691 + /* n-ary operation */
233.692 + for (e = arg->list; e != NULL; e = e->next)
233.693 + { xassert(e->x != NULL);
233.694 + xassert(e->x->up == NULL);
233.695 + e->x->up = code;
233.696 + code->vflag |= e->x->vflag;
233.697 + }
233.698 + code->arg.list = arg->list;
233.699 + break;
233.700 + case O_SUM:
233.701 + case O_PROD:
233.702 + case O_MINIMUM:
233.703 + case O_MAXIMUM:
233.704 + case O_FORALL:
233.705 + case O_EXISTS:
233.706 + case O_SETOF:
233.707 + case O_BUILD:
233.708 + /* iterated operation */
233.709 + domain = arg->loop.domain;
233.710 + xassert(domain != NULL);
233.711 + if (domain->code != NULL)
233.712 + { xassert(domain->code->up == NULL);
233.713 + domain->code->up = code;
233.714 + code->vflag |= domain->code->vflag;
233.715 + }
233.716 + for (block = domain->list; block != NULL; block =
233.717 + block->next)
233.718 + { xassert(block->code != NULL);
233.719 + xassert(block->code->up == NULL);
233.720 + block->code->up = code;
233.721 + code->vflag |= block->code->vflag;
233.722 + }
233.723 + if (arg->loop.x != NULL)
233.724 + { xassert(arg->loop.x->up == NULL);
233.725 + arg->loop.x->up = code;
233.726 + code->vflag |= arg->loop.x->vflag;
233.727 + }
233.728 + code->arg.loop.domain = arg->loop.domain;
233.729 + code->arg.loop.x = arg->loop.x;
233.730 + break;
233.731 + default:
233.732 + xassert(op != op);
233.733 + }
233.734 + /* set other attributes of the pseudo-code */
233.735 + code->type = type;
233.736 + code->dim = dim;
233.737 + code->up = NULL;
233.738 + code->valid = 0;
233.739 + memset(&code->value, '?', sizeof(VALUE));
233.740 + return code;
233.741 +}
233.742 +
233.743 +/*----------------------------------------------------------------------
233.744 +-- make_unary - generate pseudo-code for unary operation.
233.745 +--
233.746 +-- This routine generates pseudo-code for unary operation. */
233.747 +
233.748 +CODE *make_unary(MPL *mpl, int op, CODE *x, int type, int dim)
233.749 +{ CODE *code;
233.750 + OPERANDS arg;
233.751 + xassert(x != NULL);
233.752 + arg.arg.x = x;
233.753 + code = make_code(mpl, op, &arg, type, dim);
233.754 + return code;
233.755 +}
233.756 +
233.757 +/*----------------------------------------------------------------------
233.758 +-- make_binary - generate pseudo-code for binary operation.
233.759 +--
233.760 +-- This routine generates pseudo-code for binary operation. */
233.761 +
233.762 +CODE *make_binary(MPL *mpl, int op, CODE *x, CODE *y, int type,
233.763 + int dim)
233.764 +{ CODE *code;
233.765 + OPERANDS arg;
233.766 + xassert(x != NULL);
233.767 + xassert(y != NULL);
233.768 + arg.arg.x = x;
233.769 + arg.arg.y = y;
233.770 + code = make_code(mpl, op, &arg, type, dim);
233.771 + return code;
233.772 +}
233.773 +
233.774 +/*----------------------------------------------------------------------
233.775 +-- make_ternary - generate pseudo-code for ternary operation.
233.776 +--
233.777 +-- This routine generates pseudo-code for ternary operation. */
233.778 +
233.779 +CODE *make_ternary(MPL *mpl, int op, CODE *x, CODE *y, CODE *z,
233.780 + int type, int dim)
233.781 +{ CODE *code;
233.782 + OPERANDS arg;
233.783 + xassert(x != NULL);
233.784 + xassert(y != NULL);
233.785 + /* third operand can be NULL */
233.786 + arg.arg.x = x;
233.787 + arg.arg.y = y;
233.788 + arg.arg.z = z;
233.789 + code = make_code(mpl, op, &arg, type, dim);
233.790 + return code;
233.791 +}
233.792 +
233.793 +/*----------------------------------------------------------------------
233.794 +-- numeric_literal - parse reference to numeric literal.
233.795 +--
233.796 +-- This routine parses primary expression using the syntax:
233.797 +--
233.798 +-- <primary expression> ::= <numeric literal> */
233.799 +
233.800 +CODE *numeric_literal(MPL *mpl)
233.801 +{ CODE *code;
233.802 + OPERANDS arg;
233.803 + xassert(mpl->token == T_NUMBER);
233.804 + arg.num = mpl->value;
233.805 + code = make_code(mpl, O_NUMBER, &arg, A_NUMERIC, 0);
233.806 + get_token(mpl /* <numeric literal> */);
233.807 + return code;
233.808 +}
233.809 +
233.810 +/*----------------------------------------------------------------------
233.811 +-- string_literal - parse reference to string literal.
233.812 +--
233.813 +-- This routine parses primary expression using the syntax:
233.814 +--
233.815 +-- <primary expression> ::= <string literal> */
233.816 +
233.817 +CODE *string_literal(MPL *mpl)
233.818 +{ CODE *code;
233.819 + OPERANDS arg;
233.820 + xassert(mpl->token == T_STRING);
233.821 + arg.str = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.822 + strcpy(arg.str, mpl->image);
233.823 + code = make_code(mpl, O_STRING, &arg, A_SYMBOLIC, 0);
233.824 + get_token(mpl /* <string literal> */);
233.825 + return code;
233.826 +}
233.827 +
233.828 +/*----------------------------------------------------------------------
233.829 +-- create_arg_list - create empty operands list.
233.830 +--
233.831 +-- This routine creates operands list, which is initially empty. */
233.832 +
233.833 +ARG_LIST *create_arg_list(MPL *mpl)
233.834 +{ ARG_LIST *list;
233.835 + xassert(mpl == mpl);
233.836 + list = NULL;
233.837 + return list;
233.838 +}
233.839 +
233.840 +/*----------------------------------------------------------------------
233.841 +-- expand_arg_list - append operand to operands list.
233.842 +--
233.843 +-- This routine appends new operand to specified operands list. */
233.844 +
233.845 +ARG_LIST *expand_arg_list(MPL *mpl, ARG_LIST *list, CODE *x)
233.846 +{ ARG_LIST *tail, *temp;
233.847 + xassert(x != NULL);
233.848 + /* create new operands list entry */
233.849 + tail = alloc(ARG_LIST);
233.850 + tail->x = x;
233.851 + tail->next = NULL;
233.852 + /* and append it to the operands list */
233.853 + if (list == NULL)
233.854 + list = tail;
233.855 + else
233.856 + { for (temp = list; temp->next != NULL; temp = temp->next);
233.857 + temp->next = tail;
233.858 + }
233.859 + return list;
233.860 +}
233.861 +
233.862 +/*----------------------------------------------------------------------
233.863 +-- arg_list_len - determine length of operands list.
233.864 +--
233.865 +-- This routine returns the number of operands in operands list. */
233.866 +
233.867 +int arg_list_len(MPL *mpl, ARG_LIST *list)
233.868 +{ ARG_LIST *temp;
233.869 + int len;
233.870 + xassert(mpl == mpl);
233.871 + len = 0;
233.872 + for (temp = list; temp != NULL; temp = temp->next) len++;
233.873 + return len;
233.874 +}
233.875 +
233.876 +/*----------------------------------------------------------------------
233.877 +-- subscript_list - parse subscript list.
233.878 +--
233.879 +-- This routine parses subscript list using the syntax:
233.880 +--
233.881 +-- <subscript list> ::= <subscript>
233.882 +-- <subscript list> ::= <subscript list> , <subscript>
233.883 +-- <subscript> ::= <expression 5> */
233.884 +
233.885 +ARG_LIST *subscript_list(MPL *mpl)
233.886 +{ ARG_LIST *list;
233.887 + CODE *x;
233.888 + list = create_arg_list(mpl);
233.889 + for (;;)
233.890 + { /* parse subscript expression */
233.891 + x = expression_5(mpl);
233.892 + /* convert it to symbolic type, if necessary */
233.893 + if (x->type == A_NUMERIC)
233.894 + x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
233.895 + /* check that now the expression is of symbolic type */
233.896 + if (x->type != A_SYMBOLIC)
233.897 + error(mpl, "subscript expression has invalid type");
233.898 + xassert(x->dim == 0);
233.899 + /* and append it to the subscript list */
233.900 + list = expand_arg_list(mpl, list, x);
233.901 + /* check a token that follows the subscript expression */
233.902 + if (mpl->token == T_COMMA)
233.903 + get_token(mpl /* , */);
233.904 + else if (mpl->token == T_RBRACKET)
233.905 + break;
233.906 + else
233.907 + error(mpl, "syntax error in subscript list");
233.908 + }
233.909 + return list;
233.910 +}
233.911 +
233.912 +#if 1 /* 15/V-2010 */
233.913 +/*----------------------------------------------------------------------
233.914 +-- object_reference - parse reference to named object.
233.915 +--
233.916 +-- This routine parses primary expression using the syntax:
233.917 +--
233.918 +-- <primary expression> ::= <dummy index>
233.919 +-- <primary expression> ::= <set name>
233.920 +-- <primary expression> ::= <set name> [ <subscript list> ]
233.921 +-- <primary expression> ::= <parameter name>
233.922 +-- <primary expression> ::= <parameter name> [ <subscript list> ]
233.923 +-- <primary expression> ::= <variable name> <suffix>
233.924 +-- <primary expression> ::= <variable name> [ <subscript list> ]
233.925 +-- <suffix>
233.926 +-- <primary expression> ::= <constraint name> <suffix>
233.927 +-- <primary expression> ::= <constraint name> [ <subscript list> ]
233.928 +-- <suffix>
233.929 +-- <dummy index> ::= <symbolic name>
233.930 +-- <set name> ::= <symbolic name>
233.931 +-- <parameter name> ::= <symbolic name>
233.932 +-- <variable name> ::= <symbolic name>
233.933 +-- <constraint name> ::= <symbolic name>
233.934 +-- <suffix> ::= <empty> | .lb | .ub | .status | .val | .dual */
233.935 +
233.936 +CODE *object_reference(MPL *mpl)
233.937 +{ AVLNODE *node;
233.938 + DOMAIN_SLOT *slot;
233.939 + SET *set;
233.940 + PARAMETER *par;
233.941 + VARIABLE *var;
233.942 + CONSTRAINT *con;
233.943 + ARG_LIST *list;
233.944 + OPERANDS arg;
233.945 + CODE *code;
233.946 + char *name;
233.947 + int dim, suff;
233.948 + /* find the object in the symbolic name table */
233.949 + xassert(mpl->token == T_NAME);
233.950 + node = avl_find_node(mpl->tree, mpl->image);
233.951 + if (node == NULL)
233.952 + error(mpl, "%s not defined", mpl->image);
233.953 + /* check the object type and obtain its dimension */
233.954 + switch (avl_get_node_type(node))
233.955 + { case A_INDEX:
233.956 + /* dummy index */
233.957 + slot = (DOMAIN_SLOT *)avl_get_node_link(node);
233.958 + name = slot->name;
233.959 + dim = 0;
233.960 + break;
233.961 + case A_SET:
233.962 + /* model set */
233.963 + set = (SET *)avl_get_node_link(node);
233.964 + name = set->name;
233.965 + dim = set->dim;
233.966 + /* if a set object is referenced in its own declaration and
233.967 + the dimen attribute is not specified yet, use dimen 1 by
233.968 + default */
233.969 + if (set->dimen == 0) set->dimen = 1;
233.970 + break;
233.971 + case A_PARAMETER:
233.972 + /* model parameter */
233.973 + par = (PARAMETER *)avl_get_node_link(node);
233.974 + name = par->name;
233.975 + dim = par->dim;
233.976 + break;
233.977 + case A_VARIABLE:
233.978 + /* model variable */
233.979 + var = (VARIABLE *)avl_get_node_link(node);
233.980 + name = var->name;
233.981 + dim = var->dim;
233.982 + break;
233.983 + case A_CONSTRAINT:
233.984 + /* model constraint or objective */
233.985 + con = (CONSTRAINT *)avl_get_node_link(node);
233.986 + name = con->name;
233.987 + dim = con->dim;
233.988 + break;
233.989 + default:
233.990 + xassert(node != node);
233.991 + }
233.992 + get_token(mpl /* <symbolic name> */);
233.993 + /* parse optional subscript list */
233.994 + if (mpl->token == T_LBRACKET)
233.995 + { /* subscript list is specified */
233.996 + if (dim == 0)
233.997 + error(mpl, "%s cannot be subscripted", name);
233.998 + get_token(mpl /* [ */);
233.999 + list = subscript_list(mpl);
233.1000 + if (dim != arg_list_len(mpl, list))
233.1001 + error(mpl, "%s must have %d subscript%s rather than %d",
233.1002 + name, dim, dim == 1 ? "" : "s", arg_list_len(mpl, list));
233.1003 + xassert(mpl->token == T_RBRACKET);
233.1004 + get_token(mpl /* ] */);
233.1005 + }
233.1006 + else
233.1007 + { /* subscript list is not specified */
233.1008 + if (dim != 0)
233.1009 + error(mpl, "%s must be subscripted", name);
233.1010 + list = create_arg_list(mpl);
233.1011 + }
233.1012 + /* parse optional suffix */
233.1013 + if (!mpl->flag_s && avl_get_node_type(node) == A_VARIABLE)
233.1014 + suff = DOT_NONE;
233.1015 + else
233.1016 + suff = DOT_VAL;
233.1017 + if (mpl->token == T_POINT)
233.1018 + { get_token(mpl /* . */);
233.1019 + if (mpl->token != T_NAME)
233.1020 + error(mpl, "invalid use of period");
233.1021 + if (!(avl_get_node_type(node) == A_VARIABLE ||
233.1022 + avl_get_node_type(node) == A_CONSTRAINT))
233.1023 + error(mpl, "%s cannot have a suffix", name);
233.1024 + if (strcmp(mpl->image, "lb") == 0)
233.1025 + suff = DOT_LB;
233.1026 + else if (strcmp(mpl->image, "ub") == 0)
233.1027 + suff = DOT_UB;
233.1028 + else if (strcmp(mpl->image, "status") == 0)
233.1029 + suff = DOT_STATUS;
233.1030 + else if (strcmp(mpl->image, "val") == 0)
233.1031 + suff = DOT_VAL;
233.1032 + else if (strcmp(mpl->image, "dual") == 0)
233.1033 + suff = DOT_DUAL;
233.1034 + else
233.1035 + error(mpl, "suffix .%s invalid", mpl->image);
233.1036 + get_token(mpl /* suffix */);
233.1037 + }
233.1038 + /* generate pseudo-code to take value of the object */
233.1039 + switch (avl_get_node_type(node))
233.1040 + { case A_INDEX:
233.1041 + arg.index.slot = slot;
233.1042 + arg.index.next = slot->list;
233.1043 + code = make_code(mpl, O_INDEX, &arg, A_SYMBOLIC, 0);
233.1044 + slot->list = code;
233.1045 + break;
233.1046 + case A_SET:
233.1047 + arg.set.set = set;
233.1048 + arg.set.list = list;
233.1049 + code = make_code(mpl, O_MEMSET, &arg, A_ELEMSET,
233.1050 + set->dimen);
233.1051 + break;
233.1052 + case A_PARAMETER:
233.1053 + arg.par.par = par;
233.1054 + arg.par.list = list;
233.1055 + if (par->type == A_SYMBOLIC)
233.1056 + code = make_code(mpl, O_MEMSYM, &arg, A_SYMBOLIC, 0);
233.1057 + else
233.1058 + code = make_code(mpl, O_MEMNUM, &arg, A_NUMERIC, 0);
233.1059 + break;
233.1060 + case A_VARIABLE:
233.1061 + if (!mpl->flag_s && (suff == DOT_STATUS || suff == DOT_VAL
233.1062 + || suff == DOT_DUAL))
233.1063 + error(mpl, "invalid reference to status, primal value, o"
233.1064 + "r dual value of variable %s above solve statement",
233.1065 + var->name);
233.1066 + arg.var.var = var;
233.1067 + arg.var.list = list;
233.1068 + arg.var.suff = suff;
233.1069 + code = make_code(mpl, O_MEMVAR, &arg, suff == DOT_NONE ?
233.1070 + A_FORMULA : A_NUMERIC, 0);
233.1071 + break;
233.1072 + case A_CONSTRAINT:
233.1073 + if (!mpl->flag_s && (suff == DOT_STATUS || suff == DOT_VAL
233.1074 + || suff == DOT_DUAL))
233.1075 + error(mpl, "invalid reference to status, primal value, o"
233.1076 + "r dual value of %s %s above solve statement",
233.1077 + con->type == A_CONSTRAINT ? "constraint" : "objective"
233.1078 + , con->name);
233.1079 + arg.con.con = con;
233.1080 + arg.con.list = list;
233.1081 + arg.con.suff = suff;
233.1082 + code = make_code(mpl, O_MEMCON, &arg, A_NUMERIC, 0);
233.1083 + break;
233.1084 + default:
233.1085 + xassert(node != node);
233.1086 + }
233.1087 + return code;
233.1088 +}
233.1089 +#endif
233.1090 +
233.1091 +/*----------------------------------------------------------------------
233.1092 +-- numeric_argument - parse argument passed to built-in function.
233.1093 +--
233.1094 +-- This routine parses an argument passed to numeric built-in function
233.1095 +-- using the syntax:
233.1096 +--
233.1097 +-- <arg> ::= <expression 5> */
233.1098 +
233.1099 +CODE *numeric_argument(MPL *mpl, char *func)
233.1100 +{ CODE *x;
233.1101 + x = expression_5(mpl);
233.1102 + /* convert the argument to numeric type, if necessary */
233.1103 + if (x->type == A_SYMBOLIC)
233.1104 + x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.1105 + /* check that now the argument is of numeric type */
233.1106 + if (x->type != A_NUMERIC)
233.1107 + error(mpl, "argument for %s has invalid type", func);
233.1108 + xassert(x->dim == 0);
233.1109 + return x;
233.1110 +}
233.1111 +
233.1112 +#if 1 /* 15/VII-2006 */
233.1113 +CODE *symbolic_argument(MPL *mpl, char *func)
233.1114 +{ CODE *x;
233.1115 + x = expression_5(mpl);
233.1116 + /* convert the argument to symbolic type, if necessary */
233.1117 + if (x->type == A_NUMERIC)
233.1118 + x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
233.1119 + /* check that now the argument is of symbolic type */
233.1120 + if (x->type != A_SYMBOLIC)
233.1121 + error(mpl, "argument for %s has invalid type", func);
233.1122 + xassert(x->dim == 0);
233.1123 + return x;
233.1124 +}
233.1125 +#endif
233.1126 +
233.1127 +#if 1 /* 15/VII-2006 */
233.1128 +CODE *elemset_argument(MPL *mpl, char *func)
233.1129 +{ CODE *x;
233.1130 + x = expression_9(mpl);
233.1131 + if (x->type != A_ELEMSET)
233.1132 + error(mpl, "argument for %s has invalid type", func);
233.1133 + xassert(x->dim > 0);
233.1134 + return x;
233.1135 +}
233.1136 +#endif
233.1137 +
233.1138 +/*----------------------------------------------------------------------
233.1139 +-- function_reference - parse reference to built-in function.
233.1140 +--
233.1141 +-- This routine parses primary expression using the syntax:
233.1142 +--
233.1143 +-- <primary expression> ::= abs ( <arg> )
233.1144 +-- <primary expression> ::= ceil ( <arg> )
233.1145 +-- <primary expression> ::= floor ( <arg> )
233.1146 +-- <primary expression> ::= exp ( <arg> )
233.1147 +-- <primary expression> ::= log ( <arg> )
233.1148 +-- <primary expression> ::= log10 ( <arg> )
233.1149 +-- <primary expression> ::= max ( <arg list> )
233.1150 +-- <primary expression> ::= min ( <arg list> )
233.1151 +-- <primary expression> ::= sqrt ( <arg> )
233.1152 +-- <primary expression> ::= sin ( <arg> )
233.1153 +-- <primary expression> ::= cos ( <arg> )
233.1154 +-- <primary expression> ::= atan ( <arg> )
233.1155 +-- <primary expression> ::= atan2 ( <arg> , <arg> )
233.1156 +-- <primary expression> ::= round ( <arg> )
233.1157 +-- <primary expression> ::= round ( <arg> , <arg> )
233.1158 +-- <primary expression> ::= trunc ( <arg> )
233.1159 +-- <primary expression> ::= trunc ( <arg> , <arg> )
233.1160 +-- <primary expression> ::= Irand224 ( )
233.1161 +-- <primary expression> ::= Uniform01 ( )
233.1162 +-- <primary expression> ::= Uniform ( <arg> , <arg> )
233.1163 +-- <primary expression> ::= Normal01 ( )
233.1164 +-- <primary expression> ::= Normal ( <arg> , <arg> )
233.1165 +-- <primary expression> ::= card ( <arg> )
233.1166 +-- <primary expression> ::= length ( <arg> )
233.1167 +-- <primary expression> ::= substr ( <arg> , <arg> )
233.1168 +-- <primary expression> ::= substr ( <arg> , <arg> , <arg> )
233.1169 +-- <primary expression> ::= str2time ( <arg> , <arg> )
233.1170 +-- <primary expression> ::= time2str ( <arg> , <arg> )
233.1171 +-- <primary expression> ::= gmtime ( )
233.1172 +-- <arg list> ::= <arg>
233.1173 +-- <arg list> ::= <arg list> , <arg> */
233.1174 +
233.1175 +CODE *function_reference(MPL *mpl)
233.1176 +{ CODE *code;
233.1177 + OPERANDS arg;
233.1178 + int op;
233.1179 + char func[15+1];
233.1180 + /* determine operation code */
233.1181 + xassert(mpl->token == T_NAME);
233.1182 + if (strcmp(mpl->image, "abs") == 0)
233.1183 + op = O_ABS;
233.1184 + else if (strcmp(mpl->image, "ceil") == 0)
233.1185 + op = O_CEIL;
233.1186 + else if (strcmp(mpl->image, "floor") == 0)
233.1187 + op = O_FLOOR;
233.1188 + else if (strcmp(mpl->image, "exp") == 0)
233.1189 + op = O_EXP;
233.1190 + else if (strcmp(mpl->image, "log") == 0)
233.1191 + op = O_LOG;
233.1192 + else if (strcmp(mpl->image, "log10") == 0)
233.1193 + op = O_LOG10;
233.1194 + else if (strcmp(mpl->image, "sqrt") == 0)
233.1195 + op = O_SQRT;
233.1196 + else if (strcmp(mpl->image, "sin") == 0)
233.1197 + op = O_SIN;
233.1198 + else if (strcmp(mpl->image, "cos") == 0)
233.1199 + op = O_COS;
233.1200 + else if (strcmp(mpl->image, "atan") == 0)
233.1201 + op = O_ATAN;
233.1202 + else if (strcmp(mpl->image, "min") == 0)
233.1203 + op = O_MIN;
233.1204 + else if (strcmp(mpl->image, "max") == 0)
233.1205 + op = O_MAX;
233.1206 + else if (strcmp(mpl->image, "round") == 0)
233.1207 + op = O_ROUND;
233.1208 + else if (strcmp(mpl->image, "trunc") == 0)
233.1209 + op = O_TRUNC;
233.1210 + else if (strcmp(mpl->image, "Irand224") == 0)
233.1211 + op = O_IRAND224;
233.1212 + else if (strcmp(mpl->image, "Uniform01") == 0)
233.1213 + op = O_UNIFORM01;
233.1214 + else if (strcmp(mpl->image, "Uniform") == 0)
233.1215 + op = O_UNIFORM;
233.1216 + else if (strcmp(mpl->image, "Normal01") == 0)
233.1217 + op = O_NORMAL01;
233.1218 + else if (strcmp(mpl->image, "Normal") == 0)
233.1219 + op = O_NORMAL;
233.1220 + else if (strcmp(mpl->image, "card") == 0)
233.1221 + op = O_CARD;
233.1222 + else if (strcmp(mpl->image, "length") == 0)
233.1223 + op = O_LENGTH;
233.1224 + else if (strcmp(mpl->image, "substr") == 0)
233.1225 + op = O_SUBSTR;
233.1226 + else if (strcmp(mpl->image, "str2time") == 0)
233.1227 + op = O_STR2TIME;
233.1228 + else if (strcmp(mpl->image, "time2str") == 0)
233.1229 + op = O_TIME2STR;
233.1230 + else if (strcmp(mpl->image, "gmtime") == 0)
233.1231 + op = O_GMTIME;
233.1232 + else
233.1233 + error(mpl, "function %s unknown", mpl->image);
233.1234 + /* save symbolic name of the function */
233.1235 + strcpy(func, mpl->image);
233.1236 + xassert(strlen(func) < sizeof(func));
233.1237 + get_token(mpl /* <symbolic name> */);
233.1238 + /* check the left parenthesis that follows the function name */
233.1239 + xassert(mpl->token == T_LEFT);
233.1240 + get_token(mpl /* ( */);
233.1241 + /* parse argument list */
233.1242 + if (op == O_MIN || op == O_MAX)
233.1243 + { /* min and max allow arbitrary number of arguments */
233.1244 + arg.list = create_arg_list(mpl);
233.1245 + /* parse argument list */
233.1246 + for (;;)
233.1247 + { /* parse argument and append it to the operands list */
233.1248 + arg.list = expand_arg_list(mpl, arg.list,
233.1249 + numeric_argument(mpl, func));
233.1250 + /* check a token that follows the argument */
233.1251 + if (mpl->token == T_COMMA)
233.1252 + get_token(mpl /* , */);
233.1253 + else if (mpl->token == T_RIGHT)
233.1254 + break;
233.1255 + else
233.1256 + error(mpl, "syntax error in argument list for %s", func);
233.1257 + }
233.1258 + }
233.1259 + else if (op == O_IRAND224 || op == O_UNIFORM01 || op ==
233.1260 + O_NORMAL01 || op == O_GMTIME)
233.1261 + { /* Irand224, Uniform01, Normal01, gmtime need no arguments */
233.1262 + if (mpl->token != T_RIGHT)
233.1263 + error(mpl, "%s needs no arguments", func);
233.1264 + }
233.1265 + else if (op == O_UNIFORM || op == O_NORMAL)
233.1266 + { /* Uniform and Normal need two arguments */
233.1267 + /* parse the first argument */
233.1268 + arg.arg.x = numeric_argument(mpl, func);
233.1269 + /* check a token that follows the first argument */
233.1270 + if (mpl->token == T_COMMA)
233.1271 + ;
233.1272 + else if (mpl->token == T_RIGHT)
233.1273 + error(mpl, "%s needs two arguments", func);
233.1274 + else
233.1275 + error(mpl, "syntax error in argument for %s", func);
233.1276 + get_token(mpl /* , */);
233.1277 + /* parse the second argument */
233.1278 + arg.arg.y = numeric_argument(mpl, func);
233.1279 + /* check a token that follows the second argument */
233.1280 + if (mpl->token == T_COMMA)
233.1281 + error(mpl, "%s needs two argument", func);
233.1282 + else if (mpl->token == T_RIGHT)
233.1283 + ;
233.1284 + else
233.1285 + error(mpl, "syntax error in argument for %s", func);
233.1286 + }
233.1287 + else if (op == O_ATAN || op == O_ROUND || op == O_TRUNC)
233.1288 + { /* atan, round, and trunc need one or two arguments */
233.1289 + /* parse the first argument */
233.1290 + arg.arg.x = numeric_argument(mpl, func);
233.1291 + /* parse the second argument, if specified */
233.1292 + if (mpl->token == T_COMMA)
233.1293 + { switch (op)
233.1294 + { case O_ATAN: op = O_ATAN2; break;
233.1295 + case O_ROUND: op = O_ROUND2; break;
233.1296 + case O_TRUNC: op = O_TRUNC2; break;
233.1297 + default: xassert(op != op);
233.1298 + }
233.1299 + get_token(mpl /* , */);
233.1300 + arg.arg.y = numeric_argument(mpl, func);
233.1301 + }
233.1302 + /* check a token that follows the last argument */
233.1303 + if (mpl->token == T_COMMA)
233.1304 + error(mpl, "%s needs one or two arguments", func);
233.1305 + else if (mpl->token == T_RIGHT)
233.1306 + ;
233.1307 + else
233.1308 + error(mpl, "syntax error in argument for %s", func);
233.1309 + }
233.1310 + else if (op == O_SUBSTR)
233.1311 + { /* substr needs two or three arguments */
233.1312 + /* parse the first argument */
233.1313 + arg.arg.x = symbolic_argument(mpl, func);
233.1314 + /* check a token that follows the first argument */
233.1315 + if (mpl->token == T_COMMA)
233.1316 + ;
233.1317 + else if (mpl->token == T_RIGHT)
233.1318 + error(mpl, "%s needs two or three arguments", func);
233.1319 + else
233.1320 + error(mpl, "syntax error in argument for %s", func);
233.1321 + get_token(mpl /* , */);
233.1322 + /* parse the second argument */
233.1323 + arg.arg.y = numeric_argument(mpl, func);
233.1324 + /* parse the third argument, if specified */
233.1325 + if (mpl->token == T_COMMA)
233.1326 + { op = O_SUBSTR3;
233.1327 + get_token(mpl /* , */);
233.1328 + arg.arg.z = numeric_argument(mpl, func);
233.1329 + }
233.1330 + /* check a token that follows the last argument */
233.1331 + if (mpl->token == T_COMMA)
233.1332 + error(mpl, "%s needs two or three arguments", func);
233.1333 + else if (mpl->token == T_RIGHT)
233.1334 + ;
233.1335 + else
233.1336 + error(mpl, "syntax error in argument for %s", func);
233.1337 + }
233.1338 + else if (op == O_STR2TIME)
233.1339 + { /* str2time needs two arguments, both symbolic */
233.1340 + /* parse the first argument */
233.1341 + arg.arg.x = symbolic_argument(mpl, func);
233.1342 + /* check a token that follows the first argument */
233.1343 + if (mpl->token == T_COMMA)
233.1344 + ;
233.1345 + else if (mpl->token == T_RIGHT)
233.1346 + error(mpl, "%s needs two arguments", func);
233.1347 + else
233.1348 + error(mpl, "syntax error in argument for %s", func);
233.1349 + get_token(mpl /* , */);
233.1350 + /* parse the second argument */
233.1351 + arg.arg.y = symbolic_argument(mpl, func);
233.1352 + /* check a token that follows the second argument */
233.1353 + if (mpl->token == T_COMMA)
233.1354 + error(mpl, "%s needs two argument", func);
233.1355 + else if (mpl->token == T_RIGHT)
233.1356 + ;
233.1357 + else
233.1358 + error(mpl, "syntax error in argument for %s", func);
233.1359 + }
233.1360 + else if (op == O_TIME2STR)
233.1361 + { /* time2str needs two arguments, numeric and symbolic */
233.1362 + /* parse the first argument */
233.1363 + arg.arg.x = numeric_argument(mpl, func);
233.1364 + /* check a token that follows the first argument */
233.1365 + if (mpl->token == T_COMMA)
233.1366 + ;
233.1367 + else if (mpl->token == T_RIGHT)
233.1368 + error(mpl, "%s needs two arguments", func);
233.1369 + else
233.1370 + error(mpl, "syntax error in argument for %s", func);
233.1371 + get_token(mpl /* , */);
233.1372 + /* parse the second argument */
233.1373 + arg.arg.y = symbolic_argument(mpl, func);
233.1374 + /* check a token that follows the second argument */
233.1375 + if (mpl->token == T_COMMA)
233.1376 + error(mpl, "%s needs two argument", func);
233.1377 + else if (mpl->token == T_RIGHT)
233.1378 + ;
233.1379 + else
233.1380 + error(mpl, "syntax error in argument for %s", func);
233.1381 + }
233.1382 + else
233.1383 + { /* other functions need one argument */
233.1384 + if (op == O_CARD)
233.1385 + arg.arg.x = elemset_argument(mpl, func);
233.1386 + else if (op == O_LENGTH)
233.1387 + arg.arg.x = symbolic_argument(mpl, func);
233.1388 + else
233.1389 + arg.arg.x = numeric_argument(mpl, func);
233.1390 + /* check a token that follows the argument */
233.1391 + if (mpl->token == T_COMMA)
233.1392 + error(mpl, "%s needs one argument", func);
233.1393 + else if (mpl->token == T_RIGHT)
233.1394 + ;
233.1395 + else
233.1396 + error(mpl, "syntax error in argument for %s", func);
233.1397 + }
233.1398 + /* make pseudo-code to call the built-in function */
233.1399 + if (op == O_SUBSTR || op == O_SUBSTR3 || op == O_TIME2STR)
233.1400 + code = make_code(mpl, op, &arg, A_SYMBOLIC, 0);
233.1401 + else
233.1402 + code = make_code(mpl, op, &arg, A_NUMERIC, 0);
233.1403 + /* the reference ends with the right parenthesis */
233.1404 + xassert(mpl->token == T_RIGHT);
233.1405 + get_token(mpl /* ) */);
233.1406 + return code;
233.1407 +}
233.1408 +
233.1409 +/*----------------------------------------------------------------------
233.1410 +-- create_domain - create empty domain.
233.1411 +--
233.1412 +-- This routine creates empty domain, which is initially empty, i.e.
233.1413 +-- has no domain blocks. */
233.1414 +
233.1415 +DOMAIN *create_domain(MPL *mpl)
233.1416 +{ DOMAIN *domain;
233.1417 + domain = alloc(DOMAIN);
233.1418 + domain->list = NULL;
233.1419 + domain->code = NULL;
233.1420 + return domain;
233.1421 +}
233.1422 +
233.1423 +/*----------------------------------------------------------------------
233.1424 +-- create_block - create empty domain block.
233.1425 +--
233.1426 +-- This routine creates empty domain block, which is initially empty,
233.1427 +-- i.e. has no domain slots. */
233.1428 +
233.1429 +DOMAIN_BLOCK *create_block(MPL *mpl)
233.1430 +{ DOMAIN_BLOCK *block;
233.1431 + block = alloc(DOMAIN_BLOCK);
233.1432 + block->list = NULL;
233.1433 + block->code = NULL;
233.1434 + block->backup = NULL;
233.1435 + block->next = NULL;
233.1436 + return block;
233.1437 +}
233.1438 +
233.1439 +/*----------------------------------------------------------------------
233.1440 +-- append_block - append domain block to specified domain.
233.1441 +--
233.1442 +-- This routine adds given domain block to the end of the block list of
233.1443 +-- specified domain. */
233.1444 +
233.1445 +void append_block(MPL *mpl, DOMAIN *domain, DOMAIN_BLOCK *block)
233.1446 +{ DOMAIN_BLOCK *temp;
233.1447 + xassert(mpl == mpl);
233.1448 + xassert(domain != NULL);
233.1449 + xassert(block != NULL);
233.1450 + xassert(block->next == NULL);
233.1451 + if (domain->list == NULL)
233.1452 + domain->list = block;
233.1453 + else
233.1454 + { for (temp = domain->list; temp->next != NULL; temp =
233.1455 + temp->next);
233.1456 + temp->next = block;
233.1457 + }
233.1458 + return;
233.1459 +}
233.1460 +
233.1461 +/*----------------------------------------------------------------------
233.1462 +-- append_slot - create and append new slot to domain block.
233.1463 +--
233.1464 +-- This routine creates new domain slot and adds it to the end of slot
233.1465 +-- list of specified domain block.
233.1466 +--
233.1467 +-- The parameter name is symbolic name of the dummy index associated
233.1468 +-- with the slot (the character string must be allocated). NULL means
233.1469 +-- the dummy index is not explicitly specified.
233.1470 +--
233.1471 +-- The parameter code is pseudo-code for computing symbolic value, at
233.1472 +-- which the dummy index is bounded. NULL means the dummy index is free
233.1473 +-- in the domain scope. */
233.1474 +
233.1475 +DOMAIN_SLOT *append_slot(MPL *mpl, DOMAIN_BLOCK *block, char *name,
233.1476 + CODE *code)
233.1477 +{ DOMAIN_SLOT *slot, *temp;
233.1478 + xassert(block != NULL);
233.1479 + slot = alloc(DOMAIN_SLOT);
233.1480 + slot->name = name;
233.1481 + slot->code = code;
233.1482 + slot->value = NULL;
233.1483 + slot->list = NULL;
233.1484 + slot->next = NULL;
233.1485 + if (block->list == NULL)
233.1486 + block->list = slot;
233.1487 + else
233.1488 + { for (temp = block->list; temp->next != NULL; temp =
233.1489 + temp->next);
233.1490 + temp->next = slot;
233.1491 + }
233.1492 + return slot;
233.1493 +}
233.1494 +
233.1495 +/*----------------------------------------------------------------------
233.1496 +-- expression_list - parse expression list.
233.1497 +--
233.1498 +-- This routine parses a list of one or more expressions enclosed into
233.1499 +-- the parentheses using the syntax:
233.1500 +--
233.1501 +-- <primary expression> ::= ( <expression list> )
233.1502 +-- <expression list> ::= <expression 13>
233.1503 +-- <expression list> ::= <expression 13> , <expression list>
233.1504 +--
233.1505 +-- Note that this construction may have three different meanings:
233.1506 +--
233.1507 +-- 1. If <expression list> consists of only one expression, <primary
233.1508 +-- expression> is a parenthesized expression, which may be of any
233.1509 +-- valid type (not necessarily 1-tuple).
233.1510 +--
233.1511 +-- 2. If <expression list> consists of several expressions separated by
233.1512 +-- commae, where no expression is undeclared symbolic name, <primary
233.1513 +-- expression> is a n-tuple.
233.1514 +--
233.1515 +-- 3. If <expression list> consists of several expressions separated by
233.1516 +-- commae, where at least one expression is undeclared symbolic name
233.1517 +-- (that denotes a dummy index), <primary expression> is a slice and
233.1518 +-- can be only used as constituent of indexing expression. */
233.1519 +
233.1520 +#define max_dim 20
233.1521 +/* maximal number of components allowed within parentheses */
233.1522 +
233.1523 +CODE *expression_list(MPL *mpl)
233.1524 +{ CODE *code;
233.1525 + OPERANDS arg;
233.1526 + struct { char *name; CODE *code; } list[1+max_dim];
233.1527 + int flag_x, next_token, dim, j, slice = 0;
233.1528 + xassert(mpl->token == T_LEFT);
233.1529 + /* the flag, which allows recognizing undeclared symbolic names
233.1530 + as dummy indices, will be automatically reset by get_token(),
233.1531 + so save it before scanning the next token */
233.1532 + flag_x = mpl->flag_x;
233.1533 + get_token(mpl /* ( */);
233.1534 + /* parse <expression list> */
233.1535 + for (dim = 1; ; dim++)
233.1536 + { if (dim > max_dim)
233.1537 + error(mpl, "too many components within parentheses");
233.1538 + /* current component of <expression list> can be either dummy
233.1539 + index or expression */
233.1540 + if (mpl->token == T_NAME)
233.1541 + { /* symbolic name is recognized as dummy index only if:
233.1542 + the flag, which allows that, is set, and
233.1543 + the name is followed by comma or right parenthesis, and
233.1544 + the name is undeclared */
233.1545 + get_token(mpl /* <symbolic name> */);
233.1546 + next_token = mpl->token;
233.1547 + unget_token(mpl);
233.1548 + if (!(flag_x &&
233.1549 + (next_token == T_COMMA || next_token == T_RIGHT) &&
233.1550 + avl_find_node(mpl->tree, mpl->image) == NULL))
233.1551 + { /* this is not dummy index */
233.1552 + goto expr;
233.1553 + }
233.1554 + /* all dummy indices within the same slice must have unique
233.1555 + symbolic names */
233.1556 + for (j = 1; j < dim; j++)
233.1557 + { if (list[j].name != NULL && strcmp(list[j].name,
233.1558 + mpl->image) == 0)
233.1559 + error(mpl, "duplicate dummy index %s not allowed",
233.1560 + mpl->image);
233.1561 + }
233.1562 + /* current component of <expression list> is dummy index */
233.1563 + list[dim].name
233.1564 + = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.1565 + strcpy(list[dim].name, mpl->image);
233.1566 + list[dim].code = NULL;
233.1567 + get_token(mpl /* <symbolic name> */);
233.1568 + /* <expression list> is a slice, because at least one dummy
233.1569 + index has appeared */
233.1570 + slice = 1;
233.1571 + /* note that the context ( <dummy index> ) is not allowed,
233.1572 + i.e. in this case <primary expression> is considered as
233.1573 + a parenthesized expression */
233.1574 + if (dim == 1 && mpl->token == T_RIGHT)
233.1575 + error(mpl, "%s not defined", list[dim].name);
233.1576 + }
233.1577 + else
233.1578 +expr: { /* current component of <expression list> is expression */
233.1579 + code = expression_13(mpl);
233.1580 + /* if the current expression is followed by comma or it is
233.1581 + not the very first expression, entire <expression list>
233.1582 + is n-tuple or slice, in which case the current expression
233.1583 + should be converted to symbolic type, if necessary */
233.1584 + if (mpl->token == T_COMMA || dim > 1)
233.1585 + { if (code->type == A_NUMERIC)
233.1586 + code = make_unary(mpl, O_CVTSYM, code, A_SYMBOLIC, 0);
233.1587 + /* now the expression must be of symbolic type */
233.1588 + if (code->type != A_SYMBOLIC)
233.1589 + error(mpl, "component expression has invalid type");
233.1590 + xassert(code->dim == 0);
233.1591 + }
233.1592 + list[dim].name = NULL;
233.1593 + list[dim].code = code;
233.1594 + }
233.1595 + /* check a token that follows the current component */
233.1596 + if (mpl->token == T_COMMA)
233.1597 + get_token(mpl /* , */);
233.1598 + else if (mpl->token == T_RIGHT)
233.1599 + break;
233.1600 + else
233.1601 + error(mpl, "right parenthesis missing where expected");
233.1602 + }
233.1603 + /* generate pseudo-code for <primary expression> */
233.1604 + if (dim == 1 && !slice)
233.1605 + { /* <primary expression> is a parenthesized expression */
233.1606 + code = list[1].code;
233.1607 + }
233.1608 + else if (!slice)
233.1609 + { /* <primary expression> is a n-tuple */
233.1610 + arg.list = create_arg_list(mpl);
233.1611 + for (j = 1; j <= dim; j++)
233.1612 + arg.list = expand_arg_list(mpl, arg.list, list[j].code);
233.1613 + code = make_code(mpl, O_TUPLE, &arg, A_TUPLE, dim);
233.1614 + }
233.1615 + else
233.1616 + { /* <primary expression> is a slice */
233.1617 + arg.slice = create_block(mpl);
233.1618 + for (j = 1; j <= dim; j++)
233.1619 + append_slot(mpl, arg.slice, list[j].name, list[j].code);
233.1620 + /* note that actually pseudo-codes with op = O_SLICE are never
233.1621 + evaluated */
233.1622 + code = make_code(mpl, O_SLICE, &arg, A_TUPLE, dim);
233.1623 + }
233.1624 + get_token(mpl /* ) */);
233.1625 + /* if <primary expression> is a slice, there must be the keyword
233.1626 + 'in', which follows the right parenthesis */
233.1627 + if (slice && mpl->token != T_IN)
233.1628 + error(mpl, "keyword in missing where expected");
233.1629 + /* if the slice flag is set and there is the keyword 'in', which
233.1630 + follows <primary expression>, the latter must be a slice */
233.1631 + if (flag_x && mpl->token == T_IN && !slice)
233.1632 + { if (dim == 1)
233.1633 + error(mpl, "syntax error in indexing expression");
233.1634 + else
233.1635 + error(mpl, "0-ary slice not allowed");
233.1636 + }
233.1637 + return code;
233.1638 +}
233.1639 +
233.1640 +/*----------------------------------------------------------------------
233.1641 +-- literal set - parse literal set.
233.1642 +--
233.1643 +-- This routine parses literal set using the syntax:
233.1644 +--
233.1645 +-- <literal set> ::= { <member list> }
233.1646 +-- <member list> ::= <member expression>
233.1647 +-- <member list> ::= <member list> , <member expression>
233.1648 +-- <member expression> ::= <expression 5>
233.1649 +--
233.1650 +-- It is assumed that the left curly brace and the very first member
233.1651 +-- expression that follows it are already parsed. The right curly brace
233.1652 +-- remains unscanned on exit. */
233.1653 +
233.1654 +CODE *literal_set(MPL *mpl, CODE *code)
233.1655 +{ OPERANDS arg;
233.1656 + int j;
233.1657 + xassert(code != NULL);
233.1658 + arg.list = create_arg_list(mpl);
233.1659 + /* parse <member list> */
233.1660 + for (j = 1; ; j++)
233.1661 + { /* all member expressions must be n-tuples; so, if the current
233.1662 + expression is not n-tuple, convert it to 1-tuple */
233.1663 + if (code->type == A_NUMERIC)
233.1664 + code = make_unary(mpl, O_CVTSYM, code, A_SYMBOLIC, 0);
233.1665 + if (code->type == A_SYMBOLIC)
233.1666 + code = make_unary(mpl, O_CVTTUP, code, A_TUPLE, 1);
233.1667 + /* now the expression must be n-tuple */
233.1668 + if (code->type != A_TUPLE)
233.1669 + error(mpl, "member expression has invalid type");
233.1670 + /* all member expressions must have identical dimension */
233.1671 + if (arg.list != NULL && arg.list->x->dim != code->dim)
233.1672 + error(mpl, "member %d has %d component%s while member %d ha"
233.1673 + "s %d component%s",
233.1674 + j-1, arg.list->x->dim, arg.list->x->dim == 1 ? "" : "s",
233.1675 + j, code->dim, code->dim == 1 ? "" : "s");
233.1676 + /* append the current expression to the member list */
233.1677 + arg.list = expand_arg_list(mpl, arg.list, code);
233.1678 + /* check a token that follows the current expression */
233.1679 + if (mpl->token == T_COMMA)
233.1680 + get_token(mpl /* , */);
233.1681 + else if (mpl->token == T_RBRACE)
233.1682 + break;
233.1683 + else
233.1684 + error(mpl, "syntax error in literal set");
233.1685 + /* parse the next expression that follows the comma */
233.1686 + code = expression_5(mpl);
233.1687 + }
233.1688 + /* generate pseudo-code for <literal set> */
233.1689 + code = make_code(mpl, O_MAKE, &arg, A_ELEMSET, arg.list->x->dim);
233.1690 + return code;
233.1691 +}
233.1692 +
233.1693 +/*----------------------------------------------------------------------
233.1694 +-- indexing_expression - parse indexing expression.
233.1695 +--
233.1696 +-- This routine parses indexing expression using the syntax:
233.1697 +--
233.1698 +-- <indexing expression> ::= <literal set>
233.1699 +-- <indexing expression> ::= { <indexing list> }
233.1700 +-- <indexing expression> ::= { <indexing list> : <logical expression> }
233.1701 +-- <indexing list> ::= <indexing element>
233.1702 +-- <indexing list> ::= <indexing list> , <indexing element>
233.1703 +-- <indexing element> ::= <basic expression>
233.1704 +-- <indexing element> ::= <dummy index> in <basic expression>
233.1705 +-- <indexing element> ::= <slice> in <basic expression>
233.1706 +-- <dummy index> ::= <symbolic name>
233.1707 +-- <slice> ::= ( <expression list> )
233.1708 +-- <basic expression> ::= <expression 9>
233.1709 +-- <logical expression> ::= <expression 13>
233.1710 +--
233.1711 +-- This routine creates domain for <indexing expression>, where each
233.1712 +-- domain block corresponds to <indexing element>, and each domain slot
233.1713 +-- corresponds to individual indexing position. */
233.1714 +
233.1715 +DOMAIN *indexing_expression(MPL *mpl)
233.1716 +{ DOMAIN *domain;
233.1717 + DOMAIN_BLOCK *block;
233.1718 + DOMAIN_SLOT *slot;
233.1719 + CODE *code;
233.1720 + xassert(mpl->token == T_LBRACE);
233.1721 + get_token(mpl /* { */);
233.1722 + if (mpl->token == T_RBRACE)
233.1723 + error(mpl, "empty indexing expression not allowed");
233.1724 + /* create domain to be constructed */
233.1725 + domain = create_domain(mpl);
233.1726 + /* parse either <member list> or <indexing list> that follows the
233.1727 + left brace */
233.1728 + for (;;)
233.1729 + { /* domain block for <indexing element> is not created yet */
233.1730 + block = NULL;
233.1731 + /* pseudo-code for <basic expression> is not generated yet */
233.1732 + code = NULL;
233.1733 + /* check a token, which <indexing element> begins with */
233.1734 + if (mpl->token == T_NAME)
233.1735 + { /* it is a symbolic name */
233.1736 + int next_token;
233.1737 + char *name;
233.1738 + /* symbolic name is recognized as dummy index only if it is
233.1739 + followed by the keyword 'in' and not declared */
233.1740 + get_token(mpl /* <symbolic name> */);
233.1741 + next_token = mpl->token;
233.1742 + unget_token(mpl);
233.1743 + if (!(next_token == T_IN &&
233.1744 + avl_find_node(mpl->tree, mpl->image) == NULL))
233.1745 + { /* this is not dummy index; the symbolic name begins an
233.1746 + expression, which is either <basic expression> or the
233.1747 + very first <member expression> in <literal set> */
233.1748 + goto expr;
233.1749 + }
233.1750 + /* create domain block with one slot, which is assigned the
233.1751 + dummy index */
233.1752 + block = create_block(mpl);
233.1753 + name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.1754 + strcpy(name, mpl->image);
233.1755 + append_slot(mpl, block, name, NULL);
233.1756 + get_token(mpl /* <symbolic name> */);
233.1757 + /* the keyword 'in' is already checked above */
233.1758 + xassert(mpl->token == T_IN);
233.1759 + get_token(mpl /* in */);
233.1760 + /* <basic expression> that follows the keyword 'in' will be
233.1761 + parsed below */
233.1762 + }
233.1763 + else if (mpl->token == T_LEFT)
233.1764 + { /* it is the left parenthesis; parse expression that begins
233.1765 + with this parenthesis (the flag is set in order to allow
233.1766 + recognizing slices; see the routine expression_list) */
233.1767 + mpl->flag_x = 1;
233.1768 + code = expression_9(mpl);
233.1769 + if (code->op != O_SLICE)
233.1770 + { /* this is either <basic expression> or the very first
233.1771 + <member expression> in <literal set> */
233.1772 + goto expr;
233.1773 + }
233.1774 + /* this is a slice; besides the corresponding domain block
233.1775 + is already created by expression_list() */
233.1776 + block = code->arg.slice;
233.1777 + code = NULL; /* <basic expression> is not parsed yet */
233.1778 + /* the keyword 'in' following the slice is already checked
233.1779 + by expression_list() */
233.1780 + xassert(mpl->token == T_IN);
233.1781 + get_token(mpl /* in */);
233.1782 + /* <basic expression> that follows the keyword 'in' will be
233.1783 + parsed below */
233.1784 + }
233.1785 +expr: /* parse expression that follows either the keyword 'in' (in
233.1786 + which case it can be <basic expression) or the left brace
233.1787 + (in which case it can be <basic expression> as well as the
233.1788 + very first <member expression> in <literal set>); note that
233.1789 + this expression can be already parsed above */
233.1790 + if (code == NULL) code = expression_9(mpl);
233.1791 + /* check the type of the expression just parsed */
233.1792 + if (code->type != A_ELEMSET)
233.1793 + { /* it is not <basic expression> and therefore it can only
233.1794 + be the very first <member expression> in <literal set>;
233.1795 + however, then there must be no dummy index neither slice
233.1796 + between the left brace and this expression */
233.1797 + if (block != NULL)
233.1798 + error(mpl, "domain expression has invalid type");
233.1799 + /* parse the rest part of <literal set> and make this set
233.1800 + be <basic expression>, i.e. the construction {a, b, c}
233.1801 + is parsed as it were written as {A}, where A = {a, b, c}
233.1802 + is a temporary elemental set */
233.1803 + code = literal_set(mpl, code);
233.1804 + }
233.1805 + /* now pseudo-code for <basic set> has been built */
233.1806 + xassert(code != NULL);
233.1807 + xassert(code->type == A_ELEMSET);
233.1808 + xassert(code->dim > 0);
233.1809 + /* if domain block for the current <indexing element> is still
233.1810 + not created, create it for fake slice of the same dimension
233.1811 + as <basic set> */
233.1812 + if (block == NULL)
233.1813 + { int j;
233.1814 + block = create_block(mpl);
233.1815 + for (j = 1; j <= code->dim; j++)
233.1816 + append_slot(mpl, block, NULL, NULL);
233.1817 + }
233.1818 + /* number of indexing positions in <indexing element> must be
233.1819 + the same as dimension of n-tuples in basic set */
233.1820 + { int dim = 0;
233.1821 + for (slot = block->list; slot != NULL; slot = slot->next)
233.1822 + dim++;
233.1823 + if (dim != code->dim)
233.1824 + error(mpl,"%d %s specified for set of dimension %d",
233.1825 + dim, dim == 1 ? "index" : "indices", code->dim);
233.1826 + }
233.1827 + /* store pseudo-code for <basic set> in the domain block */
233.1828 + xassert(block->code == NULL);
233.1829 + block->code = code;
233.1830 + /* and append the domain block to the domain */
233.1831 + append_block(mpl, domain, block);
233.1832 + /* the current <indexing element> has been completely parsed;
233.1833 + include all its dummy indices into the symbolic name table
233.1834 + to make them available for referencing from expressions;
233.1835 + implicit declarations of dummy indices remain valid while
233.1836 + the corresponding domain scope is valid */
233.1837 + for (slot = block->list; slot != NULL; slot = slot->next)
233.1838 + if (slot->name != NULL)
233.1839 + { AVLNODE *node;
233.1840 + xassert(avl_find_node(mpl->tree, slot->name) == NULL);
233.1841 + node = avl_insert_node(mpl->tree, slot->name);
233.1842 + avl_set_node_type(node, A_INDEX);
233.1843 + avl_set_node_link(node, (void *)slot);
233.1844 + }
233.1845 + /* check a token that follows <indexing element> */
233.1846 + if (mpl->token == T_COMMA)
233.1847 + get_token(mpl /* , */);
233.1848 + else if (mpl->token == T_COLON || mpl->token == T_RBRACE)
233.1849 + break;
233.1850 + else
233.1851 + error(mpl, "syntax error in indexing expression");
233.1852 + }
233.1853 + /* parse <logical expression> that follows the colon */
233.1854 + if (mpl->token == T_COLON)
233.1855 + { get_token(mpl /* : */);
233.1856 + code = expression_13(mpl);
233.1857 + /* convert the expression to logical type, if necessary */
233.1858 + if (code->type == A_SYMBOLIC)
233.1859 + code = make_unary(mpl, O_CVTNUM, code, A_NUMERIC, 0);
233.1860 + if (code->type == A_NUMERIC)
233.1861 + code = make_unary(mpl, O_CVTLOG, code, A_LOGICAL, 0);
233.1862 + /* now the expression must be of logical type */
233.1863 + if (code->type != A_LOGICAL)
233.1864 + error(mpl, "expression following colon has invalid type");
233.1865 + xassert(code->dim == 0);
233.1866 + domain->code = code;
233.1867 + /* the right brace must follow the logical expression */
233.1868 + if (mpl->token != T_RBRACE)
233.1869 + error(mpl, "syntax error in indexing expression");
233.1870 + }
233.1871 + get_token(mpl /* } */);
233.1872 + return domain;
233.1873 +}
233.1874 +
233.1875 +/*----------------------------------------------------------------------
233.1876 +-- close_scope - close scope of indexing expression.
233.1877 +--
233.1878 +-- The routine closes the scope of indexing expression specified by its
233.1879 +-- domain and thereby makes all dummy indices introduced in the indexing
233.1880 +-- expression no longer available for referencing. */
233.1881 +
233.1882 +void close_scope(MPL *mpl, DOMAIN *domain)
233.1883 +{ DOMAIN_BLOCK *block;
233.1884 + DOMAIN_SLOT *slot;
233.1885 + AVLNODE *node;
233.1886 + xassert(domain != NULL);
233.1887 + /* remove all dummy indices from the symbolic names table */
233.1888 + for (block = domain->list; block != NULL; block = block->next)
233.1889 + { for (slot = block->list; slot != NULL; slot = slot->next)
233.1890 + { if (slot->name != NULL)
233.1891 + { node = avl_find_node(mpl->tree, slot->name);
233.1892 + xassert(node != NULL);
233.1893 + xassert(avl_get_node_type(node) == A_INDEX);
233.1894 + avl_delete_node(mpl->tree, node);
233.1895 + }
233.1896 + }
233.1897 + }
233.1898 + return;
233.1899 +}
233.1900 +
233.1901 +/*----------------------------------------------------------------------
233.1902 +-- iterated_expression - parse iterated expression.
233.1903 +--
233.1904 +-- This routine parses primary expression using the syntax:
233.1905 +--
233.1906 +-- <primary expression> ::= <iterated expression>
233.1907 +-- <iterated expression> ::= sum <indexing expression> <expression 3>
233.1908 +-- <iterated expression> ::= prod <indexing expression> <expression 3>
233.1909 +-- <iterated expression> ::= min <indexing expression> <expression 3>
233.1910 +-- <iterated expression> ::= max <indexing expression> <expression 3>
233.1911 +-- <iterated expression> ::= exists <indexing expression>
233.1912 +-- <expression 12>
233.1913 +-- <iterated expression> ::= forall <indexing expression>
233.1914 +-- <expression 12>
233.1915 +-- <iterated expression> ::= setof <indexing expression> <expression 5>
233.1916 +--
233.1917 +-- Note that parsing "integrand" depends on the iterated operator. */
233.1918 +
233.1919 +#if 1 /* 07/IX-2008 */
233.1920 +static void link_up(CODE *code)
233.1921 +{ /* if we have something like sum{(i+1,j,k-1) in E} x[i,j,k],
233.1922 + where i and k are dummy indices defined out of the iterated
233.1923 + expression, we should link up pseudo-code for computing i+1
233.1924 + and k-1 to pseudo-code for computing the iterated expression;
233.1925 + this is needed to invalidate current value of the iterated
233.1926 + expression once i or k have been changed */
233.1927 + DOMAIN_BLOCK *block;
233.1928 + DOMAIN_SLOT *slot;
233.1929 + for (block = code->arg.loop.domain->list; block != NULL;
233.1930 + block = block->next)
233.1931 + { for (slot = block->list; slot != NULL; slot = slot->next)
233.1932 + { if (slot->code != NULL)
233.1933 + { xassert(slot->code->up == NULL);
233.1934 + slot->code->up = code;
233.1935 + }
233.1936 + }
233.1937 + }
233.1938 + return;
233.1939 +}
233.1940 +#endif
233.1941 +
233.1942 +CODE *iterated_expression(MPL *mpl)
233.1943 +{ CODE *code;
233.1944 + OPERANDS arg;
233.1945 + int op;
233.1946 + char opstr[8];
233.1947 + /* determine operation code */
233.1948 + xassert(mpl->token == T_NAME);
233.1949 + if (strcmp(mpl->image, "sum") == 0)
233.1950 + op = O_SUM;
233.1951 + else if (strcmp(mpl->image, "prod") == 0)
233.1952 + op = O_PROD;
233.1953 + else if (strcmp(mpl->image, "min") == 0)
233.1954 + op = O_MINIMUM;
233.1955 + else if (strcmp(mpl->image, "max") == 0)
233.1956 + op = O_MAXIMUM;
233.1957 + else if (strcmp(mpl->image, "forall") == 0)
233.1958 + op = O_FORALL;
233.1959 + else if (strcmp(mpl->image, "exists") == 0)
233.1960 + op = O_EXISTS;
233.1961 + else if (strcmp(mpl->image, "setof") == 0)
233.1962 + op = O_SETOF;
233.1963 + else
233.1964 + error(mpl, "operator %s unknown", mpl->image);
233.1965 + strcpy(opstr, mpl->image);
233.1966 + xassert(strlen(opstr) < sizeof(opstr));
233.1967 + get_token(mpl /* <symbolic name> */);
233.1968 + /* check the left brace that follows the operator name */
233.1969 + xassert(mpl->token == T_LBRACE);
233.1970 + /* parse indexing expression that controls iterating */
233.1971 + arg.loop.domain = indexing_expression(mpl);
233.1972 + /* parse "integrand" expression and generate pseudo-code */
233.1973 + switch (op)
233.1974 + { case O_SUM:
233.1975 + case O_PROD:
233.1976 + case O_MINIMUM:
233.1977 + case O_MAXIMUM:
233.1978 + arg.loop.x = expression_3(mpl);
233.1979 + /* convert the integrand to numeric type, if necessary */
233.1980 + if (arg.loop.x->type == A_SYMBOLIC)
233.1981 + arg.loop.x = make_unary(mpl, O_CVTNUM, arg.loop.x,
233.1982 + A_NUMERIC, 0);
233.1983 + /* now the integrand must be of numeric type or linear form
233.1984 + (the latter is only allowed for the sum operator) */
233.1985 + if (!(arg.loop.x->type == A_NUMERIC ||
233.1986 + op == O_SUM && arg.loop.x->type == A_FORMULA))
233.1987 +err: error(mpl, "integrand following %s{...} has invalid type"
233.1988 + , opstr);
233.1989 + xassert(arg.loop.x->dim == 0);
233.1990 + /* generate pseudo-code */
233.1991 + code = make_code(mpl, op, &arg, arg.loop.x->type, 0);
233.1992 + break;
233.1993 + case O_FORALL:
233.1994 + case O_EXISTS:
233.1995 + arg.loop.x = expression_12(mpl);
233.1996 + /* convert the integrand to logical type, if necessary */
233.1997 + if (arg.loop.x->type == A_SYMBOLIC)
233.1998 + arg.loop.x = make_unary(mpl, O_CVTNUM, arg.loop.x,
233.1999 + A_NUMERIC, 0);
233.2000 + if (arg.loop.x->type == A_NUMERIC)
233.2001 + arg.loop.x = make_unary(mpl, O_CVTLOG, arg.loop.x,
233.2002 + A_LOGICAL, 0);
233.2003 + /* now the integrand must be of logical type */
233.2004 + if (arg.loop.x->type != A_LOGICAL) goto err;
233.2005 + xassert(arg.loop.x->dim == 0);
233.2006 + /* generate pseudo-code */
233.2007 + code = make_code(mpl, op, &arg, A_LOGICAL, 0);
233.2008 + break;
233.2009 + case O_SETOF:
233.2010 + arg.loop.x = expression_5(mpl);
233.2011 + /* convert the integrand to 1-tuple, if necessary */
233.2012 + if (arg.loop.x->type == A_NUMERIC)
233.2013 + arg.loop.x = make_unary(mpl, O_CVTSYM, arg.loop.x,
233.2014 + A_SYMBOLIC, 0);
233.2015 + if (arg.loop.x->type == A_SYMBOLIC)
233.2016 + arg.loop.x = make_unary(mpl, O_CVTTUP, arg.loop.x,
233.2017 + A_TUPLE, 1);
233.2018 + /* now the integrand must be n-tuple */
233.2019 + if (arg.loop.x->type != A_TUPLE) goto err;
233.2020 + xassert(arg.loop.x->dim > 0);
233.2021 + /* generate pseudo-code */
233.2022 + code = make_code(mpl, op, &arg, A_ELEMSET, arg.loop.x->dim);
233.2023 + break;
233.2024 + default:
233.2025 + xassert(op != op);
233.2026 + }
233.2027 + /* close the scope of the indexing expression */
233.2028 + close_scope(mpl, arg.loop.domain);
233.2029 +#if 1 /* 07/IX-2008 */
233.2030 + link_up(code);
233.2031 +#endif
233.2032 + return code;
233.2033 +}
233.2034 +
233.2035 +/*----------------------------------------------------------------------
233.2036 +-- domain_arity - determine arity of domain.
233.2037 +--
233.2038 +-- This routine returns arity of specified domain, which is number of
233.2039 +-- its free dummy indices. */
233.2040 +
233.2041 +int domain_arity(MPL *mpl, DOMAIN *domain)
233.2042 +{ DOMAIN_BLOCK *block;
233.2043 + DOMAIN_SLOT *slot;
233.2044 + int arity;
233.2045 + xassert(mpl == mpl);
233.2046 + arity = 0;
233.2047 + for (block = domain->list; block != NULL; block = block->next)
233.2048 + for (slot = block->list; slot != NULL; slot = slot->next)
233.2049 + if (slot->code == NULL) arity++;
233.2050 + return arity;
233.2051 +}
233.2052 +
233.2053 +/*----------------------------------------------------------------------
233.2054 +-- set_expression - parse set expression.
233.2055 +--
233.2056 +-- This routine parses primary expression using the syntax:
233.2057 +--
233.2058 +-- <primary expression> ::= { }
233.2059 +-- <primary expression> ::= <indexing expression> */
233.2060 +
233.2061 +CODE *set_expression(MPL *mpl)
233.2062 +{ CODE *code;
233.2063 + OPERANDS arg;
233.2064 + xassert(mpl->token == T_LBRACE);
233.2065 + get_token(mpl /* { */);
233.2066 + /* check a token that follows the left brace */
233.2067 + if (mpl->token == T_RBRACE)
233.2068 + { /* it is the right brace, so the resultant is an empty set of
233.2069 + dimension 1 */
233.2070 + arg.list = NULL;
233.2071 + /* generate pseudo-code to build the resultant set */
233.2072 + code = make_code(mpl, O_MAKE, &arg, A_ELEMSET, 1);
233.2073 + get_token(mpl /* } */);
233.2074 + }
233.2075 + else
233.2076 + { /* the next token begins an indexing expression */
233.2077 + unget_token(mpl);
233.2078 + arg.loop.domain = indexing_expression(mpl);
233.2079 + arg.loop.x = NULL; /* integrand is not used */
233.2080 + /* close the scope of the indexing expression */
233.2081 + close_scope(mpl, arg.loop.domain);
233.2082 + /* generate pseudo-code to build the resultant set */
233.2083 + code = make_code(mpl, O_BUILD, &arg, A_ELEMSET,
233.2084 + domain_arity(mpl, arg.loop.domain));
233.2085 +#if 1 /* 07/IX-2008 */
233.2086 + link_up(code);
233.2087 +#endif
233.2088 + }
233.2089 + return code;
233.2090 +}
233.2091 +
233.2092 +/*----------------------------------------------------------------------
233.2093 +-- branched_expression - parse conditional expression.
233.2094 +--
233.2095 +-- This routine parses primary expression using the syntax:
233.2096 +--
233.2097 +-- <primary expression> ::= <branched expression>
233.2098 +-- <branched expression> ::= if <logical expression> then <expression 9>
233.2099 +-- <branched expression> ::= if <logical expression> then <expression 9>
233.2100 +-- else <expression 9>
233.2101 +-- <logical expression> ::= <expression 13> */
233.2102 +
233.2103 +CODE *branched_expression(MPL *mpl)
233.2104 +{ CODE *code, *x, *y, *z;
233.2105 + xassert(mpl->token == T_IF);
233.2106 + get_token(mpl /* if */);
233.2107 + /* parse <logical expression> that follows 'if' */
233.2108 + x = expression_13(mpl);
233.2109 + /* convert the expression to logical type, if necessary */
233.2110 + if (x->type == A_SYMBOLIC)
233.2111 + x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2112 + if (x->type == A_NUMERIC)
233.2113 + x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
233.2114 + /* now the expression must be of logical type */
233.2115 + if (x->type != A_LOGICAL)
233.2116 + error(mpl, "expression following if has invalid type");
233.2117 + xassert(x->dim == 0);
233.2118 + /* the keyword 'then' must follow the logical expression */
233.2119 + if (mpl->token != T_THEN)
233.2120 + error(mpl, "keyword then missing where expected");
233.2121 + get_token(mpl /* then */);
233.2122 + /* parse <expression> that follows 'then' and check its type */
233.2123 + y = expression_9(mpl);
233.2124 + if (!(y->type == A_NUMERIC || y->type == A_SYMBOLIC ||
233.2125 + y->type == A_ELEMSET || y->type == A_FORMULA))
233.2126 + error(mpl, "expression following then has invalid type");
233.2127 + /* if the expression that follows the keyword 'then' is elemental
233.2128 + set, the keyword 'else' cannot be omitted; otherwise else-part
233.2129 + is optional */
233.2130 + if (mpl->token != T_ELSE)
233.2131 + { if (y->type == A_ELEMSET)
233.2132 + error(mpl, "keyword else missing where expected");
233.2133 + z = NULL;
233.2134 + goto skip;
233.2135 + }
233.2136 + get_token(mpl /* else */);
233.2137 + /* parse <expression> that follow 'else' and check its type */
233.2138 + z = expression_9(mpl);
233.2139 + if (!(z->type == A_NUMERIC || z->type == A_SYMBOLIC ||
233.2140 + z->type == A_ELEMSET || z->type == A_FORMULA))
233.2141 + error(mpl, "expression following else has invalid type");
233.2142 + /* convert to identical types, if necessary */
233.2143 + if (y->type == A_FORMULA || z->type == A_FORMULA)
233.2144 + { if (y->type == A_SYMBOLIC)
233.2145 + y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2146 + if (y->type == A_NUMERIC)
233.2147 + y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0);
233.2148 + if (z->type == A_SYMBOLIC)
233.2149 + z = make_unary(mpl, O_CVTNUM, z, A_NUMERIC, 0);
233.2150 + if (z->type == A_NUMERIC)
233.2151 + z = make_unary(mpl, O_CVTLFM, z, A_FORMULA, 0);
233.2152 + }
233.2153 + if (y->type == A_SYMBOLIC || z->type == A_SYMBOLIC)
233.2154 + { if (y->type == A_NUMERIC)
233.2155 + y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0);
233.2156 + if (z->type == A_NUMERIC)
233.2157 + z = make_unary(mpl, O_CVTSYM, z, A_SYMBOLIC, 0);
233.2158 + }
233.2159 + /* now both expressions must have identical types */
233.2160 + if (y->type != z->type)
233.2161 + error(mpl, "expressions following then and else have incompati"
233.2162 + "ble types");
233.2163 + /* and identical dimensions */
233.2164 + if (y->dim != z->dim)
233.2165 + error(mpl, "expressions following then and else have different"
233.2166 + " dimensions %d and %d, respectively", y->dim, z->dim);
233.2167 +skip: /* generate pseudo-code to perform branching */
233.2168 + code = make_ternary(mpl, O_FORK, x, y, z, y->type, y->dim);
233.2169 + return code;
233.2170 +}
233.2171 +
233.2172 +/*----------------------------------------------------------------------
233.2173 +-- primary_expression - parse primary expression.
233.2174 +--
233.2175 +-- This routine parses primary expression using the syntax:
233.2176 +--
233.2177 +-- <primary expression> ::= <numeric literal>
233.2178 +-- <primary expression> ::= Infinity
233.2179 +-- <primary expression> ::= <string literal>
233.2180 +-- <primary expression> ::= <dummy index>
233.2181 +-- <primary expression> ::= <set name>
233.2182 +-- <primary expression> ::= <set name> [ <subscript list> ]
233.2183 +-- <primary expression> ::= <parameter name>
233.2184 +-- <primary expression> ::= <parameter name> [ <subscript list> ]
233.2185 +-- <primary expression> ::= <variable name>
233.2186 +-- <primary expression> ::= <variable name> [ <subscript list> ]
233.2187 +-- <primary expression> ::= <built-in function> ( <argument list> )
233.2188 +-- <primary expression> ::= ( <expression list> )
233.2189 +-- <primary expression> ::= <iterated expression>
233.2190 +-- <primary expression> ::= { }
233.2191 +-- <primary expression> ::= <indexing expression>
233.2192 +-- <primary expression> ::= <branched expression>
233.2193 +--
233.2194 +-- For complete list of syntactic rules for <primary expression> see
233.2195 +-- comments to the corresponding parsing routines. */
233.2196 +
233.2197 +CODE *primary_expression(MPL *mpl)
233.2198 +{ CODE *code;
233.2199 + if (mpl->token == T_NUMBER)
233.2200 + { /* parse numeric literal */
233.2201 + code = numeric_literal(mpl);
233.2202 + }
233.2203 +#if 1 /* 21/VII-2006 */
233.2204 + else if (mpl->token == T_INFINITY)
233.2205 + { /* parse "infinity" */
233.2206 + OPERANDS arg;
233.2207 + arg.num = DBL_MAX;
233.2208 + code = make_code(mpl, O_NUMBER, &arg, A_NUMERIC, 0);
233.2209 + get_token(mpl /* Infinity */);
233.2210 + }
233.2211 +#endif
233.2212 + else if (mpl->token == T_STRING)
233.2213 + { /* parse string literal */
233.2214 + code = string_literal(mpl);
233.2215 + }
233.2216 + else if (mpl->token == T_NAME)
233.2217 + { int next_token;
233.2218 + get_token(mpl /* <symbolic name> */);
233.2219 + next_token = mpl->token;
233.2220 + unget_token(mpl);
233.2221 + /* check a token that follows <symbolic name> */
233.2222 + switch (next_token)
233.2223 + { case T_LBRACKET:
233.2224 + /* parse reference to subscripted object */
233.2225 + code = object_reference(mpl);
233.2226 + break;
233.2227 + case T_LEFT:
233.2228 + /* parse reference to built-in function */
233.2229 + code = function_reference(mpl);
233.2230 + break;
233.2231 + case T_LBRACE:
233.2232 + /* parse iterated expression */
233.2233 + code = iterated_expression(mpl);
233.2234 + break;
233.2235 + default:
233.2236 + /* parse reference to unsubscripted object */
233.2237 + code = object_reference(mpl);
233.2238 + break;
233.2239 + }
233.2240 + }
233.2241 + else if (mpl->token == T_LEFT)
233.2242 + { /* parse parenthesized expression */
233.2243 + code = expression_list(mpl);
233.2244 + }
233.2245 + else if (mpl->token == T_LBRACE)
233.2246 + { /* parse set expression */
233.2247 + code = set_expression(mpl);
233.2248 + }
233.2249 + else if (mpl->token == T_IF)
233.2250 + { /* parse conditional expression */
233.2251 + code = branched_expression(mpl);
233.2252 + }
233.2253 + else if (is_reserved(mpl))
233.2254 + { /* other reserved keywords cannot be used here */
233.2255 + error(mpl, "invalid use of reserved keyword %s", mpl->image);
233.2256 + }
233.2257 + else
233.2258 + error(mpl, "syntax error in expression");
233.2259 + return code;
233.2260 +}
233.2261 +
233.2262 +/*----------------------------------------------------------------------
233.2263 +-- error_preceding - raise error if preceding operand has wrong type.
233.2264 +--
233.2265 +-- This routine is called to raise error if operand that precedes some
233.2266 +-- infix operator has invalid type. */
233.2267 +
233.2268 +void error_preceding(MPL *mpl, char *opstr)
233.2269 +{ error(mpl, "operand preceding %s has invalid type", opstr);
233.2270 + /* no return */
233.2271 +}
233.2272 +
233.2273 +/*----------------------------------------------------------------------
233.2274 +-- error_following - raise error if following operand has wrong type.
233.2275 +--
233.2276 +-- This routine is called to raise error if operand that follows some
233.2277 +-- infix operator has invalid type. */
233.2278 +
233.2279 +void error_following(MPL *mpl, char *opstr)
233.2280 +{ error(mpl, "operand following %s has invalid type", opstr);
233.2281 + /* no return */
233.2282 +}
233.2283 +
233.2284 +/*----------------------------------------------------------------------
233.2285 +-- error_dimension - raise error if operands have different dimension.
233.2286 +--
233.2287 +-- This routine is called to raise error if two operands of some infix
233.2288 +-- operator have different dimension. */
233.2289 +
233.2290 +void error_dimension(MPL *mpl, char *opstr, int dim1, int dim2)
233.2291 +{ error(mpl, "operands preceding and following %s have different di"
233.2292 + "mensions %d and %d, respectively", opstr, dim1, dim2);
233.2293 + /* no return */
233.2294 +}
233.2295 +
233.2296 +/*----------------------------------------------------------------------
233.2297 +-- expression_0 - parse expression of level 0.
233.2298 +--
233.2299 +-- This routine parses expression of level 0 using the syntax:
233.2300 +--
233.2301 +-- <expression 0> ::= <primary expression> */
233.2302 +
233.2303 +CODE *expression_0(MPL *mpl)
233.2304 +{ CODE *code;
233.2305 + code = primary_expression(mpl);
233.2306 + return code;
233.2307 +}
233.2308 +
233.2309 +/*----------------------------------------------------------------------
233.2310 +-- expression_1 - parse expression of level 1.
233.2311 +--
233.2312 +-- This routine parses expression of level 1 using the syntax:
233.2313 +--
233.2314 +-- <expression 1> ::= <expression 0>
233.2315 +-- <expression 1> ::= <expression 0> <power> <expression 1>
233.2316 +-- <expression 1> ::= <expression 0> <power> <expression 2>
233.2317 +-- <power> ::= ^ | ** */
233.2318 +
233.2319 +CODE *expression_1(MPL *mpl)
233.2320 +{ CODE *x, *y;
233.2321 + char opstr[8];
233.2322 + x = expression_0(mpl);
233.2323 + if (mpl->token == T_POWER)
233.2324 + { strcpy(opstr, mpl->image);
233.2325 + xassert(strlen(opstr) < sizeof(opstr));
233.2326 + if (x->type == A_SYMBOLIC)
233.2327 + x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2328 + if (x->type != A_NUMERIC)
233.2329 + error_preceding(mpl, opstr);
233.2330 + get_token(mpl /* ^ | ** */);
233.2331 + if (mpl->token == T_PLUS || mpl->token == T_MINUS)
233.2332 + y = expression_2(mpl);
233.2333 + else
233.2334 + y = expression_1(mpl);
233.2335 + if (y->type == A_SYMBOLIC)
233.2336 + y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2337 + if (y->type != A_NUMERIC)
233.2338 + error_following(mpl, opstr);
233.2339 + x = make_binary(mpl, O_POWER, x, y, A_NUMERIC, 0);
233.2340 + }
233.2341 + return x;
233.2342 +}
233.2343 +
233.2344 +/*----------------------------------------------------------------------
233.2345 +-- expression_2 - parse expression of level 2.
233.2346 +--
233.2347 +-- This routine parses expression of level 2 using the syntax:
233.2348 +--
233.2349 +-- <expression 2> ::= <expression 1>
233.2350 +-- <expression 2> ::= + <expression 1>
233.2351 +-- <expression 2> ::= - <expression 1> */
233.2352 +
233.2353 +CODE *expression_2(MPL *mpl)
233.2354 +{ CODE *x;
233.2355 + if (mpl->token == T_PLUS)
233.2356 + { get_token(mpl /* + */);
233.2357 + x = expression_1(mpl);
233.2358 + if (x->type == A_SYMBOLIC)
233.2359 + x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2360 + if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
233.2361 + error_following(mpl, "+");
233.2362 + x = make_unary(mpl, O_PLUS, x, x->type, 0);
233.2363 + }
233.2364 + else if (mpl->token == T_MINUS)
233.2365 + { get_token(mpl /* - */);
233.2366 + x = expression_1(mpl);
233.2367 + if (x->type == A_SYMBOLIC)
233.2368 + x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2369 + if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
233.2370 + error_following(mpl, "-");
233.2371 + x = make_unary(mpl, O_MINUS, x, x->type, 0);
233.2372 + }
233.2373 + else
233.2374 + x = expression_1(mpl);
233.2375 + return x;
233.2376 +}
233.2377 +
233.2378 +/*----------------------------------------------------------------------
233.2379 +-- expression_3 - parse expression of level 3.
233.2380 +--
233.2381 +-- This routine parses expression of level 3 using the syntax:
233.2382 +--
233.2383 +-- <expression 3> ::= <expression 2>
233.2384 +-- <expression 3> ::= <expression 3> * <expression 2>
233.2385 +-- <expression 3> ::= <expression 3> / <expression 2>
233.2386 +-- <expression 3> ::= <expression 3> div <expression 2>
233.2387 +-- <expression 3> ::= <expression 3> mod <expression 2> */
233.2388 +
233.2389 +CODE *expression_3(MPL *mpl)
233.2390 +{ CODE *x, *y;
233.2391 + x = expression_2(mpl);
233.2392 + for (;;)
233.2393 + { if (mpl->token == T_ASTERISK)
233.2394 + { if (x->type == A_SYMBOLIC)
233.2395 + x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2396 + if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
233.2397 + error_preceding(mpl, "*");
233.2398 + get_token(mpl /* * */);
233.2399 + y = expression_2(mpl);
233.2400 + if (y->type == A_SYMBOLIC)
233.2401 + y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2402 + if (!(y->type == A_NUMERIC || y->type == A_FORMULA))
233.2403 + error_following(mpl, "*");
233.2404 + if (x->type == A_FORMULA && y->type == A_FORMULA)
233.2405 + error(mpl, "multiplication of linear forms not allowed");
233.2406 + if (x->type == A_NUMERIC && y->type == A_NUMERIC)
233.2407 + x = make_binary(mpl, O_MUL, x, y, A_NUMERIC, 0);
233.2408 + else
233.2409 + x = make_binary(mpl, O_MUL, x, y, A_FORMULA, 0);
233.2410 + }
233.2411 + else if (mpl->token == T_SLASH)
233.2412 + { if (x->type == A_SYMBOLIC)
233.2413 + x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2414 + if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
233.2415 + error_preceding(mpl, "/");
233.2416 + get_token(mpl /* / */);
233.2417 + y = expression_2(mpl);
233.2418 + if (y->type == A_SYMBOLIC)
233.2419 + y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2420 + if (y->type != A_NUMERIC)
233.2421 + error_following(mpl, "/");
233.2422 + if (x->type == A_NUMERIC)
233.2423 + x = make_binary(mpl, O_DIV, x, y, A_NUMERIC, 0);
233.2424 + else
233.2425 + x = make_binary(mpl, O_DIV, x, y, A_FORMULA, 0);
233.2426 + }
233.2427 + else if (mpl->token == T_DIV)
233.2428 + { if (x->type == A_SYMBOLIC)
233.2429 + x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2430 + if (x->type != A_NUMERIC)
233.2431 + error_preceding(mpl, "div");
233.2432 + get_token(mpl /* div */);
233.2433 + y = expression_2(mpl);
233.2434 + if (y->type == A_SYMBOLIC)
233.2435 + y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2436 + if (y->type != A_NUMERIC)
233.2437 + error_following(mpl, "div");
233.2438 + x = make_binary(mpl, O_IDIV, x, y, A_NUMERIC, 0);
233.2439 + }
233.2440 + else if (mpl->token == T_MOD)
233.2441 + { if (x->type == A_SYMBOLIC)
233.2442 + x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2443 + if (x->type != A_NUMERIC)
233.2444 + error_preceding(mpl, "mod");
233.2445 + get_token(mpl /* mod */);
233.2446 + y = expression_2(mpl);
233.2447 + if (y->type == A_SYMBOLIC)
233.2448 + y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2449 + if (y->type != A_NUMERIC)
233.2450 + error_following(mpl, "mod");
233.2451 + x = make_binary(mpl, O_MOD, x, y, A_NUMERIC, 0);
233.2452 + }
233.2453 + else
233.2454 + break;
233.2455 + }
233.2456 + return x;
233.2457 +}
233.2458 +
233.2459 +/*----------------------------------------------------------------------
233.2460 +-- expression_4 - parse expression of level 4.
233.2461 +--
233.2462 +-- This routine parses expression of level 4 using the syntax:
233.2463 +--
233.2464 +-- <expression 4> ::= <expression 3>
233.2465 +-- <expression 4> ::= <expression 4> + <expression 3>
233.2466 +-- <expression 4> ::= <expression 4> - <expression 3>
233.2467 +-- <expression 4> ::= <expression 4> less <expression 3> */
233.2468 +
233.2469 +CODE *expression_4(MPL *mpl)
233.2470 +{ CODE *x, *y;
233.2471 + x = expression_3(mpl);
233.2472 + for (;;)
233.2473 + { if (mpl->token == T_PLUS)
233.2474 + { if (x->type == A_SYMBOLIC)
233.2475 + x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2476 + if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
233.2477 + error_preceding(mpl, "+");
233.2478 + get_token(mpl /* + */);
233.2479 + y = expression_3(mpl);
233.2480 + if (y->type == A_SYMBOLIC)
233.2481 + y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2482 + if (!(y->type == A_NUMERIC || y->type == A_FORMULA))
233.2483 + error_following(mpl, "+");
233.2484 + if (x->type == A_NUMERIC && y->type == A_FORMULA)
233.2485 + x = make_unary(mpl, O_CVTLFM, x, A_FORMULA, 0);
233.2486 + if (x->type == A_FORMULA && y->type == A_NUMERIC)
233.2487 + y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0);
233.2488 + x = make_binary(mpl, O_ADD, x, y, x->type, 0);
233.2489 + }
233.2490 + else if (mpl->token == T_MINUS)
233.2491 + { if (x->type == A_SYMBOLIC)
233.2492 + x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2493 + if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
233.2494 + error_preceding(mpl, "-");
233.2495 + get_token(mpl /* - */);
233.2496 + y = expression_3(mpl);
233.2497 + if (y->type == A_SYMBOLIC)
233.2498 + y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2499 + if (!(y->type == A_NUMERIC || y->type == A_FORMULA))
233.2500 + error_following(mpl, "-");
233.2501 + if (x->type == A_NUMERIC && y->type == A_FORMULA)
233.2502 + x = make_unary(mpl, O_CVTLFM, x, A_FORMULA, 0);
233.2503 + if (x->type == A_FORMULA && y->type == A_NUMERIC)
233.2504 + y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0);
233.2505 + x = make_binary(mpl, O_SUB, x, y, x->type, 0);
233.2506 + }
233.2507 + else if (mpl->token == T_LESS)
233.2508 + { if (x->type == A_SYMBOLIC)
233.2509 + x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2510 + if (x->type != A_NUMERIC)
233.2511 + error_preceding(mpl, "less");
233.2512 + get_token(mpl /* less */);
233.2513 + y = expression_3(mpl);
233.2514 + if (y->type == A_SYMBOLIC)
233.2515 + y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2516 + if (y->type != A_NUMERIC)
233.2517 + error_following(mpl, "less");
233.2518 + x = make_binary(mpl, O_LESS, x, y, A_NUMERIC, 0);
233.2519 + }
233.2520 + else
233.2521 + break;
233.2522 + }
233.2523 + return x;
233.2524 +}
233.2525 +
233.2526 +/*----------------------------------------------------------------------
233.2527 +-- expression_5 - parse expression of level 5.
233.2528 +--
233.2529 +-- This routine parses expression of level 5 using the syntax:
233.2530 +--
233.2531 +-- <expression 5> ::= <expression 4>
233.2532 +-- <expression 5> ::= <expression 5> & <expression 4> */
233.2533 +
233.2534 +CODE *expression_5(MPL *mpl)
233.2535 +{ CODE *x, *y;
233.2536 + x = expression_4(mpl);
233.2537 + for (;;)
233.2538 + { if (mpl->token == T_CONCAT)
233.2539 + { if (x->type == A_NUMERIC)
233.2540 + x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
233.2541 + if (x->type != A_SYMBOLIC)
233.2542 + error_preceding(mpl, "&");
233.2543 + get_token(mpl /* & */);
233.2544 + y = expression_4(mpl);
233.2545 + if (y->type == A_NUMERIC)
233.2546 + y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0);
233.2547 + if (y->type != A_SYMBOLIC)
233.2548 + error_following(mpl, "&");
233.2549 + x = make_binary(mpl, O_CONCAT, x, y, A_SYMBOLIC, 0);
233.2550 + }
233.2551 + else
233.2552 + break;
233.2553 + }
233.2554 + return x;
233.2555 +}
233.2556 +
233.2557 +/*----------------------------------------------------------------------
233.2558 +-- expression_6 - parse expression of level 6.
233.2559 +--
233.2560 +-- This routine parses expression of level 6 using the syntax:
233.2561 +--
233.2562 +-- <expression 6> ::= <expression 5>
233.2563 +-- <expression 6> ::= <expression 5> .. <expression 5>
233.2564 +-- <expression 6> ::= <expression 5> .. <expression 5> by
233.2565 +-- <expression 5> */
233.2566 +
233.2567 +CODE *expression_6(MPL *mpl)
233.2568 +{ CODE *x, *y, *z;
233.2569 + x = expression_5(mpl);
233.2570 + if (mpl->token == T_DOTS)
233.2571 + { if (x->type == A_SYMBOLIC)
233.2572 + x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2573 + if (x->type != A_NUMERIC)
233.2574 + error_preceding(mpl, "..");
233.2575 + get_token(mpl /* .. */);
233.2576 + y = expression_5(mpl);
233.2577 + if (y->type == A_SYMBOLIC)
233.2578 + y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2579 + if (y->type != A_NUMERIC)
233.2580 + error_following(mpl, "..");
233.2581 + if (mpl->token == T_BY)
233.2582 + { get_token(mpl /* by */);
233.2583 + z = expression_5(mpl);
233.2584 + if (z->type == A_SYMBOLIC)
233.2585 + z = make_unary(mpl, O_CVTNUM, z, A_NUMERIC, 0);
233.2586 + if (z->type != A_NUMERIC)
233.2587 + error_following(mpl, "by");
233.2588 + }
233.2589 + else
233.2590 + z = NULL;
233.2591 + x = make_ternary(mpl, O_DOTS, x, y, z, A_ELEMSET, 1);
233.2592 + }
233.2593 + return x;
233.2594 +}
233.2595 +
233.2596 +/*----------------------------------------------------------------------
233.2597 +-- expression_7 - parse expression of level 7.
233.2598 +--
233.2599 +-- This routine parses expression of level 7 using the syntax:
233.2600 +--
233.2601 +-- <expression 7> ::= <expression 6>
233.2602 +-- <expression 7> ::= <expression 7> cross <expression 6> */
233.2603 +
233.2604 +CODE *expression_7(MPL *mpl)
233.2605 +{ CODE *x, *y;
233.2606 + x = expression_6(mpl);
233.2607 + for (;;)
233.2608 + { if (mpl->token == T_CROSS)
233.2609 + { if (x->type != A_ELEMSET)
233.2610 + error_preceding(mpl, "cross");
233.2611 + get_token(mpl /* cross */);
233.2612 + y = expression_6(mpl);
233.2613 + if (y->type != A_ELEMSET)
233.2614 + error_following(mpl, "cross");
233.2615 + x = make_binary(mpl, O_CROSS, x, y, A_ELEMSET,
233.2616 + x->dim + y->dim);
233.2617 + }
233.2618 + else
233.2619 + break;
233.2620 + }
233.2621 + return x;
233.2622 +}
233.2623 +
233.2624 +/*----------------------------------------------------------------------
233.2625 +-- expression_8 - parse expression of level 8.
233.2626 +--
233.2627 +-- This routine parses expression of level 8 using the syntax:
233.2628 +--
233.2629 +-- <expression 8> ::= <expression 7>
233.2630 +-- <expression 8> ::= <expression 8> inter <expression 7> */
233.2631 +
233.2632 +CODE *expression_8(MPL *mpl)
233.2633 +{ CODE *x, *y;
233.2634 + x = expression_7(mpl);
233.2635 + for (;;)
233.2636 + { if (mpl->token == T_INTER)
233.2637 + { if (x->type != A_ELEMSET)
233.2638 + error_preceding(mpl, "inter");
233.2639 + get_token(mpl /* inter */);
233.2640 + y = expression_7(mpl);
233.2641 + if (y->type != A_ELEMSET)
233.2642 + error_following(mpl, "inter");
233.2643 + if (x->dim != y->dim)
233.2644 + error_dimension(mpl, "inter", x->dim, y->dim);
233.2645 + x = make_binary(mpl, O_INTER, x, y, A_ELEMSET, x->dim);
233.2646 + }
233.2647 + else
233.2648 + break;
233.2649 + }
233.2650 + return x;
233.2651 +}
233.2652 +
233.2653 +/*----------------------------------------------------------------------
233.2654 +-- expression_9 - parse expression of level 9.
233.2655 +--
233.2656 +-- This routine parses expression of level 9 using the syntax:
233.2657 +--
233.2658 +-- <expression 9> ::= <expression 8>
233.2659 +-- <expression 9> ::= <expression 9> union <expression 8>
233.2660 +-- <expression 9> ::= <expression 9> diff <expression 8>
233.2661 +-- <expression 9> ::= <expression 9> symdiff <expression 8> */
233.2662 +
233.2663 +CODE *expression_9(MPL *mpl)
233.2664 +{ CODE *x, *y;
233.2665 + x = expression_8(mpl);
233.2666 + for (;;)
233.2667 + { if (mpl->token == T_UNION)
233.2668 + { if (x->type != A_ELEMSET)
233.2669 + error_preceding(mpl, "union");
233.2670 + get_token(mpl /* union */);
233.2671 + y = expression_8(mpl);
233.2672 + if (y->type != A_ELEMSET)
233.2673 + error_following(mpl, "union");
233.2674 + if (x->dim != y->dim)
233.2675 + error_dimension(mpl, "union", x->dim, y->dim);
233.2676 + x = make_binary(mpl, O_UNION, x, y, A_ELEMSET, x->dim);
233.2677 + }
233.2678 + else if (mpl->token == T_DIFF)
233.2679 + { if (x->type != A_ELEMSET)
233.2680 + error_preceding(mpl, "diff");
233.2681 + get_token(mpl /* diff */);
233.2682 + y = expression_8(mpl);
233.2683 + if (y->type != A_ELEMSET)
233.2684 + error_following(mpl, "diff");
233.2685 + if (x->dim != y->dim)
233.2686 + error_dimension(mpl, "diff", x->dim, y->dim);
233.2687 + x = make_binary(mpl, O_DIFF, x, y, A_ELEMSET, x->dim);
233.2688 + }
233.2689 + else if (mpl->token == T_SYMDIFF)
233.2690 + { if (x->type != A_ELEMSET)
233.2691 + error_preceding(mpl, "symdiff");
233.2692 + get_token(mpl /* symdiff */);
233.2693 + y = expression_8(mpl);
233.2694 + if (y->type != A_ELEMSET)
233.2695 + error_following(mpl, "symdiff");
233.2696 + if (x->dim != y->dim)
233.2697 + error_dimension(mpl, "symdiff", x->dim, y->dim);
233.2698 + x = make_binary(mpl, O_SYMDIFF, x, y, A_ELEMSET, x->dim);
233.2699 + }
233.2700 + else
233.2701 + break;
233.2702 + }
233.2703 + return x;
233.2704 +}
233.2705 +
233.2706 +/*----------------------------------------------------------------------
233.2707 +-- expression_10 - parse expression of level 10.
233.2708 +--
233.2709 +-- This routine parses expression of level 10 using the syntax:
233.2710 +--
233.2711 +-- <expression 10> ::= <expression 9>
233.2712 +-- <expression 10> ::= <expression 9> <rho> <expression 9>
233.2713 +-- <rho> ::= < | <= | = | == | >= | > | <> | != | in | not in | ! in |
233.2714 +-- within | not within | ! within */
233.2715 +
233.2716 +CODE *expression_10(MPL *mpl)
233.2717 +{ CODE *x, *y;
233.2718 + int op = -1;
233.2719 + char opstr[16];
233.2720 + x = expression_9(mpl);
233.2721 + strcpy(opstr, "");
233.2722 + switch (mpl->token)
233.2723 + { case T_LT:
233.2724 + op = O_LT; break;
233.2725 + case T_LE:
233.2726 + op = O_LE; break;
233.2727 + case T_EQ:
233.2728 + op = O_EQ; break;
233.2729 + case T_GE:
233.2730 + op = O_GE; break;
233.2731 + case T_GT:
233.2732 + op = O_GT; break;
233.2733 + case T_NE:
233.2734 + op = O_NE; break;
233.2735 + case T_IN:
233.2736 + op = O_IN; break;
233.2737 + case T_WITHIN:
233.2738 + op = O_WITHIN; break;
233.2739 + case T_NOT:
233.2740 + strcpy(opstr, mpl->image);
233.2741 + get_token(mpl /* not | ! */);
233.2742 + if (mpl->token == T_IN)
233.2743 + op = O_NOTIN;
233.2744 + else if (mpl->token == T_WITHIN)
233.2745 + op = O_NOTWITHIN;
233.2746 + else
233.2747 + error(mpl, "invalid use of %s", opstr);
233.2748 + strcat(opstr, " ");
233.2749 + break;
233.2750 + default:
233.2751 + goto done;
233.2752 + }
233.2753 + strcat(opstr, mpl->image);
233.2754 + xassert(strlen(opstr) < sizeof(opstr));
233.2755 + switch (op)
233.2756 + { case O_EQ:
233.2757 + case O_NE:
233.2758 +#if 1 /* 02/VIII-2008 */
233.2759 + case O_LT:
233.2760 + case O_LE:
233.2761 + case O_GT:
233.2762 + case O_GE:
233.2763 +#endif
233.2764 + if (!(x->type == A_NUMERIC || x->type == A_SYMBOLIC))
233.2765 + error_preceding(mpl, opstr);
233.2766 + get_token(mpl /* <rho> */);
233.2767 + y = expression_9(mpl);
233.2768 + if (!(y->type == A_NUMERIC || y->type == A_SYMBOLIC))
233.2769 + error_following(mpl, opstr);
233.2770 + if (x->type == A_NUMERIC && y->type == A_SYMBOLIC)
233.2771 + x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
233.2772 + if (x->type == A_SYMBOLIC && y->type == A_NUMERIC)
233.2773 + y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0);
233.2774 + x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
233.2775 + break;
233.2776 +#if 0 /* 02/VIII-2008 */
233.2777 + case O_LT:
233.2778 + case O_LE:
233.2779 + case O_GT:
233.2780 + case O_GE:
233.2781 + if (x->type == A_SYMBOLIC)
233.2782 + x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2783 + if (x->type != A_NUMERIC)
233.2784 + error_preceding(mpl, opstr);
233.2785 + get_token(mpl /* <rho> */);
233.2786 + y = expression_9(mpl);
233.2787 + if (y->type == A_SYMBOLIC)
233.2788 + y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2789 + if (y->type != A_NUMERIC)
233.2790 + error_following(mpl, opstr);
233.2791 + x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
233.2792 + break;
233.2793 +#endif
233.2794 + case O_IN:
233.2795 + case O_NOTIN:
233.2796 + if (x->type == A_NUMERIC)
233.2797 + x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
233.2798 + if (x->type == A_SYMBOLIC)
233.2799 + x = make_unary(mpl, O_CVTTUP, x, A_TUPLE, 1);
233.2800 + if (x->type != A_TUPLE)
233.2801 + error_preceding(mpl, opstr);
233.2802 + get_token(mpl /* <rho> */);
233.2803 + y = expression_9(mpl);
233.2804 + if (y->type != A_ELEMSET)
233.2805 + error_following(mpl, opstr);
233.2806 + if (x->dim != y->dim)
233.2807 + error_dimension(mpl, opstr, x->dim, y->dim);
233.2808 + x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
233.2809 + break;
233.2810 + case O_WITHIN:
233.2811 + case O_NOTWITHIN:
233.2812 + if (x->type != A_ELEMSET)
233.2813 + error_preceding(mpl, opstr);
233.2814 + get_token(mpl /* <rho> */);
233.2815 + y = expression_9(mpl);
233.2816 + if (y->type != A_ELEMSET)
233.2817 + error_following(mpl, opstr);
233.2818 + if (x->dim != y->dim)
233.2819 + error_dimension(mpl, opstr, x->dim, y->dim);
233.2820 + x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
233.2821 + break;
233.2822 + default:
233.2823 + xassert(op != op);
233.2824 + }
233.2825 +done: return x;
233.2826 +}
233.2827 +
233.2828 +/*----------------------------------------------------------------------
233.2829 +-- expression_11 - parse expression of level 11.
233.2830 +--
233.2831 +-- This routine parses expression of level 11 using the syntax:
233.2832 +--
233.2833 +-- <expression 11> ::= <expression 10>
233.2834 +-- <expression 11> ::= not <expression 10>
233.2835 +-- <expression 11> ::= ! <expression 10> */
233.2836 +
233.2837 +CODE *expression_11(MPL *mpl)
233.2838 +{ CODE *x;
233.2839 + char opstr[8];
233.2840 + if (mpl->token == T_NOT)
233.2841 + { strcpy(opstr, mpl->image);
233.2842 + xassert(strlen(opstr) < sizeof(opstr));
233.2843 + get_token(mpl /* not | ! */);
233.2844 + x = expression_10(mpl);
233.2845 + if (x->type == A_SYMBOLIC)
233.2846 + x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2847 + if (x->type == A_NUMERIC)
233.2848 + x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
233.2849 + if (x->type != A_LOGICAL)
233.2850 + error_following(mpl, opstr);
233.2851 + x = make_unary(mpl, O_NOT, x, A_LOGICAL, 0);
233.2852 + }
233.2853 + else
233.2854 + x = expression_10(mpl);
233.2855 + return x;
233.2856 +}
233.2857 +
233.2858 +/*----------------------------------------------------------------------
233.2859 +-- expression_12 - parse expression of level 12.
233.2860 +--
233.2861 +-- This routine parses expression of level 12 using the syntax:
233.2862 +--
233.2863 +-- <expression 12> ::= <expression 11>
233.2864 +-- <expression 12> ::= <expression 12> and <expression 11>
233.2865 +-- <expression 12> ::= <expression 12> && <expression 11> */
233.2866 +
233.2867 +CODE *expression_12(MPL *mpl)
233.2868 +{ CODE *x, *y;
233.2869 + char opstr[8];
233.2870 + x = expression_11(mpl);
233.2871 + for (;;)
233.2872 + { if (mpl->token == T_AND)
233.2873 + { strcpy(opstr, mpl->image);
233.2874 + xassert(strlen(opstr) < sizeof(opstr));
233.2875 + if (x->type == A_SYMBOLIC)
233.2876 + x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2877 + if (x->type == A_NUMERIC)
233.2878 + x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
233.2879 + if (x->type != A_LOGICAL)
233.2880 + error_preceding(mpl, opstr);
233.2881 + get_token(mpl /* and | && */);
233.2882 + y = expression_11(mpl);
233.2883 + if (y->type == A_SYMBOLIC)
233.2884 + y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2885 + if (y->type == A_NUMERIC)
233.2886 + y = make_unary(mpl, O_CVTLOG, y, A_LOGICAL, 0);
233.2887 + if (y->type != A_LOGICAL)
233.2888 + error_following(mpl, opstr);
233.2889 + x = make_binary(mpl, O_AND, x, y, A_LOGICAL, 0);
233.2890 + }
233.2891 + else
233.2892 + break;
233.2893 + }
233.2894 + return x;
233.2895 +}
233.2896 +
233.2897 +/*----------------------------------------------------------------------
233.2898 +-- expression_13 - parse expression of level 13.
233.2899 +--
233.2900 +-- This routine parses expression of level 13 using the syntax:
233.2901 +--
233.2902 +-- <expression 13> ::= <expression 12>
233.2903 +-- <expression 13> ::= <expression 13> or <expression 12>
233.2904 +-- <expression 13> ::= <expression 13> || <expression 12> */
233.2905 +
233.2906 +CODE *expression_13(MPL *mpl)
233.2907 +{ CODE *x, *y;
233.2908 + char opstr[8];
233.2909 + x = expression_12(mpl);
233.2910 + for (;;)
233.2911 + { if (mpl->token == T_OR)
233.2912 + { strcpy(opstr, mpl->image);
233.2913 + xassert(strlen(opstr) < sizeof(opstr));
233.2914 + if (x->type == A_SYMBOLIC)
233.2915 + x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
233.2916 + if (x->type == A_NUMERIC)
233.2917 + x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
233.2918 + if (x->type != A_LOGICAL)
233.2919 + error_preceding(mpl, opstr);
233.2920 + get_token(mpl /* or | || */);
233.2921 + y = expression_12(mpl);
233.2922 + if (y->type == A_SYMBOLIC)
233.2923 + y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
233.2924 + if (y->type == A_NUMERIC)
233.2925 + y = make_unary(mpl, O_CVTLOG, y, A_LOGICAL, 0);
233.2926 + if (y->type != A_LOGICAL)
233.2927 + error_following(mpl, opstr);
233.2928 + x = make_binary(mpl, O_OR, x, y, A_LOGICAL, 0);
233.2929 + }
233.2930 + else
233.2931 + break;
233.2932 + }
233.2933 + return x;
233.2934 +}
233.2935 +
233.2936 +/*----------------------------------------------------------------------
233.2937 +-- set_statement - parse set statement.
233.2938 +--
233.2939 +-- This routine parses set statement using the syntax:
233.2940 +--
233.2941 +-- <set statement> ::= set <symbolic name> <alias> <domain>
233.2942 +-- <attributes> ;
233.2943 +-- <alias> ::= <empty>
233.2944 +-- <alias> ::= <string literal>
233.2945 +-- <domain> ::= <empty>
233.2946 +-- <domain> ::= <indexing expression>
233.2947 +-- <attributes> ::= <empty>
233.2948 +-- <attributes> ::= <attributes> , dimen <numeric literal>
233.2949 +-- <attributes> ::= <attributes> , within <expression 9>
233.2950 +-- <attributes> ::= <attributes> , := <expression 9>
233.2951 +-- <attributes> ::= <attributes> , default <expression 9>
233.2952 +--
233.2953 +-- Commae in <attributes> are optional and may be omitted anywhere. */
233.2954 +
233.2955 +SET *set_statement(MPL *mpl)
233.2956 +{ SET *set;
233.2957 + int dimen_used = 0;
233.2958 + xassert(is_keyword(mpl, "set"));
233.2959 + get_token(mpl /* set */);
233.2960 + /* symbolic name must follow the keyword 'set' */
233.2961 + if (mpl->token == T_NAME)
233.2962 + ;
233.2963 + else if (is_reserved(mpl))
233.2964 + error(mpl, "invalid use of reserved keyword %s", mpl->image);
233.2965 + else
233.2966 + error(mpl, "symbolic name missing where expected");
233.2967 + /* there must be no other object with the same name */
233.2968 + if (avl_find_node(mpl->tree, mpl->image) != NULL)
233.2969 + error(mpl, "%s multiply declared", mpl->image);
233.2970 + /* create model set */
233.2971 + set = alloc(SET);
233.2972 + set->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.2973 + strcpy(set->name, mpl->image);
233.2974 + set->alias = NULL;
233.2975 + set->dim = 0;
233.2976 + set->domain = NULL;
233.2977 + set->dimen = 0;
233.2978 + set->within = NULL;
233.2979 + set->assign = NULL;
233.2980 + set->option = NULL;
233.2981 + set->gadget = NULL;
233.2982 + set->data = 0;
233.2983 + set->array = NULL;
233.2984 + get_token(mpl /* <symbolic name> */);
233.2985 + /* parse optional alias */
233.2986 + if (mpl->token == T_STRING)
233.2987 + { set->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.2988 + strcpy(set->alias, mpl->image);
233.2989 + get_token(mpl /* <string literal> */);
233.2990 + }
233.2991 + /* parse optional indexing expression */
233.2992 + if (mpl->token == T_LBRACE)
233.2993 + { set->domain = indexing_expression(mpl);
233.2994 + set->dim = domain_arity(mpl, set->domain);
233.2995 + }
233.2996 + /* include the set name in the symbolic names table */
233.2997 + { AVLNODE *node;
233.2998 + node = avl_insert_node(mpl->tree, set->name);
233.2999 + avl_set_node_type(node, A_SET);
233.3000 + avl_set_node_link(node, (void *)set);
233.3001 + }
233.3002 + /* parse the list of optional attributes */
233.3003 + for (;;)
233.3004 + { if (mpl->token == T_COMMA)
233.3005 + get_token(mpl /* , */);
233.3006 + else if (mpl->token == T_SEMICOLON)
233.3007 + break;
233.3008 + if (is_keyword(mpl, "dimen"))
233.3009 + { /* dimension of set members */
233.3010 + int dimen;
233.3011 + get_token(mpl /* dimen */);
233.3012 + if (!(mpl->token == T_NUMBER &&
233.3013 + 1.0 <= mpl->value && mpl->value <= 20.0 &&
233.3014 + floor(mpl->value) == mpl->value))
233.3015 + error(mpl, "dimension must be integer between 1 and 20");
233.3016 + dimen = (int)(mpl->value + 0.5);
233.3017 + if (dimen_used)
233.3018 + error(mpl, "at most one dimension attribute allowed");
233.3019 + if (set->dimen > 0)
233.3020 + error(mpl, "dimension %d conflicts with dimension %d alr"
233.3021 + "eady determined", dimen, set->dimen);
233.3022 + set->dimen = dimen;
233.3023 + dimen_used = 1;
233.3024 + get_token(mpl /* <numeric literal> */);
233.3025 + }
233.3026 + else if (mpl->token == T_WITHIN || mpl->token == T_IN)
233.3027 + { /* restricting superset */
233.3028 + WITHIN *within, *temp;
233.3029 + if (mpl->token == T_IN && !mpl->as_within)
233.3030 + { warning(mpl, "keyword in understood as within");
233.3031 + mpl->as_within = 1;
233.3032 + }
233.3033 + get_token(mpl /* within */);
233.3034 + /* create new restricting superset list entry and append it
233.3035 + to the within-list */
233.3036 + within = alloc(WITHIN);
233.3037 + within->code = NULL;
233.3038 + within->next = NULL;
233.3039 + if (set->within == NULL)
233.3040 + set->within = within;
233.3041 + else
233.3042 + { for (temp = set->within; temp->next != NULL; temp =
233.3043 + temp->next);
233.3044 + temp->next = within;
233.3045 + }
233.3046 + /* parse an expression that follows 'within' */
233.3047 + within->code = expression_9(mpl);
233.3048 + if (within->code->type != A_ELEMSET)
233.3049 + error(mpl, "expression following within has invalid type"
233.3050 + );
233.3051 + xassert(within->code->dim > 0);
233.3052 + /* check/set dimension of set members */
233.3053 + if (set->dimen == 0) set->dimen = within->code->dim;
233.3054 + if (set->dimen != within->code->dim)
233.3055 + error(mpl, "set expression following within must have di"
233.3056 + "mension %d rather than %d",
233.3057 + set->dimen, within->code->dim);
233.3058 + }
233.3059 + else if (mpl->token == T_ASSIGN)
233.3060 + { /* assignment expression */
233.3061 + if (!(set->assign == NULL && set->option == NULL &&
233.3062 + set->gadget == NULL))
233.3063 +err: error(mpl, "at most one := or default/data allowed");
233.3064 + get_token(mpl /* := */);
233.3065 + /* parse an expression that follows ':=' */
233.3066 + set->assign = expression_9(mpl);
233.3067 + if (set->assign->type != A_ELEMSET)
233.3068 + error(mpl, "expression following := has invalid type");
233.3069 + xassert(set->assign->dim > 0);
233.3070 + /* check/set dimension of set members */
233.3071 + if (set->dimen == 0) set->dimen = set->assign->dim;
233.3072 + if (set->dimen != set->assign->dim)
233.3073 + error(mpl, "set expression following := must have dimens"
233.3074 + "ion %d rather than %d",
233.3075 + set->dimen, set->assign->dim);
233.3076 + }
233.3077 + else if (is_keyword(mpl, "default"))
233.3078 + { /* expression for default value */
233.3079 + if (!(set->assign == NULL && set->option == NULL)) goto err;
233.3080 + get_token(mpl /* := */);
233.3081 + /* parse an expression that follows 'default' */
233.3082 + set->option = expression_9(mpl);
233.3083 + if (set->option->type != A_ELEMSET)
233.3084 + error(mpl, "expression following default has invalid typ"
233.3085 + "e");
233.3086 + xassert(set->option->dim > 0);
233.3087 + /* check/set dimension of set members */
233.3088 + if (set->dimen == 0) set->dimen = set->option->dim;
233.3089 + if (set->dimen != set->option->dim)
233.3090 + error(mpl, "set expression following default must have d"
233.3091 + "imension %d rather than %d",
233.3092 + set->dimen, set->option->dim);
233.3093 + }
233.3094 +#if 1 /* 12/XII-2008 */
233.3095 + else if (is_keyword(mpl, "data"))
233.3096 + { /* gadget to initialize the set by data from plain set */
233.3097 + GADGET *gadget;
233.3098 + AVLNODE *node;
233.3099 + int i, k, fff[20];
233.3100 + if (!(set->assign == NULL && set->gadget == NULL)) goto err;
233.3101 + get_token(mpl /* data */);
233.3102 + set->gadget = gadget = alloc(GADGET);
233.3103 + /* set name must follow the keyword 'data' */
233.3104 + if (mpl->token == T_NAME)
233.3105 + ;
233.3106 + else if (is_reserved(mpl))
233.3107 + error(mpl, "invalid use of reserved keyword %s",
233.3108 + mpl->image);
233.3109 + else
233.3110 + error(mpl, "set name missing where expected");
233.3111 + /* find the set in the symbolic name table */
233.3112 + node = avl_find_node(mpl->tree, mpl->image);
233.3113 + if (node == NULL)
233.3114 + error(mpl, "%s not defined", mpl->image);
233.3115 + if (avl_get_node_type(node) != A_SET)
233.3116 +err1: error(mpl, "%s not a plain set", mpl->image);
233.3117 + gadget->set = avl_get_node_link(node);
233.3118 + if (gadget->set->dim != 0) goto err1;
233.3119 + if (gadget->set == set)
233.3120 + error(mpl, "set cannot be initialized by itself");
233.3121 + /* check and set dimensions */
233.3122 + if (set->dim >= gadget->set->dimen)
233.3123 +err2: error(mpl, "dimension of %s too small", mpl->image);
233.3124 + if (set->dimen == 0)
233.3125 + set->dimen = gadget->set->dimen - set->dim;
233.3126 + if (set->dim + set->dimen > gadget->set->dimen)
233.3127 + goto err2;
233.3128 + else if (set->dim + set->dimen < gadget->set->dimen)
233.3129 + error(mpl, "dimension of %s too big", mpl->image);
233.3130 + get_token(mpl /* set name */);
233.3131 + /* left parenthesis must follow the set name */
233.3132 + if (mpl->token == T_LEFT)
233.3133 + get_token(mpl /* ( */);
233.3134 + else
233.3135 + error(mpl, "left parenthesis missing where expected");
233.3136 + /* parse permutation of component numbers */
233.3137 + for (k = 0; k < gadget->set->dimen; k++) fff[k] = 0;
233.3138 + k = 0;
233.3139 + for (;;)
233.3140 + { if (mpl->token != T_NUMBER)
233.3141 + error(mpl, "component number missing where expected");
233.3142 + if (str2int(mpl->image, &i) != 0)
233.3143 +err3: error(mpl, "component number must be integer between "
233.3144 + "1 and %d", gadget->set->dimen);
233.3145 + if (!(1 <= i && i <= gadget->set->dimen)) goto err3;
233.3146 + if (fff[i-1] != 0)
233.3147 + error(mpl, "component %d multiply specified", i);
233.3148 + gadget->ind[k++] = i, fff[i-1] = 1;
233.3149 + xassert(k <= gadget->set->dimen);
233.3150 + get_token(mpl /* number */);
233.3151 + if (mpl->token == T_COMMA)
233.3152 + get_token(mpl /* , */);
233.3153 + else if (mpl->token == T_RIGHT)
233.3154 + break;
233.3155 + else
233.3156 + error(mpl, "syntax error in data attribute");
233.3157 + }
233.3158 + if (k < gadget->set->dimen)
233.3159 + error(mpl, "there are must be %d components rather than "
233.3160 + "%d", gadget->set->dimen, k);
233.3161 + get_token(mpl /* ) */);
233.3162 + }
233.3163 +#endif
233.3164 + else
233.3165 + error(mpl, "syntax error in set statement");
233.3166 + }
233.3167 + /* close the domain scope */
233.3168 + if (set->domain != NULL) close_scope(mpl, set->domain);
233.3169 + /* if dimension of set members is still unknown, set it to 1 */
233.3170 + if (set->dimen == 0) set->dimen = 1;
233.3171 + /* the set statement has been completely parsed */
233.3172 + xassert(mpl->token == T_SEMICOLON);
233.3173 + get_token(mpl /* ; */);
233.3174 + return set;
233.3175 +}
233.3176 +
233.3177 +/*----------------------------------------------------------------------
233.3178 +-- parameter_statement - parse parameter statement.
233.3179 +--
233.3180 +-- This routine parses parameter statement using the syntax:
233.3181 +--
233.3182 +-- <parameter statement> ::= param <symbolic name> <alias> <domain>
233.3183 +-- <attributes> ;
233.3184 +-- <alias> ::= <empty>
233.3185 +-- <alias> ::= <string literal>
233.3186 +-- <domain> ::= <empty>
233.3187 +-- <domain> ::= <indexing expression>
233.3188 +-- <attributes> ::= <empty>
233.3189 +-- <attributes> ::= <attributes> , integer
233.3190 +-- <attributes> ::= <attributes> , binary
233.3191 +-- <attributes> ::= <attributes> , symbolic
233.3192 +-- <attributes> ::= <attributes> , <rho> <expression 5>
233.3193 +-- <attributes> ::= <attributes> , in <expression 9>
233.3194 +-- <attributes> ::= <attributes> , := <expression 5>
233.3195 +-- <attributes> ::= <attributes> , default <expression 5>
233.3196 +-- <rho> ::= < | <= | = | == | >= | > | <> | !=
233.3197 +--
233.3198 +-- Commae in <attributes> are optional and may be omitted anywhere. */
233.3199 +
233.3200 +PARAMETER *parameter_statement(MPL *mpl)
233.3201 +{ PARAMETER *par;
233.3202 + int integer_used = 0, binary_used = 0, symbolic_used = 0;
233.3203 + xassert(is_keyword(mpl, "param"));
233.3204 + get_token(mpl /* param */);
233.3205 + /* symbolic name must follow the keyword 'param' */
233.3206 + if (mpl->token == T_NAME)
233.3207 + ;
233.3208 + else if (is_reserved(mpl))
233.3209 + error(mpl, "invalid use of reserved keyword %s", mpl->image);
233.3210 + else
233.3211 + error(mpl, "symbolic name missing where expected");
233.3212 + /* there must be no other object with the same name */
233.3213 + if (avl_find_node(mpl->tree, mpl->image) != NULL)
233.3214 + error(mpl, "%s multiply declared", mpl->image);
233.3215 + /* create model parameter */
233.3216 + par = alloc(PARAMETER);
233.3217 + par->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.3218 + strcpy(par->name, mpl->image);
233.3219 + par->alias = NULL;
233.3220 + par->dim = 0;
233.3221 + par->domain = NULL;
233.3222 + par->type = A_NUMERIC;
233.3223 + par->cond = NULL;
233.3224 + par->in = NULL;
233.3225 + par->assign = NULL;
233.3226 + par->option = NULL;
233.3227 + par->data = 0;
233.3228 + par->defval = NULL;
233.3229 + par->array = NULL;
233.3230 + get_token(mpl /* <symbolic name> */);
233.3231 + /* parse optional alias */
233.3232 + if (mpl->token == T_STRING)
233.3233 + { par->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.3234 + strcpy(par->alias, mpl->image);
233.3235 + get_token(mpl /* <string literal> */);
233.3236 + }
233.3237 + /* parse optional indexing expression */
233.3238 + if (mpl->token == T_LBRACE)
233.3239 + { par->domain = indexing_expression(mpl);
233.3240 + par->dim = domain_arity(mpl, par->domain);
233.3241 + }
233.3242 + /* include the parameter name in the symbolic names table */
233.3243 + { AVLNODE *node;
233.3244 + node = avl_insert_node(mpl->tree, par->name);
233.3245 + avl_set_node_type(node, A_PARAMETER);
233.3246 + avl_set_node_link(node, (void *)par);
233.3247 + }
233.3248 + /* parse the list of optional attributes */
233.3249 + for (;;)
233.3250 + { if (mpl->token == T_COMMA)
233.3251 + get_token(mpl /* , */);
233.3252 + else if (mpl->token == T_SEMICOLON)
233.3253 + break;
233.3254 + if (is_keyword(mpl, "integer"))
233.3255 + { if (integer_used)
233.3256 + error(mpl, "at most one integer allowed");
233.3257 + if (par->type == A_SYMBOLIC)
233.3258 + error(mpl, "symbolic parameter cannot be integer");
233.3259 + if (par->type != A_BINARY) par->type = A_INTEGER;
233.3260 + integer_used = 1;
233.3261 + get_token(mpl /* integer */);
233.3262 + }
233.3263 + else if (is_keyword(mpl, "binary"))
233.3264 +bin: { if (binary_used)
233.3265 + error(mpl, "at most one binary allowed");
233.3266 + if (par->type == A_SYMBOLIC)
233.3267 + error(mpl, "symbolic parameter cannot be binary");
233.3268 + par->type = A_BINARY;
233.3269 + binary_used = 1;
233.3270 + get_token(mpl /* binary */);
233.3271 + }
233.3272 + else if (is_keyword(mpl, "logical"))
233.3273 + { if (!mpl->as_binary)
233.3274 + { warning(mpl, "keyword logical understood as binary");
233.3275 + mpl->as_binary = 1;
233.3276 + }
233.3277 + goto bin;
233.3278 + }
233.3279 + else if (is_keyword(mpl, "symbolic"))
233.3280 + { if (symbolic_used)
233.3281 + error(mpl, "at most one symbolic allowed");
233.3282 + if (par->type != A_NUMERIC)
233.3283 + error(mpl, "integer or binary parameter cannot be symbol"
233.3284 + "ic");
233.3285 + /* the parameter may be referenced from expressions given
233.3286 + in the same parameter declaration, so its type must be
233.3287 + completed before parsing that expressions */
233.3288 + if (!(par->cond == NULL && par->in == NULL &&
233.3289 + par->assign == NULL && par->option == NULL))
233.3290 + error(mpl, "keyword symbolic must precede any other para"
233.3291 + "meter attributes");
233.3292 + par->type = A_SYMBOLIC;
233.3293 + symbolic_used = 1;
233.3294 + get_token(mpl /* symbolic */);
233.3295 + }
233.3296 + else if (mpl->token == T_LT || mpl->token == T_LE ||
233.3297 + mpl->token == T_EQ || mpl->token == T_GE ||
233.3298 + mpl->token == T_GT || mpl->token == T_NE)
233.3299 + { /* restricting condition */
233.3300 + CONDITION *cond, *temp;
233.3301 + char opstr[8];
233.3302 + /* create new restricting condition list entry and append
233.3303 + it to the conditions list */
233.3304 + cond = alloc(CONDITION);
233.3305 + switch (mpl->token)
233.3306 + { case T_LT:
233.3307 + cond->rho = O_LT, strcpy(opstr, mpl->image); break;
233.3308 + case T_LE:
233.3309 + cond->rho = O_LE, strcpy(opstr, mpl->image); break;
233.3310 + case T_EQ:
233.3311 + cond->rho = O_EQ, strcpy(opstr, mpl->image); break;
233.3312 + case T_GE:
233.3313 + cond->rho = O_GE, strcpy(opstr, mpl->image); break;
233.3314 + case T_GT:
233.3315 + cond->rho = O_GT, strcpy(opstr, mpl->image); break;
233.3316 + case T_NE:
233.3317 + cond->rho = O_NE, strcpy(opstr, mpl->image); break;
233.3318 + default:
233.3319 + xassert(mpl->token != mpl->token);
233.3320 + }
233.3321 + xassert(strlen(opstr) < sizeof(opstr));
233.3322 + cond->code = NULL;
233.3323 + cond->next = NULL;
233.3324 + if (par->cond == NULL)
233.3325 + par->cond = cond;
233.3326 + else
233.3327 + { for (temp = par->cond; temp->next != NULL; temp =
233.3328 + temp->next);
233.3329 + temp->next = cond;
233.3330 + }
233.3331 +#if 0 /* 13/VIII-2008 */
233.3332 + if (par->type == A_SYMBOLIC &&
233.3333 + !(cond->rho == O_EQ || cond->rho == O_NE))
233.3334 + error(mpl, "inequality restriction not allowed");
233.3335 +#endif
233.3336 + get_token(mpl /* rho */);
233.3337 + /* parse an expression that follows relational operator */
233.3338 + cond->code = expression_5(mpl);
233.3339 + if (!(cond->code->type == A_NUMERIC ||
233.3340 + cond->code->type == A_SYMBOLIC))
233.3341 + error(mpl, "expression following %s has invalid type",
233.3342 + opstr);
233.3343 + xassert(cond->code->dim == 0);
233.3344 + /* convert to the parameter type, if necessary */
233.3345 + if (par->type != A_SYMBOLIC && cond->code->type ==
233.3346 + A_SYMBOLIC)
233.3347 + cond->code = make_unary(mpl, O_CVTNUM, cond->code,
233.3348 + A_NUMERIC, 0);
233.3349 + if (par->type == A_SYMBOLIC && cond->code->type !=
233.3350 + A_SYMBOLIC)
233.3351 + cond->code = make_unary(mpl, O_CVTSYM, cond->code,
233.3352 + A_SYMBOLIC, 0);
233.3353 + }
233.3354 + else if (mpl->token == T_IN || mpl->token == T_WITHIN)
233.3355 + { /* restricting superset */
233.3356 + WITHIN *in, *temp;
233.3357 + if (mpl->token == T_WITHIN && !mpl->as_in)
233.3358 + { warning(mpl, "keyword within understood as in");
233.3359 + mpl->as_in = 1;
233.3360 + }
233.3361 + get_token(mpl /* in */);
233.3362 + /* create new restricting superset list entry and append it
233.3363 + to the in-list */
233.3364 + in = alloc(WITHIN);
233.3365 + in->code = NULL;
233.3366 + in->next = NULL;
233.3367 + if (par->in == NULL)
233.3368 + par->in = in;
233.3369 + else
233.3370 + { for (temp = par->in; temp->next != NULL; temp =
233.3371 + temp->next);
233.3372 + temp->next = in;
233.3373 + }
233.3374 + /* parse an expression that follows 'in' */
233.3375 + in->code = expression_9(mpl);
233.3376 + if (in->code->type != A_ELEMSET)
233.3377 + error(mpl, "expression following in has invalid type");
233.3378 + xassert(in->code->dim > 0);
233.3379 + if (in->code->dim != 1)
233.3380 + error(mpl, "set expression following in must have dimens"
233.3381 + "ion 1 rather than %d", in->code->dim);
233.3382 + }
233.3383 + else if (mpl->token == T_ASSIGN)
233.3384 + { /* assignment expression */
233.3385 + if (!(par->assign == NULL && par->option == NULL))
233.3386 +err: error(mpl, "at most one := or default allowed");
233.3387 + get_token(mpl /* := */);
233.3388 + /* parse an expression that follows ':=' */
233.3389 + par->assign = expression_5(mpl);
233.3390 + /* the expression must be of numeric/symbolic type */
233.3391 + if (!(par->assign->type == A_NUMERIC ||
233.3392 + par->assign->type == A_SYMBOLIC))
233.3393 + error(mpl, "expression following := has invalid type");
233.3394 + xassert(par->assign->dim == 0);
233.3395 + /* convert to the parameter type, if necessary */
233.3396 + if (par->type != A_SYMBOLIC && par->assign->type ==
233.3397 + A_SYMBOLIC)
233.3398 + par->assign = make_unary(mpl, O_CVTNUM, par->assign,
233.3399 + A_NUMERIC, 0);
233.3400 + if (par->type == A_SYMBOLIC && par->assign->type !=
233.3401 + A_SYMBOLIC)
233.3402 + par->assign = make_unary(mpl, O_CVTSYM, par->assign,
233.3403 + A_SYMBOLIC, 0);
233.3404 + }
233.3405 + else if (is_keyword(mpl, "default"))
233.3406 + { /* expression for default value */
233.3407 + if (!(par->assign == NULL && par->option == NULL)) goto err;
233.3408 + get_token(mpl /* default */);
233.3409 + /* parse an expression that follows 'default' */
233.3410 + par->option = expression_5(mpl);
233.3411 + if (!(par->option->type == A_NUMERIC ||
233.3412 + par->option->type == A_SYMBOLIC))
233.3413 + error(mpl, "expression following default has invalid typ"
233.3414 + "e");
233.3415 + xassert(par->option->dim == 0);
233.3416 + /* convert to the parameter type, if necessary */
233.3417 + if (par->type != A_SYMBOLIC && par->option->type ==
233.3418 + A_SYMBOLIC)
233.3419 + par->option = make_unary(mpl, O_CVTNUM, par->option,
233.3420 + A_NUMERIC, 0);
233.3421 + if (par->type == A_SYMBOLIC && par->option->type !=
233.3422 + A_SYMBOLIC)
233.3423 + par->option = make_unary(mpl, O_CVTSYM, par->option,
233.3424 + A_SYMBOLIC, 0);
233.3425 + }
233.3426 + else
233.3427 + error(mpl, "syntax error in parameter statement");
233.3428 + }
233.3429 + /* close the domain scope */
233.3430 + if (par->domain != NULL) close_scope(mpl, par->domain);
233.3431 + /* the parameter statement has been completely parsed */
233.3432 + xassert(mpl->token == T_SEMICOLON);
233.3433 + get_token(mpl /* ; */);
233.3434 + return par;
233.3435 +}
233.3436 +
233.3437 +/*----------------------------------------------------------------------
233.3438 +-- variable_statement - parse variable statement.
233.3439 +--
233.3440 +-- This routine parses variable statement using the syntax:
233.3441 +--
233.3442 +-- <variable statement> ::= var <symbolic name> <alias> <domain>
233.3443 +-- <attributes> ;
233.3444 +-- <alias> ::= <empty>
233.3445 +-- <alias> ::= <string literal>
233.3446 +-- <domain> ::= <empty>
233.3447 +-- <domain> ::= <indexing expression>
233.3448 +-- <attributes> ::= <empty>
233.3449 +-- <attributes> ::= <attributes> , integer
233.3450 +-- <attributes> ::= <attributes> , binary
233.3451 +-- <attributes> ::= <attributes> , <rho> <expression 5>
233.3452 +-- <rho> ::= >= | <= | = | ==
233.3453 +--
233.3454 +-- Commae in <attributes> are optional and may be omitted anywhere. */
233.3455 +
233.3456 +VARIABLE *variable_statement(MPL *mpl)
233.3457 +{ VARIABLE *var;
233.3458 + int integer_used = 0, binary_used = 0;
233.3459 + xassert(is_keyword(mpl, "var"));
233.3460 + if (mpl->flag_s)
233.3461 + error(mpl, "variable statement must precede solve statement");
233.3462 + get_token(mpl /* var */);
233.3463 + /* symbolic name must follow the keyword 'var' */
233.3464 + if (mpl->token == T_NAME)
233.3465 + ;
233.3466 + else if (is_reserved(mpl))
233.3467 + error(mpl, "invalid use of reserved keyword %s", mpl->image);
233.3468 + else
233.3469 + error(mpl, "symbolic name missing where expected");
233.3470 + /* there must be no other object with the same name */
233.3471 + if (avl_find_node(mpl->tree, mpl->image) != NULL)
233.3472 + error(mpl, "%s multiply declared", mpl->image);
233.3473 + /* create model variable */
233.3474 + var = alloc(VARIABLE);
233.3475 + var->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.3476 + strcpy(var->name, mpl->image);
233.3477 + var->alias = NULL;
233.3478 + var->dim = 0;
233.3479 + var->domain = NULL;
233.3480 + var->type = A_NUMERIC;
233.3481 + var->lbnd = NULL;
233.3482 + var->ubnd = NULL;
233.3483 + var->array = NULL;
233.3484 + get_token(mpl /* <symbolic name> */);
233.3485 + /* parse optional alias */
233.3486 + if (mpl->token == T_STRING)
233.3487 + { var->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.3488 + strcpy(var->alias, mpl->image);
233.3489 + get_token(mpl /* <string literal> */);
233.3490 + }
233.3491 + /* parse optional indexing expression */
233.3492 + if (mpl->token == T_LBRACE)
233.3493 + { var->domain = indexing_expression(mpl);
233.3494 + var->dim = domain_arity(mpl, var->domain);
233.3495 + }
233.3496 + /* include the variable name in the symbolic names table */
233.3497 + { AVLNODE *node;
233.3498 + node = avl_insert_node(mpl->tree, var->name);
233.3499 + avl_set_node_type(node, A_VARIABLE);
233.3500 + avl_set_node_link(node, (void *)var);
233.3501 + }
233.3502 + /* parse the list of optional attributes */
233.3503 + for (;;)
233.3504 + { if (mpl->token == T_COMMA)
233.3505 + get_token(mpl /* , */);
233.3506 + else if (mpl->token == T_SEMICOLON)
233.3507 + break;
233.3508 + if (is_keyword(mpl, "integer"))
233.3509 + { if (integer_used)
233.3510 + error(mpl, "at most one integer allowed");
233.3511 + if (var->type != A_BINARY) var->type = A_INTEGER;
233.3512 + integer_used = 1;
233.3513 + get_token(mpl /* integer */);
233.3514 + }
233.3515 + else if (is_keyword(mpl, "binary"))
233.3516 +bin: { if (binary_used)
233.3517 + error(mpl, "at most one binary allowed");
233.3518 + var->type = A_BINARY;
233.3519 + binary_used = 1;
233.3520 + get_token(mpl /* binary */);
233.3521 + }
233.3522 + else if (is_keyword(mpl, "logical"))
233.3523 + { if (!mpl->as_binary)
233.3524 + { warning(mpl, "keyword logical understood as binary");
233.3525 + mpl->as_binary = 1;
233.3526 + }
233.3527 + goto bin;
233.3528 + }
233.3529 + else if (is_keyword(mpl, "symbolic"))
233.3530 + error(mpl, "variable cannot be symbolic");
233.3531 + else if (mpl->token == T_GE)
233.3532 + { /* lower bound */
233.3533 + if (var->lbnd != NULL)
233.3534 + { if (var->lbnd == var->ubnd)
233.3535 + error(mpl, "both fixed value and lower bound not allo"
233.3536 + "wed");
233.3537 + else
233.3538 + error(mpl, "at most one lower bound allowed");
233.3539 + }
233.3540 + get_token(mpl /* >= */);
233.3541 + /* parse an expression that specifies the lower bound */
233.3542 + var->lbnd = expression_5(mpl);
233.3543 + if (var->lbnd->type == A_SYMBOLIC)
233.3544 + var->lbnd = make_unary(mpl, O_CVTNUM, var->lbnd,
233.3545 + A_NUMERIC, 0);
233.3546 + if (var->lbnd->type != A_NUMERIC)
233.3547 + error(mpl, "expression following >= has invalid type");
233.3548 + xassert(var->lbnd->dim == 0);
233.3549 + }
233.3550 + else if (mpl->token == T_LE)
233.3551 + { /* upper bound */
233.3552 + if (var->ubnd != NULL)
233.3553 + { if (var->ubnd == var->lbnd)
233.3554 + error(mpl, "both fixed value and upper bound not allo"
233.3555 + "wed");
233.3556 + else
233.3557 + error(mpl, "at most one upper bound allowed");
233.3558 + }
233.3559 + get_token(mpl /* <= */);
233.3560 + /* parse an expression that specifies the upper bound */
233.3561 + var->ubnd = expression_5(mpl);
233.3562 + if (var->ubnd->type == A_SYMBOLIC)
233.3563 + var->ubnd = make_unary(mpl, O_CVTNUM, var->ubnd,
233.3564 + A_NUMERIC, 0);
233.3565 + if (var->ubnd->type != A_NUMERIC)
233.3566 + error(mpl, "expression following <= has invalid type");
233.3567 + xassert(var->ubnd->dim == 0);
233.3568 + }
233.3569 + else if (mpl->token == T_EQ)
233.3570 + { /* fixed value */
233.3571 + char opstr[8];
233.3572 + if (!(var->lbnd == NULL && var->ubnd == NULL))
233.3573 + { if (var->lbnd == var->ubnd)
233.3574 + error(mpl, "at most one fixed value allowed");
233.3575 + else if (var->lbnd != NULL)
233.3576 + error(mpl, "both lower bound and fixed value not allo"
233.3577 + "wed");
233.3578 + else
233.3579 + error(mpl, "both upper bound and fixed value not allo"
233.3580 + "wed");
233.3581 + }
233.3582 + strcpy(opstr, mpl->image);
233.3583 + xassert(strlen(opstr) < sizeof(opstr));
233.3584 + get_token(mpl /* = | == */);
233.3585 + /* parse an expression that specifies the fixed value */
233.3586 + var->lbnd = expression_5(mpl);
233.3587 + if (var->lbnd->type == A_SYMBOLIC)
233.3588 + var->lbnd = make_unary(mpl, O_CVTNUM, var->lbnd,
233.3589 + A_NUMERIC, 0);
233.3590 + if (var->lbnd->type != A_NUMERIC)
233.3591 + error(mpl, "expression following %s has invalid type",
233.3592 + opstr);
233.3593 + xassert(var->lbnd->dim == 0);
233.3594 + /* indicate that the variable is fixed, not bounded */
233.3595 + var->ubnd = var->lbnd;
233.3596 + }
233.3597 + else if (mpl->token == T_LT || mpl->token == T_GT ||
233.3598 + mpl->token == T_NE)
233.3599 + error(mpl, "strict bound not allowed");
233.3600 + else
233.3601 + error(mpl, "syntax error in variable statement");
233.3602 + }
233.3603 + /* close the domain scope */
233.3604 + if (var->domain != NULL) close_scope(mpl, var->domain);
233.3605 + /* the variable statement has been completely parsed */
233.3606 + xassert(mpl->token == T_SEMICOLON);
233.3607 + get_token(mpl /* ; */);
233.3608 + return var;
233.3609 +}
233.3610 +
233.3611 +/*----------------------------------------------------------------------
233.3612 +-- constraint_statement - parse constraint statement.
233.3613 +--
233.3614 +-- This routine parses constraint statement using the syntax:
233.3615 +--
233.3616 +-- <constraint statement> ::= <subject to> <symbolic name> <alias>
233.3617 +-- <domain> : <constraint> ;
233.3618 +-- <subject to> ::= <empty>
233.3619 +-- <subject to> ::= subject to
233.3620 +-- <subject to> ::= subj to
233.3621 +-- <subject to> ::= s.t.
233.3622 +-- <alias> ::= <empty>
233.3623 +-- <alias> ::= <string literal>
233.3624 +-- <domain> ::= <empty>
233.3625 +-- <domain> ::= <indexing expression>
233.3626 +-- <constraint> ::= <formula> , >= <formula>
233.3627 +-- <constraint> ::= <formula> , <= <formula>
233.3628 +-- <constraint> ::= <formula> , = <formula>
233.3629 +-- <constraint> ::= <formula> , <= <formula> , <= <formula>
233.3630 +-- <constraint> ::= <formula> , >= <formula> , >= <formula>
233.3631 +-- <formula> ::= <expression 5>
233.3632 +--
233.3633 +-- Commae in <constraint> are optional and may be omitted anywhere. */
233.3634 +
233.3635 +CONSTRAINT *constraint_statement(MPL *mpl)
233.3636 +{ CONSTRAINT *con;
233.3637 + CODE *first, *second, *third;
233.3638 + int rho;
233.3639 + char opstr[8];
233.3640 + if (mpl->flag_s)
233.3641 + error(mpl, "constraint statement must precede solve statement")
233.3642 + ;
233.3643 + if (is_keyword(mpl, "subject"))
233.3644 + { get_token(mpl /* subject */);
233.3645 + if (!is_keyword(mpl, "to"))
233.3646 + error(mpl, "keyword subject to incomplete");
233.3647 + get_token(mpl /* to */);
233.3648 + }
233.3649 + else if (is_keyword(mpl, "subj"))
233.3650 + { get_token(mpl /* subj */);
233.3651 + if (!is_keyword(mpl, "to"))
233.3652 + error(mpl, "keyword subj to incomplete");
233.3653 + get_token(mpl /* to */);
233.3654 + }
233.3655 + else if (mpl->token == T_SPTP)
233.3656 + get_token(mpl /* s.t. */);
233.3657 + /* the current token must be symbolic name of constraint */
233.3658 + if (mpl->token == T_NAME)
233.3659 + ;
233.3660 + else if (is_reserved(mpl))
233.3661 + error(mpl, "invalid use of reserved keyword %s", mpl->image);
233.3662 + else
233.3663 + error(mpl, "symbolic name missing where expected");
233.3664 + /* there must be no other object with the same name */
233.3665 + if (avl_find_node(mpl->tree, mpl->image) != NULL)
233.3666 + error(mpl, "%s multiply declared", mpl->image);
233.3667 + /* create model constraint */
233.3668 + con = alloc(CONSTRAINT);
233.3669 + con->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.3670 + strcpy(con->name, mpl->image);
233.3671 + con->alias = NULL;
233.3672 + con->dim = 0;
233.3673 + con->domain = NULL;
233.3674 + con->type = A_CONSTRAINT;
233.3675 + con->code = NULL;
233.3676 + con->lbnd = NULL;
233.3677 + con->ubnd = NULL;
233.3678 + con->array = NULL;
233.3679 + get_token(mpl /* <symbolic name> */);
233.3680 + /* parse optional alias */
233.3681 + if (mpl->token == T_STRING)
233.3682 + { con->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.3683 + strcpy(con->alias, mpl->image);
233.3684 + get_token(mpl /* <string literal> */);
233.3685 + }
233.3686 + /* parse optional indexing expression */
233.3687 + if (mpl->token == T_LBRACE)
233.3688 + { con->domain = indexing_expression(mpl);
233.3689 + con->dim = domain_arity(mpl, con->domain);
233.3690 + }
233.3691 + /* include the constraint name in the symbolic names table */
233.3692 + { AVLNODE *node;
233.3693 + node = avl_insert_node(mpl->tree, con->name);
233.3694 + avl_set_node_type(node, A_CONSTRAINT);
233.3695 + avl_set_node_link(node, (void *)con);
233.3696 + }
233.3697 + /* the colon must precede the first expression */
233.3698 + if (mpl->token != T_COLON)
233.3699 + error(mpl, "colon missing where expected");
233.3700 + get_token(mpl /* : */);
233.3701 + /* parse the first expression */
233.3702 + first = expression_5(mpl);
233.3703 + if (first->type == A_SYMBOLIC)
233.3704 + first = make_unary(mpl, O_CVTNUM, first, A_NUMERIC, 0);
233.3705 + if (!(first->type == A_NUMERIC || first->type == A_FORMULA))
233.3706 + error(mpl, "expression following colon has invalid type");
233.3707 + xassert(first->dim == 0);
233.3708 + /* relational operator must follow the first expression */
233.3709 + if (mpl->token == T_COMMA) get_token(mpl /* , */);
233.3710 + switch (mpl->token)
233.3711 + { case T_LE:
233.3712 + case T_GE:
233.3713 + case T_EQ:
233.3714 + break;
233.3715 + case T_LT:
233.3716 + case T_GT:
233.3717 + case T_NE:
233.3718 + error(mpl, "strict inequality not allowed");
233.3719 + case T_SEMICOLON:
233.3720 + error(mpl, "constraint must be equality or inequality");
233.3721 + default:
233.3722 + goto err;
233.3723 + }
233.3724 + rho = mpl->token;
233.3725 + strcpy(opstr, mpl->image);
233.3726 + xassert(strlen(opstr) < sizeof(opstr));
233.3727 + get_token(mpl /* rho */);
233.3728 + /* parse the second expression */
233.3729 + second = expression_5(mpl);
233.3730 + if (second->type == A_SYMBOLIC)
233.3731 + second = make_unary(mpl, O_CVTNUM, second, A_NUMERIC, 0);
233.3732 + if (!(second->type == A_NUMERIC || second->type == A_FORMULA))
233.3733 + error(mpl, "expression following %s has invalid type", opstr);
233.3734 + xassert(second->dim == 0);
233.3735 + /* check a token that follow the second expression */
233.3736 + if (mpl->token == T_COMMA)
233.3737 + { get_token(mpl /* , */);
233.3738 + if (mpl->token == T_SEMICOLON) goto err;
233.3739 + }
233.3740 + if (mpl->token == T_LT || mpl->token == T_LE ||
233.3741 + mpl->token == T_EQ || mpl->token == T_GE ||
233.3742 + mpl->token == T_GT || mpl->token == T_NE)
233.3743 + { /* it is another relational operator, therefore the constraint
233.3744 + is double inequality */
233.3745 + if (rho == T_EQ || mpl->token != rho)
233.3746 + error(mpl, "double inequality must be ... <= ... <= ... or "
233.3747 + "... >= ... >= ...");
233.3748 + /* the first expression cannot be linear form */
233.3749 + if (first->type == A_FORMULA)
233.3750 + error(mpl, "leftmost expression in double inequality cannot"
233.3751 + " be linear form");
233.3752 + get_token(mpl /* rho */);
233.3753 + /* parse the third expression */
233.3754 + third = expression_5(mpl);
233.3755 + if (third->type == A_SYMBOLIC)
233.3756 + third = make_unary(mpl, O_CVTNUM, second, A_NUMERIC, 0);
233.3757 + if (!(third->type == A_NUMERIC || third->type == A_FORMULA))
233.3758 + error(mpl, "rightmost expression in double inequality const"
233.3759 + "raint has invalid type");
233.3760 + xassert(third->dim == 0);
233.3761 + /* the third expression also cannot be linear form */
233.3762 + if (third->type == A_FORMULA)
233.3763 + error(mpl, "rightmost expression in double inequality canno"
233.3764 + "t be linear form");
233.3765 + }
233.3766 + else
233.3767 + { /* the constraint is equality or single inequality */
233.3768 + third = NULL;
233.3769 + }
233.3770 + /* close the domain scope */
233.3771 + if (con->domain != NULL) close_scope(mpl, con->domain);
233.3772 + /* convert all expressions to linear form, if necessary */
233.3773 + if (first->type != A_FORMULA)
233.3774 + first = make_unary(mpl, O_CVTLFM, first, A_FORMULA, 0);
233.3775 + if (second->type != A_FORMULA)
233.3776 + second = make_unary(mpl, O_CVTLFM, second, A_FORMULA, 0);
233.3777 + if (third != NULL)
233.3778 + third = make_unary(mpl, O_CVTLFM, third, A_FORMULA, 0);
233.3779 + /* arrange expressions in the constraint */
233.3780 + if (third == NULL)
233.3781 + { /* the constraint is equality or single inequality */
233.3782 + switch (rho)
233.3783 + { case T_LE:
233.3784 + /* first <= second */
233.3785 + con->code = first;
233.3786 + con->lbnd = NULL;
233.3787 + con->ubnd = second;
233.3788 + break;
233.3789 + case T_GE:
233.3790 + /* first >= second */
233.3791 + con->code = first;
233.3792 + con->lbnd = second;
233.3793 + con->ubnd = NULL;
233.3794 + break;
233.3795 + case T_EQ:
233.3796 + /* first = second */
233.3797 + con->code = first;
233.3798 + con->lbnd = second;
233.3799 + con->ubnd = second;
233.3800 + break;
233.3801 + default:
233.3802 + xassert(rho != rho);
233.3803 + }
233.3804 + }
233.3805 + else
233.3806 + { /* the constraint is double inequality */
233.3807 + switch (rho)
233.3808 + { case T_LE:
233.3809 + /* first <= second <= third */
233.3810 + con->code = second;
233.3811 + con->lbnd = first;
233.3812 + con->ubnd = third;
233.3813 + break;
233.3814 + case T_GE:
233.3815 + /* first >= second >= third */
233.3816 + con->code = second;
233.3817 + con->lbnd = third;
233.3818 + con->ubnd = first;
233.3819 + break;
233.3820 + default:
233.3821 + xassert(rho != rho);
233.3822 + }
233.3823 + }
233.3824 + /* the constraint statement has been completely parsed */
233.3825 + if (mpl->token != T_SEMICOLON)
233.3826 +err: error(mpl, "syntax error in constraint statement");
233.3827 + get_token(mpl /* ; */);
233.3828 + return con;
233.3829 +}
233.3830 +
233.3831 +/*----------------------------------------------------------------------
233.3832 +-- objective_statement - parse objective statement.
233.3833 +--
233.3834 +-- This routine parses objective statement using the syntax:
233.3835 +--
233.3836 +-- <objective statement> ::= <verb> <symbolic name> <alias> <domain> :
233.3837 +-- <formula> ;
233.3838 +-- <verb> ::= minimize
233.3839 +-- <verb> ::= maximize
233.3840 +-- <alias> ::= <empty>
233.3841 +-- <alias> ::= <string literal>
233.3842 +-- <domain> ::= <empty>
233.3843 +-- <domain> ::= <indexing expression>
233.3844 +-- <formula> ::= <expression 5> */
233.3845 +
233.3846 +CONSTRAINT *objective_statement(MPL *mpl)
233.3847 +{ CONSTRAINT *obj;
233.3848 + int type;
233.3849 + if (is_keyword(mpl, "minimize"))
233.3850 + type = A_MINIMIZE;
233.3851 + else if (is_keyword(mpl, "maximize"))
233.3852 + type = A_MAXIMIZE;
233.3853 + else
233.3854 + xassert(mpl != mpl);
233.3855 + if (mpl->flag_s)
233.3856 + error(mpl, "objective statement must precede solve statement");
233.3857 + get_token(mpl /* minimize | maximize */);
233.3858 + /* symbolic name must follow the verb 'minimize' or 'maximize' */
233.3859 + if (mpl->token == T_NAME)
233.3860 + ;
233.3861 + else if (is_reserved(mpl))
233.3862 + error(mpl, "invalid use of reserved keyword %s", mpl->image);
233.3863 + else
233.3864 + error(mpl, "symbolic name missing where expected");
233.3865 + /* there must be no other object with the same name */
233.3866 + if (avl_find_node(mpl->tree, mpl->image) != NULL)
233.3867 + error(mpl, "%s multiply declared", mpl->image);
233.3868 + /* create model objective */
233.3869 + obj = alloc(CONSTRAINT);
233.3870 + obj->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.3871 + strcpy(obj->name, mpl->image);
233.3872 + obj->alias = NULL;
233.3873 + obj->dim = 0;
233.3874 + obj->domain = NULL;
233.3875 + obj->type = type;
233.3876 + obj->code = NULL;
233.3877 + obj->lbnd = NULL;
233.3878 + obj->ubnd = NULL;
233.3879 + obj->array = NULL;
233.3880 + get_token(mpl /* <symbolic name> */);
233.3881 + /* parse optional alias */
233.3882 + if (mpl->token == T_STRING)
233.3883 + { obj->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.3884 + strcpy(obj->alias, mpl->image);
233.3885 + get_token(mpl /* <string literal> */);
233.3886 + }
233.3887 + /* parse optional indexing expression */
233.3888 + if (mpl->token == T_LBRACE)
233.3889 + { obj->domain = indexing_expression(mpl);
233.3890 + obj->dim = domain_arity(mpl, obj->domain);
233.3891 + }
233.3892 + /* include the constraint name in the symbolic names table */
233.3893 + { AVLNODE *node;
233.3894 + node = avl_insert_node(mpl->tree, obj->name);
233.3895 + avl_set_node_type(node, A_CONSTRAINT);
233.3896 + avl_set_node_link(node, (void *)obj);
233.3897 + }
233.3898 + /* the colon must precede the objective expression */
233.3899 + if (mpl->token != T_COLON)
233.3900 + error(mpl, "colon missing where expected");
233.3901 + get_token(mpl /* : */);
233.3902 + /* parse the objective expression */
233.3903 + obj->code = expression_5(mpl);
233.3904 + if (obj->code->type == A_SYMBOLIC)
233.3905 + obj->code = make_unary(mpl, O_CVTNUM, obj->code, A_NUMERIC, 0);
233.3906 + if (obj->code->type == A_NUMERIC)
233.3907 + obj->code = make_unary(mpl, O_CVTLFM, obj->code, A_FORMULA, 0);
233.3908 + if (obj->code->type != A_FORMULA)
233.3909 + error(mpl, "expression following colon has invalid type");
233.3910 + xassert(obj->code->dim == 0);
233.3911 + /* close the domain scope */
233.3912 + if (obj->domain != NULL) close_scope(mpl, obj->domain);
233.3913 + /* the objective statement has been completely parsed */
233.3914 + if (mpl->token != T_SEMICOLON)
233.3915 + error(mpl, "syntax error in objective statement");
233.3916 + get_token(mpl /* ; */);
233.3917 + return obj;
233.3918 +}
233.3919 +
233.3920 +#if 1 /* 11/II-2008 */
233.3921 +/***********************************************************************
233.3922 +* table_statement - parse table statement
233.3923 +*
233.3924 +* This routine parses table statement using the syntax:
233.3925 +*
233.3926 +* <table statement> ::= <input table statement>
233.3927 +* <table statement> ::= <output table statement>
233.3928 +*
233.3929 +* <input table statement> ::=
233.3930 +* table <table name> <alias> IN <argument list> :
233.3931 +* <input set> [ <field list> ] , <input list> ;
233.3932 +* <alias> ::= <empty>
233.3933 +* <alias> ::= <string literal>
233.3934 +* <argument list> ::= <expression 5>
233.3935 +* <argument list> ::= <argument list> <expression 5>
233.3936 +* <argument list> ::= <argument list> , <expression 5>
233.3937 +* <input set> ::= <empty>
233.3938 +* <input set> ::= <set name> <-
233.3939 +* <field list> ::= <field name>
233.3940 +* <field list> ::= <field list> , <field name>
233.3941 +* <input list> ::= <input item>
233.3942 +* <input list> ::= <input list> , <input item>
233.3943 +* <input item> ::= <parameter name>
233.3944 +* <input item> ::= <parameter name> ~ <field name>
233.3945 +*
233.3946 +* <output table statement> ::=
233.3947 +* table <table name> <alias> <domain> OUT <argument list> :
233.3948 +* <output list> ;
233.3949 +* <domain> ::= <indexing expression>
233.3950 +* <output list> ::= <output item>
233.3951 +* <output list> ::= <output list> , <output item>
233.3952 +* <output item> ::= <expression 5>
233.3953 +* <output item> ::= <expression 5> ~ <field name> */
233.3954 +
233.3955 +TABLE *table_statement(MPL *mpl)
233.3956 +{ TABLE *tab;
233.3957 + TABARG *last_arg, *arg;
233.3958 + TABFLD *last_fld, *fld;
233.3959 + TABIN *last_in, *in;
233.3960 + TABOUT *last_out, *out;
233.3961 + AVLNODE *node;
233.3962 + int nflds;
233.3963 + char name[MAX_LENGTH+1];
233.3964 + xassert(is_keyword(mpl, "table"));
233.3965 + get_token(mpl /* solve */);
233.3966 + /* symbolic name must follow the keyword table */
233.3967 + if (mpl->token == T_NAME)
233.3968 + ;
233.3969 + else if (is_reserved(mpl))
233.3970 + error(mpl, "invalid use of reserved keyword %s", mpl->image);
233.3971 + else
233.3972 + error(mpl, "symbolic name missing where expected");
233.3973 + /* there must be no other object with the same name */
233.3974 + if (avl_find_node(mpl->tree, mpl->image) != NULL)
233.3975 + error(mpl, "%s multiply declared", mpl->image);
233.3976 + /* create data table */
233.3977 + tab = alloc(TABLE);
233.3978 + tab->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.3979 + strcpy(tab->name, mpl->image);
233.3980 + get_token(mpl /* <symbolic name> */);
233.3981 + /* parse optional alias */
233.3982 + if (mpl->token == T_STRING)
233.3983 + { tab->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.3984 + strcpy(tab->alias, mpl->image);
233.3985 + get_token(mpl /* <string literal> */);
233.3986 + }
233.3987 + else
233.3988 + tab->alias = NULL;
233.3989 + /* parse optional indexing expression */
233.3990 + if (mpl->token == T_LBRACE)
233.3991 + { /* this is output table */
233.3992 + tab->type = A_OUTPUT;
233.3993 + tab->u.out.domain = indexing_expression(mpl);
233.3994 + if (!is_keyword(mpl, "OUT"))
233.3995 + error(mpl, "keyword OUT missing where expected");
233.3996 + get_token(mpl /* OUT */);
233.3997 + }
233.3998 + else
233.3999 + { /* this is input table */
233.4000 + tab->type = A_INPUT;
233.4001 + if (!is_keyword(mpl, "IN"))
233.4002 + error(mpl, "keyword IN missing where expected");
233.4003 + get_token(mpl /* IN */);
233.4004 + }
233.4005 + /* parse argument list */
233.4006 + tab->arg = last_arg = NULL;
233.4007 + for (;;)
233.4008 + { /* create argument list entry */
233.4009 + arg = alloc(TABARG);
233.4010 + /* parse argument expression */
233.4011 + if (mpl->token == T_COMMA || mpl->token == T_COLON ||
233.4012 + mpl->token == T_SEMICOLON)
233.4013 + error(mpl, "argument expression missing where expected");
233.4014 + arg->code = expression_5(mpl);
233.4015 + /* convert the result to symbolic type, if necessary */
233.4016 + if (arg->code->type == A_NUMERIC)
233.4017 + arg->code =
233.4018 + make_unary(mpl, O_CVTSYM, arg->code, A_SYMBOLIC, 0);
233.4019 + /* check that now the result is of symbolic type */
233.4020 + if (arg->code->type != A_SYMBOLIC)
233.4021 + error(mpl, "argument expression has invalid type");
233.4022 + /* add the entry to the end of the list */
233.4023 + arg->next = NULL;
233.4024 + if (last_arg == NULL)
233.4025 + tab->arg = arg;
233.4026 + else
233.4027 + last_arg->next = arg;
233.4028 + last_arg = arg;
233.4029 + /* argument expression has been parsed */
233.4030 + if (mpl->token == T_COMMA)
233.4031 + get_token(mpl /* , */);
233.4032 + else if (mpl->token == T_COLON || mpl->token == T_SEMICOLON)
233.4033 + break;
233.4034 + }
233.4035 + xassert(tab->arg != NULL);
233.4036 + /* argument list must end with colon */
233.4037 + if (mpl->token == T_COLON)
233.4038 + get_token(mpl /* : */);
233.4039 + else
233.4040 + error(mpl, "colon missing where expected");
233.4041 + /* parse specific part of the table statement */
233.4042 + switch (tab->type)
233.4043 + { case A_INPUT: goto input_table;
233.4044 + case A_OUTPUT: goto output_table;
233.4045 + default: xassert(tab != tab);
233.4046 + }
233.4047 +input_table:
233.4048 + /* parse optional set name */
233.4049 + if (mpl->token == T_NAME)
233.4050 + { node = avl_find_node(mpl->tree, mpl->image);
233.4051 + if (node == NULL)
233.4052 + error(mpl, "%s not defined", mpl->image);
233.4053 + if (avl_get_node_type(node) != A_SET)
233.4054 + error(mpl, "%s not a set", mpl->image);
233.4055 + tab->u.in.set = (SET *)avl_get_node_link(node);
233.4056 + if (tab->u.in.set->assign != NULL)
233.4057 + error(mpl, "%s needs no data", mpl->image);
233.4058 + if (tab->u.in.set->dim != 0)
233.4059 + error(mpl, "%s must be a simple set", mpl->image);
233.4060 + get_token(mpl /* <symbolic name> */);
233.4061 + if (mpl->token == T_INPUT)
233.4062 + get_token(mpl /* <- */);
233.4063 + else
233.4064 + error(mpl, "delimiter <- missing where expected");
233.4065 + }
233.4066 + else if (is_reserved(mpl))
233.4067 + error(mpl, "invalid use of reserved keyword %s", mpl->image);
233.4068 + else
233.4069 + tab->u.in.set = NULL;
233.4070 + /* parse field list */
233.4071 + tab->u.in.fld = last_fld = NULL;
233.4072 + nflds = 0;
233.4073 + if (mpl->token == T_LBRACKET)
233.4074 + get_token(mpl /* [ */);
233.4075 + else
233.4076 + error(mpl, "field list missing where expected");
233.4077 + for (;;)
233.4078 + { /* create field list entry */
233.4079 + fld = alloc(TABFLD);
233.4080 + /* parse field name */
233.4081 + if (mpl->token == T_NAME)
233.4082 + ;
233.4083 + else if (is_reserved(mpl))
233.4084 + error(mpl,
233.4085 + "invalid use of reserved keyword %s", mpl->image);
233.4086 + else
233.4087 + error(mpl, "field name missing where expected");
233.4088 + fld->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
233.4089 + strcpy(fld->name, mpl->image);
233.4090 + get_token(mpl /* <symbolic name> */);
233.4091 + /* add the entry to the end of the list */
233.4092 + fld->next = NULL;
233.4093 + if (last_fld == NULL)
233.4094 + tab->u.in.fld = fld;
233.4095 + else
233.4096 + last_fld->next = fld;
233.4097 + last_fld = fld;
233.4098 + nflds++;
233.4099 + /* field name has been parsed */
233.4100 + if (mpl->token == T_COMMA)
233.4101 + get_token(mpl /* , */);
233.4102 + else if (mpl->token == T_RBRACKET)
233.4103 + break;
233.4104 + else
233.4105 + error(mpl, "syntax error in field list");
233.4106 + }
233.4107 + /* check that the set dimen is equal to the number of fields */
233.4108 + if (tab->u.in.set != NULL && tab->u.in.set->dimen != nflds)
233.4109 + error(mpl, "there must be %d field%s rather than %d",
233.4110 + tab->u.in.set->dimen, tab->u.in.set->dimen == 1 ? "" : "s",
233.4111 + nflds);
233.4112 + get_token(mpl /* ] */);
233.4113 + /* parse optional input list */
233.4114 + tab->u.in.list = last_in = NULL;
233.4115 + while (mpl->token == T_COMMA)
233.4116 + { get_token(mpl /* , */);
233.4117 + /* create input list entry */
233.4118 + in = alloc(TABIN);
233.4119 + /* parse parameter name */
233.4120 + if (mpl->token == T_NAME)
233.4121 + ;
233.4122 + else if (is_reserved(mpl))
233.4123 + error(mpl,
233.4124 + "invalid use of reserved keyword %s", mpl->image);
233.4125 + else
233.4126 + error(mpl, "parameter name missing where expected");
233.4127 + node = avl_find_node(mpl->tree, mpl->image);
233.4128 + if (node == NULL)
233.4129 + error(mpl, "%s not defined", mpl->image);
233.4130 + if (avl_get_node_type(node) != A_PARAMETER)
233.4131 + error(mpl, "%s not a parameter", mpl->image);
233.4132 + in->par = (PARAMETER *)avl_get_node_link(node);
233.4133 + if (in->par->dim != nflds)
233.4134 + error(mpl, "%s must have %d subscript%s rather than %d",
233.4135 + mpl->image, nflds, nflds == 1 ? "" : "s", in->par->dim);
233.4136 + if (in->par->assign != NULL)
233.4137 + error(mpl, "%s needs no data", mpl->image);
233.4138 + get_token(mpl /* <symbolic name> */);
233.4139 + /* parse optional field name */
233.4140 + if (mpl->token == T_TILDE)
233.4141 + { get_token(mpl /* ~ */);
233.4142 + /* parse field name */
233.4143 + if (mpl->token == T_NAME)
233.4144 + ;
233.4145 + else if (is_reserved(mpl))
233.4146 + error(mpl,
233.4147 + "invalid use of reserved keyword %s", mpl->image);
233.4148 + else
233.4149 + error(mpl, "field name missing where expected");
233.4150 + xassert(strlen(mpl->image) < sizeof(name));
233.4151 + strcpy(name, mpl->image);
233.4152 + get_token(mpl /* <symbolic name> */);
233.4153 + }
233.4154 + else
233.4155 + { /* field name is the same as the parameter name */
233.4156 + xassert(strlen(in->par->name) < sizeof(name));
233.4157 + strcpy(name, in->par->name);
233.4158 + }
233.4159 + /* assign field name */
233.4160 + in->name = dmp_get_atomv(mpl->pool, strlen(name)+1);
233.4161 + strcpy(in->name, name);
233.4162 + /* add the entry to the end of the list */
233.4163 + in->next = NULL;
233.4164 + if (last_in == NULL)
233.4165 + tab->u.in.list = in;
233.4166 + else
233.4167 + last_in->next = in;
233.4168 + last_in = in;
233.4169 + }
233.4170 + goto end_of_table;
233.4171 +output_table:
233.4172 + /* parse output list */
233.4173 + tab->u.out.list = last_out = NULL;
233.4174 + for (;;)
233.4175 + { /* create output list entry */
233.4176 + out = alloc(TABOUT);
233.4177 + /* parse expression */
233.4178 + if (mpl->token == T_COMMA || mpl->token == T_SEMICOLON)
233.4179 + error(mpl, "expression missing where expected");
233.4180 + if (mpl->token == T_NAME)
233.4181 + { xassert(strlen(mpl->image) < sizeof(name));
233.4182 + strcpy(name, mpl->image);
233.4183 + }
233.4184 + else
233.4185 + name[0] = '\0';
233.4186 + out->code = expression_5(mpl);
233.4187 + /* parse optional field name */
233.4188 + if (mpl->token == T_TILDE)
233.4189 + { get_token(mpl /* ~ */);
233.4190 + /* parse field name */
233.4191 + if (mpl->token == T_NAME)
233.4192 + ;
233.4193 + else if (is_reserved(mpl))
233.4194 + error(mpl,
233.4195 + "invalid use of reserved keyword %s", mpl->image);
233.4196 + else
233.4197 + error(mpl, "field name missing where expected");
233.4198 + xassert(strlen(mpl->image) < sizeof(name));
233.4199 + strcpy(name, mpl->image);
233.4200 + get_token(mpl /* <symbolic name> */);
233.4201 + }
233.4202 + /* assign field name */
233.4203 + if (name[0] == '\0')
233.4204 + error(mpl, "field name required");
233.4205 + out->name = dmp_get_atomv(mpl->pool, strlen(name)+1);
233.4206 + strcpy(out->name, name);
233.4207 + /* add the entry to the end of the list */
233.4208 + out->next = NULL;
233.4209 + if (last_out == NULL)
233.4210 + tab->u.out.list = out;
233.4211 + else
233.4212 + last_out->next = out;
233.4213 + last_out = out;
233.4214 + /* output item has been parsed */
233.4215 + if (mpl->token == T_COMMA)
233.4216 + get_token(mpl /* , */);
233.4217 + else if (mpl->token == T_SEMICOLON)
233.4218 + break;
233.4219 + else
233.4220 + error(mpl, "syntax error in output list");
233.4221 + }
233.4222 + /* close the domain scope */
233.4223 + close_scope(mpl,tab->u.out.domain);
233.4224 +end_of_table:
233.4225 + /* the table statement must end with semicolon */
233.4226 + if (mpl->token != T_SEMICOLON)
233.4227 + error(mpl, "syntax error in table statement");
233.4228 + get_token(mpl /* ; */);
233.4229 + return tab;
233.4230 +}
233.4231 +#endif
233.4232 +
233.4233 +/*----------------------------------------------------------------------
233.4234 +-- solve_statement - parse solve statement.
233.4235 +--
233.4236 +-- This routine parses solve statement using the syntax:
233.4237 +--
233.4238 +-- <solve statement> ::= solve ;
233.4239 +--
233.4240 +-- The solve statement can be used at most once. */
233.4241 +
233.4242 +void *solve_statement(MPL *mpl)
233.4243 +{ xassert(is_keyword(mpl, "solve"));
233.4244 + if (mpl->flag_s)
233.4245 + error(mpl, "at most one solve statement allowed");
233.4246 + mpl->flag_s = 1;
233.4247 + get_token(mpl /* solve */);
233.4248 + /* semicolon must follow solve statement */
233.4249 + if (mpl->token != T_SEMICOLON)
233.4250 + error(mpl, "syntax error in solve statement");
233.4251 + get_token(mpl /* ; */);
233.4252 + return NULL;
233.4253 +}
233.4254 +
233.4255 +/*----------------------------------------------------------------------
233.4256 +-- check_statement - parse check statement.
233.4257 +--
233.4258 +-- This routine parses check statement using the syntax:
233.4259 +--
233.4260 +-- <check statement> ::= check <domain> : <expression 13> ;
233.4261 +-- <domain> ::= <empty>
233.4262 +-- <domain> ::= <indexing expression>
233.4263 +--
233.4264 +-- If <domain> is omitted, colon following it may also be omitted. */
233.4265 +
233.4266 +CHECK *check_statement(MPL *mpl)
233.4267 +{ CHECK *chk;
233.4268 + xassert(is_keyword(mpl, "check"));
233.4269 + /* create check descriptor */
233.4270 + chk = alloc(CHECK);
233.4271 + chk->domain = NULL;
233.4272 + chk->code = NULL;
233.4273 + get_token(mpl /* check */);
233.4274 + /* parse optional indexing expression */
233.4275 + if (mpl->token == T_LBRACE)
233.4276 + { chk->domain = indexing_expression(mpl);
233.4277 +#if 0
233.4278 + if (mpl->token != T_COLON)
233.4279 + error(mpl, "colon missing where expected");
233.4280 +#endif
233.4281 + }
233.4282 + /* skip optional colon */
233.4283 + if (mpl->token == T_COLON) get_token(mpl /* : */);
233.4284 + /* parse logical expression */
233.4285 + chk->code = expression_13(mpl);
233.4286 + if (chk->code->type != A_LOGICAL)
233.4287 + error(mpl, "expression has invalid type");
233.4288 + xassert(chk->code->dim == 0);
233.4289 + /* close the domain scope */
233.4290 + if (chk->domain != NULL) close_scope(mpl, chk->domain);
233.4291 + /* the check statement has been completely parsed */
233.4292 + if (mpl->token != T_SEMICOLON)
233.4293 + error(mpl, "syntax error in check statement");
233.4294 + get_token(mpl /* ; */);
233.4295 + return chk;
233.4296 +}
233.4297 +
233.4298 +#if 1 /* 15/V-2010 */
233.4299 +/*----------------------------------------------------------------------
233.4300 +-- display_statement - parse display statement.
233.4301 +--
233.4302 +-- This routine parses display statement using the syntax:
233.4303 +--
233.4304 +-- <display statement> ::= display <domain> : <display list> ;
233.4305 +-- <display statement> ::= display <domain> <display list> ;
233.4306 +-- <domain> ::= <empty>
233.4307 +-- <domain> ::= <indexing expression>
233.4308 +-- <display list> ::= <display entry>
233.4309 +-- <display list> ::= <display list> , <display entry>
233.4310 +-- <display entry> ::= <dummy index>
233.4311 +-- <display entry> ::= <set name>
233.4312 +-- <display entry> ::= <set name> [ <subscript list> ]
233.4313 +-- <display entry> ::= <parameter name>
233.4314 +-- <display entry> ::= <parameter name> [ <subscript list> ]
233.4315 +-- <display entry> ::= <variable name>
233.4316 +-- <display entry> ::= <variable name> [ <subscript list> ]
233.4317 +-- <display entry> ::= <constraint name>
233.4318 +-- <display entry> ::= <constraint name> [ <subscript list> ]
233.4319 +-- <display entry> ::= <expression 13> */
233.4320 +
233.4321 +DISPLAY *display_statement(MPL *mpl)
233.4322 +{ DISPLAY *dpy;
233.4323 + DISPLAY1 *entry, *last_entry;
233.4324 + xassert(is_keyword(mpl, "display"));
233.4325 + /* create display descriptor */
233.4326 + dpy = alloc(DISPLAY);
233.4327 + dpy->domain = NULL;
233.4328 + dpy->list = last_entry = NULL;
233.4329 + get_token(mpl /* display */);
233.4330 + /* parse optional indexing expression */
233.4331 + if (mpl->token == T_LBRACE)
233.4332 + dpy->domain = indexing_expression(mpl);
233.4333 + /* skip optional colon */
233.4334 + if (mpl->token == T_COLON) get_token(mpl /* : */);
233.4335 + /* parse display list */
233.4336 + for (;;)
233.4337 + { /* create new display entry */
233.4338 + entry = alloc(DISPLAY1);
233.4339 + entry->type = 0;
233.4340 + entry->next = NULL;
233.4341 + /* and append it to the display list */
233.4342 + if (dpy->list == NULL)
233.4343 + dpy->list = entry;
233.4344 + else
233.4345 + last_entry->next = entry;
233.4346 + last_entry = entry;
233.4347 + /* parse display entry */
233.4348 + if (mpl->token == T_NAME)
233.4349 + { AVLNODE *node;
233.4350 + int next_token;
233.4351 + get_token(mpl /* <symbolic name> */);
233.4352 + next_token = mpl->token;
233.4353 + unget_token(mpl);
233.4354 + if (!(next_token == T_COMMA || next_token == T_SEMICOLON))
233.4355 + { /* symbolic name begins expression */
233.4356 + goto expr;
233.4357 + }
233.4358 + /* display entry is dummy index or model object */
233.4359 + node = avl_find_node(mpl->tree, mpl->image);
233.4360 + if (node == NULL)
233.4361 + error(mpl, "%s not defined", mpl->image);
233.4362 + entry->type = avl_get_node_type(node);
233.4363 + switch (avl_get_node_type(node))
233.4364 + { case A_INDEX:
233.4365 + entry->u.slot =
233.4366 + (DOMAIN_SLOT *)avl_get_node_link(node);
233.4367 + break;
233.4368 + case A_SET:
233.4369 + entry->u.set = (SET *)avl_get_node_link(node);
233.4370 + break;
233.4371 + case A_PARAMETER:
233.4372 + entry->u.par = (PARAMETER *)avl_get_node_link(node);
233.4373 + break;
233.4374 + case A_VARIABLE:
233.4375 + entry->u.var = (VARIABLE *)avl_get_node_link(node);
233.4376 + if (!mpl->flag_s)
233.4377 + error(mpl, "invalid reference to variable %s above"
233.4378 + " solve statement", entry->u.var->name);
233.4379 + break;
233.4380 + case A_CONSTRAINT:
233.4381 + entry->u.con = (CONSTRAINT *)avl_get_node_link(node);
233.4382 + if (!mpl->flag_s)
233.4383 + error(mpl, "invalid reference to %s %s above solve"
233.4384 + " statement",
233.4385 + entry->u.con->type == A_CONSTRAINT ?
233.4386 + "constraint" : "objective", entry->u.con->name);
233.4387 + break;
233.4388 + default:
233.4389 + xassert(node != node);
233.4390 + }
233.4391 + get_token(mpl /* <symbolic name> */);
233.4392 + }
233.4393 + else
233.4394 +expr: { /* display entry is expression */
233.4395 + entry->type = A_EXPRESSION;
233.4396 + entry->u.code = expression_13(mpl);
233.4397 + }
233.4398 + /* check a token that follows the entry parsed */
233.4399 + if (mpl->token == T_COMMA)
233.4400 + get_token(mpl /* , */);
233.4401 + else
233.4402 + break;
233.4403 + }
233.4404 + /* close the domain scope */
233.4405 + if (dpy->domain != NULL) close_scope(mpl, dpy->domain);
233.4406 + /* the display statement has been completely parsed */
233.4407 + if (mpl->token != T_SEMICOLON)
233.4408 + error(mpl, "syntax error in display statement");
233.4409 + get_token(mpl /* ; */);
233.4410 + return dpy;
233.4411 +}
233.4412 +#endif
233.4413 +
233.4414 +/*----------------------------------------------------------------------
233.4415 +-- printf_statement - parse printf statement.
233.4416 +--
233.4417 +-- This routine parses print statement using the syntax:
233.4418 +--
233.4419 +-- <printf statement> ::= <printf clause> ;
233.4420 +-- <printf statement> ::= <printf clause> > <file name> ;
233.4421 +-- <printf statement> ::= <printf clause> >> <file name> ;
233.4422 +-- <printf clause> ::= printf <domain> : <format> <printf list>
233.4423 +-- <printf clause> ::= printf <domain> <format> <printf list>
233.4424 +-- <domain> ::= <empty>
233.4425 +-- <domain> ::= <indexing expression>
233.4426 +-- <format> ::= <expression 5>
233.4427 +-- <printf list> ::= <empty>
233.4428 +-- <printf list> ::= <printf list> , <printf entry>
233.4429 +-- <printf entry> ::= <expression 9>
233.4430 +-- <file name> ::= <expression 5> */
233.4431 +
233.4432 +PRINTF *printf_statement(MPL *mpl)
233.4433 +{ PRINTF *prt;
233.4434 + PRINTF1 *entry, *last_entry;
233.4435 + xassert(is_keyword(mpl, "printf"));
233.4436 + /* create printf descriptor */
233.4437 + prt = alloc(PRINTF);
233.4438 + prt->domain = NULL;
233.4439 + prt->fmt = NULL;
233.4440 + prt->list = last_entry = NULL;
233.4441 + get_token(mpl /* printf */);
233.4442 + /* parse optional indexing expression */
233.4443 + if (mpl->token == T_LBRACE)
233.4444 + { prt->domain = indexing_expression(mpl);
233.4445 +#if 0
233.4446 + if (mpl->token != T_COLON)
233.4447 + error(mpl, "colon missing where expected");
233.4448 +#endif
233.4449 + }
233.4450 + /* skip optional colon */
233.4451 + if (mpl->token == T_COLON) get_token(mpl /* : */);
233.4452 + /* parse expression for format string */
233.4453 + prt->fmt = expression_5(mpl);
233.4454 + /* convert it to symbolic type, if necessary */
233.4455 + if (prt->fmt->type == A_NUMERIC)
233.4456 + prt->fmt = make_unary(mpl, O_CVTSYM, prt->fmt, A_SYMBOLIC, 0);
233.4457 + /* check that now the expression is of symbolic type */
233.4458 + if (prt->fmt->type != A_SYMBOLIC)
233.4459 + error(mpl, "format expression has invalid type");
233.4460 + /* parse printf list */
233.4461 + while (mpl->token == T_COMMA)
233.4462 + { get_token(mpl /* , */);
233.4463 + /* create new printf entry */
233.4464 + entry = alloc(PRINTF1);
233.4465 + entry->code = NULL;
233.4466 + entry->next = NULL;
233.4467 + /* and append it to the printf list */
233.4468 + if (prt->list == NULL)
233.4469 + prt->list = entry;
233.4470 + else
233.4471 + last_entry->next = entry;
233.4472 + last_entry = entry;
233.4473 + /* parse printf entry */
233.4474 + entry->code = expression_9(mpl);
233.4475 + if (!(entry->code->type == A_NUMERIC ||
233.4476 + entry->code->type == A_SYMBOLIC ||
233.4477 + entry->code->type == A_LOGICAL))
233.4478 + error(mpl, "only numeric, symbolic, or logical expression a"
233.4479 + "llowed");
233.4480 + }
233.4481 + /* close the domain scope */
233.4482 + if (prt->domain != NULL) close_scope(mpl, prt->domain);
233.4483 +#if 1 /* 14/VII-2006 */
233.4484 + /* parse optional redirection */
233.4485 + prt->fname = NULL, prt->app = 0;
233.4486 + if (mpl->token == T_GT || mpl->token == T_APPEND)
233.4487 + { prt->app = (mpl->token == T_APPEND);
233.4488 + get_token(mpl /* > or >> */);
233.4489 + /* parse expression for file name string */
233.4490 + prt->fname = expression_5(mpl);
233.4491 + /* convert it to symbolic type, if necessary */
233.4492 + if (prt->fname->type == A_NUMERIC)
233.4493 + prt->fname = make_unary(mpl, O_CVTSYM, prt->fname,
233.4494 + A_SYMBOLIC, 0);
233.4495 + /* check that now the expression is of symbolic type */
233.4496 + if (prt->fname->type != A_SYMBOLIC)
233.4497 + error(mpl, "file name expression has invalid type");
233.4498 + }
233.4499 +#endif
233.4500 + /* the printf statement has been completely parsed */
233.4501 + if (mpl->token != T_SEMICOLON)
233.4502 + error(mpl, "syntax error in printf statement");
233.4503 + get_token(mpl /* ; */);
233.4504 + return prt;
233.4505 +}
233.4506 +
233.4507 +/*----------------------------------------------------------------------
233.4508 +-- for_statement - parse for statement.
233.4509 +--
233.4510 +-- This routine parses for statement using the syntax:
233.4511 +--
233.4512 +-- <for statement> ::= for <domain> <statement>
233.4513 +-- <for statement> ::= for <domain> { <statement list> }
233.4514 +-- <domain> ::= <indexing expression>
233.4515 +-- <statement list> ::= <empty>
233.4516 +-- <statement list> ::= <statement list> <statement>
233.4517 +-- <statement> ::= <check statement>
233.4518 +-- <statement> ::= <display statement>
233.4519 +-- <statement> ::= <printf statement>
233.4520 +-- <statement> ::= <for statement> */
233.4521 +
233.4522 +FOR *for_statement(MPL *mpl)
233.4523 +{ FOR *fur;
233.4524 + STATEMENT *stmt, *last_stmt;
233.4525 + xassert(is_keyword(mpl, "for"));
233.4526 + /* create for descriptor */
233.4527 + fur = alloc(FOR);
233.4528 + fur->domain = NULL;
233.4529 + fur->list = last_stmt = NULL;
233.4530 + get_token(mpl /* for */);
233.4531 + /* parse indexing expression */
233.4532 + if (mpl->token != T_LBRACE)
233.4533 + error(mpl, "indexing expression missing where expected");
233.4534 + fur->domain = indexing_expression(mpl);
233.4535 + /* skip optional colon */
233.4536 + if (mpl->token == T_COLON) get_token(mpl /* : */);
233.4537 + /* parse for statement body */
233.4538 + if (mpl->token != T_LBRACE)
233.4539 + { /* parse simple statement */
233.4540 + fur->list = simple_statement(mpl, 1);
233.4541 + }
233.4542 + else
233.4543 + { /* parse compound statement */
233.4544 + get_token(mpl /* { */);
233.4545 + while (mpl->token != T_RBRACE)
233.4546 + { /* parse statement */
233.4547 + stmt = simple_statement(mpl, 1);
233.4548 + /* and append it to the end of the statement list */
233.4549 + if (last_stmt == NULL)
233.4550 + fur->list = stmt;
233.4551 + else
233.4552 + last_stmt->next = stmt;
233.4553 + last_stmt = stmt;
233.4554 + }
233.4555 + get_token(mpl /* } */);
233.4556 + }
233.4557 + /* close the domain scope */
233.4558 + xassert(fur->domain != NULL);
233.4559 + close_scope(mpl, fur->domain);
233.4560 + /* the for statement has been completely parsed */
233.4561 + return fur;
233.4562 +}
233.4563 +
233.4564 +/*----------------------------------------------------------------------
233.4565 +-- end_statement - parse end statement.
233.4566 +--
233.4567 +-- This routine parses end statement using the syntax:
233.4568 +--
233.4569 +-- <end statement> ::= end ; <eof> */
233.4570 +
233.4571 +void end_statement(MPL *mpl)
233.4572 +{ if (!mpl->flag_d && is_keyword(mpl, "end") ||
233.4573 + mpl->flag_d && is_literal(mpl, "end"))
233.4574 + { get_token(mpl /* end */);
233.4575 + if (mpl->token == T_SEMICOLON)
233.4576 + get_token(mpl /* ; */);
233.4577 + else
233.4578 + warning(mpl, "no semicolon following end statement; missing"
233.4579 + " semicolon inserted");
233.4580 + }
233.4581 + else
233.4582 + warning(mpl, "unexpected end of file; missing end statement in"
233.4583 + "serted");
233.4584 + if (mpl->token != T_EOF)
233.4585 + warning(mpl, "some text detected beyond end statement; text ig"
233.4586 + "nored");
233.4587 + return;
233.4588 +}
233.4589 +
233.4590 +/*----------------------------------------------------------------------
233.4591 +-- simple_statement - parse simple statement.
233.4592 +--
233.4593 +-- This routine parses simple statement using the syntax:
233.4594 +--
233.4595 +-- <statement> ::= <set statement>
233.4596 +-- <statement> ::= <parameter statement>
233.4597 +-- <statement> ::= <variable statement>
233.4598 +-- <statement> ::= <constraint statement>
233.4599 +-- <statement> ::= <objective statement>
233.4600 +-- <statement> ::= <solve statement>
233.4601 +-- <statement> ::= <check statement>
233.4602 +-- <statement> ::= <display statement>
233.4603 +-- <statement> ::= <printf statement>
233.4604 +-- <statement> ::= <for statement>
233.4605 +--
233.4606 +-- If the flag spec is set, some statements cannot be used. */
233.4607 +
233.4608 +STATEMENT *simple_statement(MPL *mpl, int spec)
233.4609 +{ STATEMENT *stmt;
233.4610 + stmt = alloc(STATEMENT);
233.4611 + stmt->line = mpl->line;
233.4612 + stmt->next = NULL;
233.4613 + if (is_keyword(mpl, "set"))
233.4614 + { if (spec)
233.4615 + error(mpl, "set statement not allowed here");
233.4616 + stmt->type = A_SET;
233.4617 + stmt->u.set = set_statement(mpl);
233.4618 + }
233.4619 + else if (is_keyword(mpl, "param"))
233.4620 + { if (spec)
233.4621 + error(mpl, "parameter statement not allowed here");
233.4622 + stmt->type = A_PARAMETER;
233.4623 + stmt->u.par = parameter_statement(mpl);
233.4624 + }
233.4625 + else if (is_keyword(mpl, "var"))
233.4626 + { if (spec)
233.4627 + error(mpl, "variable statement not allowed here");
233.4628 + stmt->type = A_VARIABLE;
233.4629 + stmt->u.var = variable_statement(mpl);
233.4630 + }
233.4631 + else if (is_keyword(mpl, "subject") ||
233.4632 + is_keyword(mpl, "subj") ||
233.4633 + mpl->token == T_SPTP)
233.4634 + { if (spec)
233.4635 + error(mpl, "constraint statement not allowed here");
233.4636 + stmt->type = A_CONSTRAINT;
233.4637 + stmt->u.con = constraint_statement(mpl);
233.4638 + }
233.4639 + else if (is_keyword(mpl, "minimize") ||
233.4640 + is_keyword(mpl, "maximize"))
233.4641 + { if (spec)
233.4642 + error(mpl, "objective statement not allowed here");
233.4643 + stmt->type = A_CONSTRAINT;
233.4644 + stmt->u.con = objective_statement(mpl);
233.4645 + }
233.4646 +#if 1 /* 11/II-2008 */
233.4647 + else if (is_keyword(mpl, "table"))
233.4648 + { if (spec)
233.4649 + error(mpl, "table statement not allowed here");
233.4650 + stmt->type = A_TABLE;
233.4651 + stmt->u.tab = table_statement(mpl);
233.4652 + }
233.4653 +#endif
233.4654 + else if (is_keyword(mpl, "solve"))
233.4655 + { if (spec)
233.4656 + error(mpl, "solve statement not allowed here");
233.4657 + stmt->type = A_SOLVE;
233.4658 + stmt->u.slv = solve_statement(mpl);
233.4659 + }
233.4660 + else if (is_keyword(mpl, "check"))
233.4661 + { stmt->type = A_CHECK;
233.4662 + stmt->u.chk = check_statement(mpl);
233.4663 + }
233.4664 + else if (is_keyword(mpl, "display"))
233.4665 + { stmt->type = A_DISPLAY;
233.4666 + stmt->u.dpy = display_statement(mpl);
233.4667 + }
233.4668 + else if (is_keyword(mpl, "printf"))
233.4669 + { stmt->type = A_PRINTF;
233.4670 + stmt->u.prt = printf_statement(mpl);
233.4671 + }
233.4672 + else if (is_keyword(mpl, "for"))
233.4673 + { stmt->type = A_FOR;
233.4674 + stmt->u.fur = for_statement(mpl);
233.4675 + }
233.4676 + else if (mpl->token == T_NAME)
233.4677 + { if (spec)
233.4678 + error(mpl, "constraint statement not allowed here");
233.4679 + stmt->type = A_CONSTRAINT;
233.4680 + stmt->u.con = constraint_statement(mpl);
233.4681 + }
233.4682 + else if (is_reserved(mpl))
233.4683 + error(mpl, "invalid use of reserved keyword %s", mpl->image);
233.4684 + else
233.4685 + error(mpl, "syntax error in model section");
233.4686 + return stmt;
233.4687 +}
233.4688 +
233.4689 +/*----------------------------------------------------------------------
233.4690 +-- model_section - parse model section.
233.4691 +--
233.4692 +-- This routine parses model section using the syntax:
233.4693 +--
233.4694 +-- <model section> ::= <empty>
233.4695 +-- <model section> ::= <model section> <statement>
233.4696 +--
233.4697 +-- Parsing model section is terminated by either the keyword 'data', or
233.4698 +-- the keyword 'end', or the end of file. */
233.4699 +
233.4700 +void model_section(MPL *mpl)
233.4701 +{ STATEMENT *stmt, *last_stmt;
233.4702 + xassert(mpl->model == NULL);
233.4703 + last_stmt = NULL;
233.4704 + while (!(mpl->token == T_EOF || is_keyword(mpl, "data") ||
233.4705 + is_keyword(mpl, "end")))
233.4706 + { /* parse statement */
233.4707 + stmt = simple_statement(mpl, 0);
233.4708 + /* and append it to the end of the statement list */
233.4709 + if (last_stmt == NULL)
233.4710 + mpl->model = stmt;
233.4711 + else
233.4712 + last_stmt->next = stmt;
233.4713 + last_stmt = stmt;
233.4714 + }
233.4715 + return;
233.4716 +}
233.4717 +
233.4718 +/* eof */
234.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
234.2 +++ b/src/glpmpl02.c Mon Dec 06 13:09:21 2010 +0100
234.3 @@ -0,0 +1,1205 @@
234.4 +/* glpmpl02.c */
234.5 +
234.6 +/***********************************************************************
234.7 +* This code is part of GLPK (GNU Linear Programming Kit).
234.8 +*
234.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
234.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
234.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
234.12 +* E-mail: <mao@gnu.org>.
234.13 +*
234.14 +* GLPK is free software: you can redistribute it and/or modify it
234.15 +* under the terms of the GNU General Public License as published by
234.16 +* the Free Software Foundation, either version 3 of the License, or
234.17 +* (at your option) any later version.
234.18 +*
234.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
234.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
234.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
234.22 +* License for more details.
234.23 +*
234.24 +* You should have received a copy of the GNU General Public License
234.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
234.26 +***********************************************************************/
234.27 +
234.28 +#define _GLPSTD_STDIO
234.29 +#include "glpenv.h"
234.30 +#include "glpmpl.h"
234.31 +
234.32 +/**********************************************************************/
234.33 +/* * * PROCESSING DATA SECTION * * */
234.34 +/**********************************************************************/
234.35 +
234.36 +/*----------------------------------------------------------------------
234.37 +-- create_slice - create slice.
234.38 +--
234.39 +-- This routine creates a slice, which initially has no components. */
234.40 +
234.41 +SLICE *create_slice(MPL *mpl)
234.42 +{ SLICE *slice;
234.43 + xassert(mpl == mpl);
234.44 + slice = NULL;
234.45 + return slice;
234.46 +}
234.47 +
234.48 +/*----------------------------------------------------------------------
234.49 +-- expand_slice - append new component to slice.
234.50 +--
234.51 +-- This routine expands slice appending to it either a given symbol or
234.52 +-- null component, which becomes the last component of the slice. */
234.53 +
234.54 +SLICE *expand_slice
234.55 +( MPL *mpl,
234.56 + SLICE *slice, /* destroyed */
234.57 + SYMBOL *sym /* destroyed */
234.58 +)
234.59 +{ SLICE *tail, *temp;
234.60 + /* create a new component */
234.61 + tail = dmp_get_atom(mpl->tuples, sizeof(SLICE));
234.62 + tail->sym = sym;
234.63 + tail->next = NULL;
234.64 + /* and append it to the component list */
234.65 + if (slice == NULL)
234.66 + slice = tail;
234.67 + else
234.68 + { for (temp = slice; temp->next != NULL; temp = temp->next);
234.69 + temp->next = tail;
234.70 + }
234.71 + return slice;
234.72 +}
234.73 +
234.74 +/*----------------------------------------------------------------------
234.75 +-- slice_dimen - determine dimension of slice.
234.76 +--
234.77 +-- This routine returns dimension of slice, which is number of all its
234.78 +-- components including null ones. */
234.79 +
234.80 +int slice_dimen
234.81 +( MPL *mpl,
234.82 + SLICE *slice /* not changed */
234.83 +)
234.84 +{ SLICE *temp;
234.85 + int dim;
234.86 + xassert(mpl == mpl);
234.87 + dim = 0;
234.88 + for (temp = slice; temp != NULL; temp = temp->next) dim++;
234.89 + return dim;
234.90 +}
234.91 +
234.92 +/*----------------------------------------------------------------------
234.93 +-- slice_arity - determine arity of slice.
234.94 +--
234.95 +-- This routine returns arity of slice, i.e. number of null components
234.96 +-- (indicated by asterisks) in the slice. */
234.97 +
234.98 +int slice_arity
234.99 +( MPL *mpl,
234.100 + SLICE *slice /* not changed */
234.101 +)
234.102 +{ SLICE *temp;
234.103 + int arity;
234.104 + xassert(mpl == mpl);
234.105 + arity = 0;
234.106 + for (temp = slice; temp != NULL; temp = temp->next)
234.107 + if (temp->sym == NULL) arity++;
234.108 + return arity;
234.109 +}
234.110 +
234.111 +/*----------------------------------------------------------------------
234.112 +-- fake_slice - create fake slice of all asterisks.
234.113 +--
234.114 +-- This routine creates a fake slice of given dimension, which contains
234.115 +-- asterisks in all components. Zero dimension is allowed. */
234.116 +
234.117 +SLICE *fake_slice(MPL *mpl, int dim)
234.118 +{ SLICE *slice;
234.119 + slice = create_slice(mpl);
234.120 + while (dim-- > 0) slice = expand_slice(mpl, slice, NULL);
234.121 + return slice;
234.122 +}
234.123 +
234.124 +/*----------------------------------------------------------------------
234.125 +-- delete_slice - delete slice.
234.126 +--
234.127 +-- This routine deletes specified slice. */
234.128 +
234.129 +void delete_slice
234.130 +( MPL *mpl,
234.131 + SLICE *slice /* destroyed */
234.132 +)
234.133 +{ SLICE *temp;
234.134 + while (slice != NULL)
234.135 + { temp = slice;
234.136 + slice = temp->next;
234.137 + if (temp->sym != NULL) delete_symbol(mpl, temp->sym);
234.138 +xassert(sizeof(SLICE) == sizeof(TUPLE));
234.139 + dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE));
234.140 + }
234.141 + return;
234.142 +}
234.143 +
234.144 +/*----------------------------------------------------------------------
234.145 +-- is_number - check if current token is number.
234.146 +--
234.147 +-- If the current token is a number, this routine returns non-zero.
234.148 +-- Otherwise zero is returned. */
234.149 +
234.150 +int is_number(MPL *mpl)
234.151 +{ return
234.152 + mpl->token == T_NUMBER;
234.153 +}
234.154 +
234.155 +/*----------------------------------------------------------------------
234.156 +-- is_symbol - check if current token is symbol.
234.157 +--
234.158 +-- If the current token is suitable to be a symbol, the routine returns
234.159 +-- non-zero. Otherwise zero is returned. */
234.160 +
234.161 +int is_symbol(MPL *mpl)
234.162 +{ return
234.163 + mpl->token == T_NUMBER ||
234.164 + mpl->token == T_SYMBOL ||
234.165 + mpl->token == T_STRING;
234.166 +}
234.167 +
234.168 +/*----------------------------------------------------------------------
234.169 +-- is_literal - check if current token is given symbolic literal.
234.170 +--
234.171 +-- If the current token is given symbolic literal, this routine returns
234.172 +-- non-zero. Otherwise zero is returned.
234.173 +--
234.174 +-- This routine is used on processing the data section in the same way
234.175 +-- as the routine is_keyword on processing the model section. */
234.176 +
234.177 +int is_literal(MPL *mpl, char *literal)
234.178 +{ return
234.179 + is_symbol(mpl) && strcmp(mpl->image, literal) == 0;
234.180 +}
234.181 +
234.182 +/*----------------------------------------------------------------------
234.183 +-- read_number - read number.
234.184 +--
234.185 +-- This routine reads the current token, which must be a number, and
234.186 +-- returns its numeric value. */
234.187 +
234.188 +double read_number(MPL *mpl)
234.189 +{ double num;
234.190 + xassert(is_number(mpl));
234.191 + num = mpl->value;
234.192 + get_token(mpl /* <number> */);
234.193 + return num;
234.194 +}
234.195 +
234.196 +/*----------------------------------------------------------------------
234.197 +-- read_symbol - read symbol.
234.198 +--
234.199 +-- This routine reads the current token, which must be a symbol, and
234.200 +-- returns its symbolic value. */
234.201 +
234.202 +SYMBOL *read_symbol(MPL *mpl)
234.203 +{ SYMBOL *sym;
234.204 + xassert(is_symbol(mpl));
234.205 + if (is_number(mpl))
234.206 + sym = create_symbol_num(mpl, mpl->value);
234.207 + else
234.208 + sym = create_symbol_str(mpl, create_string(mpl, mpl->image));
234.209 + get_token(mpl /* <symbol> */);
234.210 + return sym;
234.211 +}
234.212 +
234.213 +/*----------------------------------------------------------------------
234.214 +-- read_slice - read slice.
234.215 +--
234.216 +-- This routine reads slice using the syntax:
234.217 +--
234.218 +-- <slice> ::= [ <symbol list> ]
234.219 +-- <slice> ::= ( <symbol list> )
234.220 +-- <symbol list> ::= <symbol or star>
234.221 +-- <symbol list> ::= <symbol list> , <symbol or star>
234.222 +-- <symbol or star> ::= <symbol>
234.223 +-- <symbol or star> ::= *
234.224 +--
234.225 +-- The bracketed form of slice is used for members of multi-dimensional
234.226 +-- objects while the parenthesized form is used for elemental sets. */
234.227 +
234.228 +SLICE *read_slice
234.229 +( MPL *mpl,
234.230 + char *name, /* not changed */
234.231 + int dim
234.232 +)
234.233 +{ SLICE *slice;
234.234 + int close;
234.235 + xassert(name != NULL);
234.236 + switch (mpl->token)
234.237 + { case T_LBRACKET:
234.238 + close = T_RBRACKET;
234.239 + break;
234.240 + case T_LEFT:
234.241 + xassert(dim > 0);
234.242 + close = T_RIGHT;
234.243 + break;
234.244 + default:
234.245 + xassert(mpl != mpl);
234.246 + }
234.247 + if (dim == 0)
234.248 + error(mpl, "%s cannot be subscripted", name);
234.249 + get_token(mpl /* ( | [ */);
234.250 + /* read slice components */
234.251 + slice = create_slice(mpl);
234.252 + for (;;)
234.253 + { /* the current token must be a symbol or asterisk */
234.254 + if (is_symbol(mpl))
234.255 + slice = expand_slice(mpl, slice, read_symbol(mpl));
234.256 + else if (mpl->token == T_ASTERISK)
234.257 + { slice = expand_slice(mpl, slice, NULL);
234.258 + get_token(mpl /* * */);
234.259 + }
234.260 + else
234.261 + error(mpl, "number, symbol, or asterisk missing where expec"
234.262 + "ted");
234.263 + /* check a token that follows the symbol */
234.264 + if (mpl->token == T_COMMA)
234.265 + get_token(mpl /* , */);
234.266 + else if (mpl->token == close)
234.267 + break;
234.268 + else
234.269 + error(mpl, "syntax error in slice");
234.270 + }
234.271 + /* number of slice components must be the same as the appropriate
234.272 + dimension */
234.273 + if (slice_dimen(mpl, slice) != dim)
234.274 + { switch (close)
234.275 + { case T_RBRACKET:
234.276 + error(mpl, "%s must have %d subscript%s, not %d", name,
234.277 + dim, dim == 1 ? "" : "s", slice_dimen(mpl, slice));
234.278 + break;
234.279 + case T_RIGHT:
234.280 + error(mpl, "%s has dimension %d, not %d", name, dim,
234.281 + slice_dimen(mpl, slice));
234.282 + break;
234.283 + default:
234.284 + xassert(close != close);
234.285 + }
234.286 + }
234.287 + get_token(mpl /* ) | ] */);
234.288 + return slice;
234.289 +}
234.290 +
234.291 +/*----------------------------------------------------------------------
234.292 +-- select_set - select set to saturate it with elemental sets.
234.293 +--
234.294 +-- This routine selects set to saturate it with elemental sets provided
234.295 +-- in the data section. */
234.296 +
234.297 +SET *select_set
234.298 +( MPL *mpl,
234.299 + char *name /* not changed */
234.300 +)
234.301 +{ SET *set;
234.302 + AVLNODE *node;
234.303 + xassert(name != NULL);
234.304 + node = avl_find_node(mpl->tree, name);
234.305 + if (node == NULL || avl_get_node_type(node) != A_SET)
234.306 + error(mpl, "%s not a set", name);
234.307 + set = (SET *)avl_get_node_link(node);
234.308 + if (set->assign != NULL || set->gadget != NULL)
234.309 + error(mpl, "%s needs no data", name);
234.310 + set->data = 1;
234.311 + return set;
234.312 +}
234.313 +
234.314 +/*----------------------------------------------------------------------
234.315 +-- simple_format - read set data block in simple format.
234.316 +--
234.317 +-- This routine reads set data block using the syntax:
234.318 +--
234.319 +-- <simple format> ::= <symbol> , <symbol> , ... , <symbol>
234.320 +--
234.321 +-- where <symbols> are used to construct a complete n-tuple, which is
234.322 +-- included in elemental set assigned to the set member. Commae between
234.323 +-- symbols are optional and may be omitted anywhere.
234.324 +--
234.325 +-- Number of components in the slice must be the same as dimension of
234.326 +-- n-tuples in elemental sets assigned to the set members. To construct
234.327 +-- complete n-tuple the routine replaces null positions in the slice by
234.328 +-- corresponding <symbols>.
234.329 +--
234.330 +-- If the slice contains at least one null position, the current token
234.331 +-- must be symbol. Otherwise, the routine reads no symbols to construct
234.332 +-- the n-tuple, so the current token is not checked. */
234.333 +
234.334 +void simple_format
234.335 +( MPL *mpl,
234.336 + SET *set, /* not changed */
234.337 + MEMBER *memb, /* modified */
234.338 + SLICE *slice /* not changed */
234.339 +)
234.340 +{ TUPLE *tuple;
234.341 + SLICE *temp;
234.342 + SYMBOL *sym, *with = NULL;
234.343 + xassert(set != NULL);
234.344 + xassert(memb != NULL);
234.345 + xassert(slice != NULL);
234.346 + xassert(set->dimen == slice_dimen(mpl, slice));
234.347 + xassert(memb->value.set->dim == set->dimen);
234.348 + if (slice_arity(mpl, slice) > 0) xassert(is_symbol(mpl));
234.349 + /* read symbols and construct complete n-tuple */
234.350 + tuple = create_tuple(mpl);
234.351 + for (temp = slice; temp != NULL; temp = temp->next)
234.352 + { if (temp->sym == NULL)
234.353 + { /* substitution is needed; read symbol */
234.354 + if (!is_symbol(mpl))
234.355 + { int lack = slice_arity(mpl, temp);
234.356 + /* with cannot be null due to assertion above */
234.357 + xassert(with != NULL);
234.358 + if (lack == 1)
234.359 + error(mpl, "one item missing in data group beginning "
234.360 + "with %s", format_symbol(mpl, with));
234.361 + else
234.362 + error(mpl, "%d items missing in data group beginning "
234.363 + "with %s", lack, format_symbol(mpl, with));
234.364 + }
234.365 + sym = read_symbol(mpl);
234.366 + if (with == NULL) with = sym;
234.367 + }
234.368 + else
234.369 + { /* copy symbol from the slice */
234.370 + sym = copy_symbol(mpl, temp->sym);
234.371 + }
234.372 + /* append the symbol to the n-tuple */
234.373 + tuple = expand_tuple(mpl, tuple, sym);
234.374 + /* skip optional comma *between* <symbols> */
234.375 + if (temp->next != NULL && mpl->token == T_COMMA)
234.376 + get_token(mpl /* , */);
234.377 + }
234.378 + /* add constructed n-tuple to elemental set */
234.379 + check_then_add(mpl, memb->value.set, tuple);
234.380 + return;
234.381 +}
234.382 +
234.383 +/*----------------------------------------------------------------------
234.384 +-- matrix_format - read set data block in matrix format.
234.385 +--
234.386 +-- This routine reads set data block using the syntax:
234.387 +--
234.388 +-- <matrix format> ::= <column> <column> ... <column> :=
234.389 +-- <row> +/- +/- ... +/-
234.390 +-- <row> +/- +/- ... +/-
234.391 +-- . . . . . . . . . . .
234.392 +-- <row> +/- +/- ... +/-
234.393 +--
234.394 +-- where <rows> are symbols that denote rows of the matrix, <columns>
234.395 +-- are symbols that denote columns of the matrix, "+" and "-" indicate
234.396 +-- whether corresponding n-tuple needs to be included in the elemental
234.397 +-- set or not, respectively.
234.398 +--
234.399 +-- Number of the slice components must be the same as dimension of the
234.400 +-- elemental set. The slice must have two null positions. To construct
234.401 +-- complete n-tuple for particular element of the matrix the routine
234.402 +-- replaces first null position of the slice by the corresponding <row>
234.403 +-- (or <column>, if the flag tr is on) and second null position by the
234.404 +-- corresponding <column> (or by <row>, if the flag tr is on). */
234.405 +
234.406 +void matrix_format
234.407 +( MPL *mpl,
234.408 + SET *set, /* not changed */
234.409 + MEMBER *memb, /* modified */
234.410 + SLICE *slice, /* not changed */
234.411 + int tr
234.412 +)
234.413 +{ SLICE *list, *col, *temp;
234.414 + TUPLE *tuple;
234.415 + SYMBOL *row;
234.416 + xassert(set != NULL);
234.417 + xassert(memb != NULL);
234.418 + xassert(slice != NULL);
234.419 + xassert(set->dimen == slice_dimen(mpl, slice));
234.420 + xassert(memb->value.set->dim == set->dimen);
234.421 + xassert(slice_arity(mpl, slice) == 2);
234.422 + /* read the matrix heading that contains column symbols (there
234.423 + may be no columns at all) */
234.424 + list = create_slice(mpl);
234.425 + while (mpl->token != T_ASSIGN)
234.426 + { /* read column symbol and append it to the column list */
234.427 + if (!is_symbol(mpl))
234.428 + error(mpl, "number, symbol, or := missing where expected");
234.429 + list = expand_slice(mpl, list, read_symbol(mpl));
234.430 + }
234.431 + get_token(mpl /* := */);
234.432 + /* read zero or more rows that contain matrix data */
234.433 + while (is_symbol(mpl))
234.434 + { /* read row symbol (if the matrix has no columns, row symbols
234.435 + are just ignored) */
234.436 + row = read_symbol(mpl);
234.437 + /* read the matrix row accordingly to the column list */
234.438 + for (col = list; col != NULL; col = col->next)
234.439 + { int which = 0;
234.440 + /* check indicator */
234.441 + if (is_literal(mpl, "+"))
234.442 + ;
234.443 + else if (is_literal(mpl, "-"))
234.444 + { get_token(mpl /* - */);
234.445 + continue;
234.446 + }
234.447 + else
234.448 + { int lack = slice_dimen(mpl, col);
234.449 + if (lack == 1)
234.450 + error(mpl, "one item missing in data group beginning "
234.451 + "with %s", format_symbol(mpl, row));
234.452 + else
234.453 + error(mpl, "%d items missing in data group beginning "
234.454 + "with %s", lack, format_symbol(mpl, row));
234.455 + }
234.456 + /* construct complete n-tuple */
234.457 + tuple = create_tuple(mpl);
234.458 + for (temp = slice; temp != NULL; temp = temp->next)
234.459 + { if (temp->sym == NULL)
234.460 + { /* substitution is needed */
234.461 + switch (++which)
234.462 + { case 1:
234.463 + /* substitute in the first null position */
234.464 + tuple = expand_tuple(mpl, tuple,
234.465 + copy_symbol(mpl, tr ? col->sym : row));
234.466 + break;
234.467 + case 2:
234.468 + /* substitute in the second null position */
234.469 + tuple = expand_tuple(mpl, tuple,
234.470 + copy_symbol(mpl, tr ? row : col->sym));
234.471 + break;
234.472 + default:
234.473 + xassert(which != which);
234.474 + }
234.475 + }
234.476 + else
234.477 + { /* copy symbol from the slice */
234.478 + tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
234.479 + temp->sym));
234.480 + }
234.481 + }
234.482 + xassert(which == 2);
234.483 + /* add constructed n-tuple to elemental set */
234.484 + check_then_add(mpl, memb->value.set, tuple);
234.485 + get_token(mpl /* + */);
234.486 + }
234.487 + /* delete the row symbol */
234.488 + delete_symbol(mpl, row);
234.489 + }
234.490 + /* delete the column list */
234.491 + delete_slice(mpl, list);
234.492 + return;
234.493 +}
234.494 +
234.495 +/*----------------------------------------------------------------------
234.496 +-- set_data - read set data.
234.497 +--
234.498 +-- This routine reads set data using the syntax:
234.499 +--
234.500 +-- <set data> ::= set <set name> <assignments> ;
234.501 +-- <set data> ::= set <set name> [ <symbol list> ] <assignments> ;
234.502 +-- <set name> ::= <symbolic name>
234.503 +-- <assignments> ::= <empty>
234.504 +-- <assignments> ::= <assignments> , :=
234.505 +-- <assignments> ::= <assignments> , ( <symbol list> )
234.506 +-- <assignments> ::= <assignments> , <simple format>
234.507 +-- <assignments> ::= <assignments> , : <matrix format>
234.508 +-- <assignments> ::= <assignments> , (tr) <matrix format>
234.509 +-- <assignments> ::= <assignments> , (tr) : <matrix format>
234.510 +--
234.511 +-- Commae in <assignments> are optional and may be omitted anywhere. */
234.512 +
234.513 +void set_data(MPL *mpl)
234.514 +{ SET *set;
234.515 + TUPLE *tuple;
234.516 + MEMBER *memb;
234.517 + SLICE *slice;
234.518 + int tr = 0;
234.519 + xassert(is_literal(mpl, "set"));
234.520 + get_token(mpl /* set */);
234.521 + /* symbolic name of set must follows the keyword 'set' */
234.522 + if (!is_symbol(mpl))
234.523 + error(mpl, "set name missing where expected");
234.524 + /* select the set to saturate it with data */
234.525 + set = select_set(mpl, mpl->image);
234.526 + get_token(mpl /* <symbolic name> */);
234.527 + /* read optional subscript list, which identifies member of the
234.528 + set to be read */
234.529 + tuple = create_tuple(mpl);
234.530 + if (mpl->token == T_LBRACKET)
234.531 + { /* subscript list is specified */
234.532 + if (set->dim == 0)
234.533 + error(mpl, "%s cannot be subscripted", set->name);
234.534 + get_token(mpl /* [ */);
234.535 + /* read symbols and construct subscript list */
234.536 + for (;;)
234.537 + { if (!is_symbol(mpl))
234.538 + error(mpl, "number or symbol missing where expected");
234.539 + tuple = expand_tuple(mpl, tuple, read_symbol(mpl));
234.540 + if (mpl->token == T_COMMA)
234.541 + get_token(mpl /* , */);
234.542 + else if (mpl->token == T_RBRACKET)
234.543 + break;
234.544 + else
234.545 + error(mpl, "syntax error in subscript list");
234.546 + }
234.547 + if (set->dim != tuple_dimen(mpl, tuple))
234.548 + error(mpl, "%s must have %d subscript%s rather than %d",
234.549 + set->name, set->dim, set->dim == 1 ? "" : "s",
234.550 + tuple_dimen(mpl, tuple));
234.551 + get_token(mpl /* ] */);
234.552 + }
234.553 + else
234.554 + { /* subscript list is not specified */
234.555 + if (set->dim != 0)
234.556 + error(mpl, "%s must be subscripted", set->name);
234.557 + }
234.558 + /* there must be no member with the same subscript list */
234.559 + if (find_member(mpl, set->array, tuple) != NULL)
234.560 + error(mpl, "%s%s already defined",
234.561 + set->name, format_tuple(mpl, '[', tuple));
234.562 + /* add new member to the set and assign it empty elemental set */
234.563 + memb = add_member(mpl, set->array, tuple);
234.564 + memb->value.set = create_elemset(mpl, set->dimen);
234.565 + /* create an initial fake slice of all asterisks */
234.566 + slice = fake_slice(mpl, set->dimen);
234.567 + /* read zero or more data assignments */
234.568 + for (;;)
234.569 + { /* skip optional comma */
234.570 + if (mpl->token == T_COMMA) get_token(mpl /* , */);
234.571 + /* process assignment element */
234.572 + if (mpl->token == T_ASSIGN)
234.573 + { /* assignment ligature is non-significant element */
234.574 + get_token(mpl /* := */);
234.575 + }
234.576 + else if (mpl->token == T_LEFT)
234.577 + { /* left parenthesis begins either new slice or "transpose"
234.578 + indicator */
234.579 + int is_tr;
234.580 + get_token(mpl /* ( */);
234.581 + is_tr = is_literal(mpl, "tr");
234.582 + unget_token(mpl /* ( */);
234.583 + if (is_tr) goto left;
234.584 + /* delete the current slice and read new one */
234.585 + delete_slice(mpl, slice);
234.586 + slice = read_slice(mpl, set->name, set->dimen);
234.587 + /* each new slice resets the "transpose" indicator */
234.588 + tr = 0;
234.589 + /* if the new slice is 0-ary, formally there is one 0-tuple
234.590 + (in the simple format) that follows it */
234.591 + if (slice_arity(mpl, slice) == 0)
234.592 + simple_format(mpl, set, memb, slice);
234.593 + }
234.594 + else if (is_symbol(mpl))
234.595 + { /* number or symbol begins data in the simple format */
234.596 + simple_format(mpl, set, memb, slice);
234.597 + }
234.598 + else if (mpl->token == T_COLON)
234.599 + { /* colon begins data in the matrix format */
234.600 + if (slice_arity(mpl, slice) != 2)
234.601 +err1: error(mpl, "slice currently used must specify 2 asterisk"
234.602 + "s, not %d", slice_arity(mpl, slice));
234.603 + get_token(mpl /* : */);
234.604 + /* read elemental set data in the matrix format */
234.605 + matrix_format(mpl, set, memb, slice, tr);
234.606 + }
234.607 + else if (mpl->token == T_LEFT)
234.608 +left: { /* left parenthesis begins the "transpose" indicator, which
234.609 + is followed by data in the matrix format */
234.610 + get_token(mpl /* ( */);
234.611 + if (!is_literal(mpl, "tr"))
234.612 +err2: error(mpl, "transpose indicator (tr) incomplete");
234.613 + if (slice_arity(mpl, slice) != 2) goto err1;
234.614 + get_token(mpl /* tr */);
234.615 + if (mpl->token != T_RIGHT) goto err2;
234.616 + get_token(mpl /* ) */);
234.617 + /* in this case the colon is optional */
234.618 + if (mpl->token == T_COLON) get_token(mpl /* : */);
234.619 + /* set the "transpose" indicator */
234.620 + tr = 1;
234.621 + /* read elemental set data in the matrix format */
234.622 + matrix_format(mpl, set, memb, slice, tr);
234.623 + }
234.624 + else if (mpl->token == T_SEMICOLON)
234.625 + { /* semicolon terminates the data block */
234.626 + get_token(mpl /* ; */);
234.627 + break;
234.628 + }
234.629 + else
234.630 + error(mpl, "syntax error in set data block");
234.631 + }
234.632 + /* delete the current slice */
234.633 + delete_slice(mpl, slice);
234.634 + return;
234.635 +}
234.636 +
234.637 +/*----------------------------------------------------------------------
234.638 +-- select_parameter - select parameter to saturate it with data.
234.639 +--
234.640 +-- This routine selects parameter to saturate it with data provided in
234.641 +-- the data section. */
234.642 +
234.643 +PARAMETER *select_parameter
234.644 +( MPL *mpl,
234.645 + char *name /* not changed */
234.646 +)
234.647 +{ PARAMETER *par;
234.648 + AVLNODE *node;
234.649 + xassert(name != NULL);
234.650 + node = avl_find_node(mpl->tree, name);
234.651 + if (node == NULL || avl_get_node_type(node) != A_PARAMETER)
234.652 + error(mpl, "%s not a parameter", name);
234.653 + par = (PARAMETER *)avl_get_node_link(node);
234.654 + if (par->assign != NULL)
234.655 + error(mpl, "%s needs no data", name);
234.656 + if (par->data)
234.657 + error(mpl, "%s already provided with data", name);
234.658 + par->data = 1;
234.659 + return par;
234.660 +}
234.661 +
234.662 +/*----------------------------------------------------------------------
234.663 +-- set_default - set default parameter value.
234.664 +--
234.665 +-- This routine sets default value for specified parameter. */
234.666 +
234.667 +void set_default
234.668 +( MPL *mpl,
234.669 + PARAMETER *par, /* not changed */
234.670 + SYMBOL *altval /* destroyed */
234.671 +)
234.672 +{ xassert(par != NULL);
234.673 + xassert(altval != NULL);
234.674 + if (par->option != NULL)
234.675 + error(mpl, "default value for %s already specified in model se"
234.676 + "ction", par->name);
234.677 + xassert(par->defval == NULL);
234.678 + par->defval = altval;
234.679 + return;
234.680 +}
234.681 +
234.682 +/*----------------------------------------------------------------------
234.683 +-- read_value - read value and assign it to parameter member.
234.684 +--
234.685 +-- This routine reads numeric or symbolic value from the input stream
234.686 +-- and assigns to new parameter member specified by its n-tuple, which
234.687 +-- (the member) is created and added to the parameter array. */
234.688 +
234.689 +MEMBER *read_value
234.690 +( MPL *mpl,
234.691 + PARAMETER *par, /* not changed */
234.692 + TUPLE *tuple /* destroyed */
234.693 +)
234.694 +{ MEMBER *memb;
234.695 + xassert(par != NULL);
234.696 + xassert(is_symbol(mpl));
234.697 + /* there must be no member with the same n-tuple */
234.698 + if (find_member(mpl, par->array, tuple) != NULL)
234.699 + error(mpl, "%s%s already defined",
234.700 + par->name, format_tuple(mpl, '[', tuple));
234.701 + /* create new parameter member with given n-tuple */
234.702 + memb = add_member(mpl, par->array, tuple);
234.703 + /* read value and assigns it to the new parameter member */
234.704 + switch (par->type)
234.705 + { case A_NUMERIC:
234.706 + case A_INTEGER:
234.707 + case A_BINARY:
234.708 + if (!is_number(mpl))
234.709 + error(mpl, "%s requires numeric data", par->name);
234.710 + memb->value.num = read_number(mpl);
234.711 + break;
234.712 + case A_SYMBOLIC:
234.713 + memb->value.sym = read_symbol(mpl);
234.714 + break;
234.715 + default:
234.716 + xassert(par != par);
234.717 + }
234.718 + return memb;
234.719 +}
234.720 +
234.721 +/*----------------------------------------------------------------------
234.722 +-- plain_format - read parameter data block in plain format.
234.723 +--
234.724 +-- This routine reads parameter data block using the syntax:
234.725 +--
234.726 +-- <plain format> ::= <symbol> , <symbol> , ... , <symbol> , <value>
234.727 +--
234.728 +-- where <symbols> are used to determine a complete subscript list for
234.729 +-- parameter member, <value> is a numeric or symbolic value assigned to
234.730 +-- the parameter member. Commae between data items are optional and may
234.731 +-- be omitted anywhere.
234.732 +--
234.733 +-- Number of components in the slice must be the same as dimension of
234.734 +-- the parameter. To construct the complete subscript list the routine
234.735 +-- replaces null positions in the slice by corresponding <symbols>. */
234.736 +
234.737 +void plain_format
234.738 +( MPL *mpl,
234.739 + PARAMETER *par, /* not changed */
234.740 + SLICE *slice /* not changed */
234.741 +)
234.742 +{ TUPLE *tuple;
234.743 + SLICE *temp;
234.744 + SYMBOL *sym, *with = NULL;
234.745 + xassert(par != NULL);
234.746 + xassert(par->dim == slice_dimen(mpl, slice));
234.747 + xassert(is_symbol(mpl));
234.748 + /* read symbols and construct complete subscript list */
234.749 + tuple = create_tuple(mpl);
234.750 + for (temp = slice; temp != NULL; temp = temp->next)
234.751 + { if (temp->sym == NULL)
234.752 + { /* substitution is needed; read symbol */
234.753 + if (!is_symbol(mpl))
234.754 + { int lack = slice_arity(mpl, temp) + 1;
234.755 + xassert(with != NULL);
234.756 + xassert(lack > 1);
234.757 + error(mpl, "%d items missing in data group beginning wit"
234.758 + "h %s", lack, format_symbol(mpl, with));
234.759 + }
234.760 + sym = read_symbol(mpl);
234.761 + if (with == NULL) with = sym;
234.762 + }
234.763 + else
234.764 + { /* copy symbol from the slice */
234.765 + sym = copy_symbol(mpl, temp->sym);
234.766 + }
234.767 + /* append the symbol to the subscript list */
234.768 + tuple = expand_tuple(mpl, tuple, sym);
234.769 + /* skip optional comma */
234.770 + if (mpl->token == T_COMMA) get_token(mpl /* , */);
234.771 + }
234.772 + /* read value and assign it to new parameter member */
234.773 + if (!is_symbol(mpl))
234.774 + { xassert(with != NULL);
234.775 + error(mpl, "one item missing in data group beginning with %s",
234.776 + format_symbol(mpl, with));
234.777 + }
234.778 + read_value(mpl, par, tuple);
234.779 + return;
234.780 +}
234.781 +
234.782 +/*----------------------------------------------------------------------
234.783 +-- tabular_format - read parameter data block in tabular format.
234.784 +--
234.785 +-- This routine reads parameter data block using the syntax:
234.786 +--
234.787 +-- <tabular format> ::= <column> <column> ... <column> :=
234.788 +-- <row> <value> <value> ... <value>
234.789 +-- <row> <value> <value> ... <value>
234.790 +-- . . . . . . . . . . .
234.791 +-- <row> <value> <value> ... <value>
234.792 +--
234.793 +-- where <rows> are symbols that denote rows of the table, <columns>
234.794 +-- are symbols that denote columns of the table, <values> are numeric
234.795 +-- or symbolic values assigned to the corresponding parameter members.
234.796 +-- If <value> is specified as single point, no value is provided.
234.797 +--
234.798 +-- Number of components in the slice must be the same as dimension of
234.799 +-- the parameter. The slice must have two null positions. To construct
234.800 +-- complete subscript list for particular <value> the routine replaces
234.801 +-- the first null position of the slice by the corresponding <row> (or
234.802 +-- <column>, if the flag tr is on) and the second null position by the
234.803 +-- corresponding <column> (or by <row>, if the flag tr is on). */
234.804 +
234.805 +void tabular_format
234.806 +( MPL *mpl,
234.807 + PARAMETER *par, /* not changed */
234.808 + SLICE *slice, /* not changed */
234.809 + int tr
234.810 +)
234.811 +{ SLICE *list, *col, *temp;
234.812 + TUPLE *tuple;
234.813 + SYMBOL *row;
234.814 + xassert(par != NULL);
234.815 + xassert(par->dim == slice_dimen(mpl, slice));
234.816 + xassert(slice_arity(mpl, slice) == 2);
234.817 + /* read the table heading that contains column symbols (the table
234.818 + may have no columns) */
234.819 + list = create_slice(mpl);
234.820 + while (mpl->token != T_ASSIGN)
234.821 + { /* read column symbol and append it to the column list */
234.822 + if (!is_symbol(mpl))
234.823 + error(mpl, "number, symbol, or := missing where expected");
234.824 + list = expand_slice(mpl, list, read_symbol(mpl));
234.825 + }
234.826 + get_token(mpl /* := */);
234.827 + /* read zero or more rows that contain tabular data */
234.828 + while (is_symbol(mpl))
234.829 + { /* read row symbol (if the table has no columns, these symbols
234.830 + are just ignored) */
234.831 + row = read_symbol(mpl);
234.832 + /* read values accordingly to the column list */
234.833 + for (col = list; col != NULL; col = col->next)
234.834 + { int which = 0;
234.835 + /* if the token is single point, no value is provided */
234.836 + if (is_literal(mpl, "."))
234.837 + { get_token(mpl /* . */);
234.838 + continue;
234.839 + }
234.840 + /* construct complete subscript list */
234.841 + tuple = create_tuple(mpl);
234.842 + for (temp = slice; temp != NULL; temp = temp->next)
234.843 + { if (temp->sym == NULL)
234.844 + { /* substitution is needed */
234.845 + switch (++which)
234.846 + { case 1:
234.847 + /* substitute in the first null position */
234.848 + tuple = expand_tuple(mpl, tuple,
234.849 + copy_symbol(mpl, tr ? col->sym : row));
234.850 + break;
234.851 + case 2:
234.852 + /* substitute in the second null position */
234.853 + tuple = expand_tuple(mpl, tuple,
234.854 + copy_symbol(mpl, tr ? row : col->sym));
234.855 + break;
234.856 + default:
234.857 + xassert(which != which);
234.858 + }
234.859 + }
234.860 + else
234.861 + { /* copy symbol from the slice */
234.862 + tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
234.863 + temp->sym));
234.864 + }
234.865 + }
234.866 + xassert(which == 2);
234.867 + /* read value and assign it to new parameter member */
234.868 + if (!is_symbol(mpl))
234.869 + { int lack = slice_dimen(mpl, col);
234.870 + if (lack == 1)
234.871 + error(mpl, "one item missing in data group beginning "
234.872 + "with %s", format_symbol(mpl, row));
234.873 + else
234.874 + error(mpl, "%d items missing in data group beginning "
234.875 + "with %s", lack, format_symbol(mpl, row));
234.876 + }
234.877 + read_value(mpl, par, tuple);
234.878 + }
234.879 + /* delete the row symbol */
234.880 + delete_symbol(mpl, row);
234.881 + }
234.882 + /* delete the column list */
234.883 + delete_slice(mpl, list);
234.884 + return;
234.885 +}
234.886 +
234.887 +/*----------------------------------------------------------------------
234.888 +-- tabbing_format - read parameter data block in tabbing format.
234.889 +--
234.890 +-- This routine reads parameter data block using the syntax:
234.891 +--
234.892 +-- <tabbing format> ::= <prefix> <name> , ... , <name> , := ,
234.893 +-- <symbol> , ... , <symbol> , <value> , ... , <value> ,
234.894 +-- <symbol> , ... , <symbol> , <value> , ... , <value> ,
234.895 +-- . . . . . . . . . . . . . . . . .
234.896 +-- <symbol> , ... , <symbol> , <value> , ... , <value>
234.897 +-- <prefix> ::= <empty>
234.898 +-- <prefix> ::= <set name> :
234.899 +--
234.900 +-- where <names> are names of parameters (all the parameters must be
234.901 +-- subscripted and have identical dimensions), <symbols> are symbols
234.902 +-- used to define subscripts of parameter members, <values> are numeric
234.903 +-- or symbolic values assigned to the corresponding parameter members.
234.904 +-- Optional <prefix> may specify a simple set, in which case n-tuples
234.905 +-- built of <symbols> for each row of the data table (i.e. subscripts
234.906 +-- of parameter members) are added to the specified set. Commae between
234.907 +-- data items are optional and may be omitted anywhere.
234.908 +--
234.909 +-- If the parameter altval is not NULL, it specifies a default value
234.910 +-- provided for all the parameters specified in the data block. */
234.911 +
234.912 +void tabbing_format
234.913 +( MPL *mpl,
234.914 + SYMBOL *altval /* not changed */
234.915 +)
234.916 +{ SET *set = NULL;
234.917 + PARAMETER *par;
234.918 + SLICE *list, *col;
234.919 + TUPLE *tuple;
234.920 + int next_token, j, dim = 0;
234.921 + char *last_name = NULL;
234.922 + /* read the optional <prefix> */
234.923 + if (is_symbol(mpl))
234.924 + { get_token(mpl /* <symbol> */);
234.925 + next_token = mpl->token;
234.926 + unget_token(mpl /* <symbol> */);
234.927 + if (next_token == T_COLON)
234.928 + { /* select the set to saturate it with data */
234.929 + set = select_set(mpl, mpl->image);
234.930 + /* the set must be simple (i.e. not set of sets) */
234.931 + if (set->dim != 0)
234.932 + error(mpl, "%s must be a simple set", set->name);
234.933 + /* and must not be defined yet */
234.934 + if (set->array->head != NULL)
234.935 + error(mpl, "%s already defined", set->name);
234.936 + /* add new (the only) member to the set and assign it empty
234.937 + elemental set */
234.938 + add_member(mpl, set->array, NULL)->value.set =
234.939 + create_elemset(mpl, set->dimen);
234.940 + last_name = set->name, dim = set->dimen;
234.941 + get_token(mpl /* <symbol> */);
234.942 + xassert(mpl->token == T_COLON);
234.943 + get_token(mpl /* : */);
234.944 + }
234.945 + }
234.946 + /* read the table heading that contains parameter names */
234.947 + list = create_slice(mpl);
234.948 + while (mpl->token != T_ASSIGN)
234.949 + { /* there must be symbolic name of parameter */
234.950 + if (!is_symbol(mpl))
234.951 + error(mpl, "parameter name or := missing where expected");
234.952 + /* select the parameter to saturate it with data */
234.953 + par = select_parameter(mpl, mpl->image);
234.954 + /* the parameter must be subscripted */
234.955 + if (par->dim == 0)
234.956 + error(mpl, "%s not a subscripted parameter", mpl->image);
234.957 + /* the set (if specified) and all the parameters in the data
234.958 + block must have identical dimension */
234.959 + if (dim != 0 && par->dim != dim)
234.960 + { xassert(last_name != NULL);
234.961 + error(mpl, "%s has dimension %d while %s has dimension %d",
234.962 + last_name, dim, par->name, par->dim);
234.963 + }
234.964 + /* set default value for the parameter (if specified) */
234.965 + if (altval != NULL)
234.966 + set_default(mpl, par, copy_symbol(mpl, altval));
234.967 + /* append the parameter to the column list */
234.968 + list = expand_slice(mpl, list, (SYMBOL *)par);
234.969 + last_name = par->name, dim = par->dim;
234.970 + get_token(mpl /* <symbol> */);
234.971 + /* skip optional comma */
234.972 + if (mpl->token == T_COMMA) get_token(mpl /* , */);
234.973 + }
234.974 + if (slice_dimen(mpl, list) == 0)
234.975 + error(mpl, "at least one parameter name required");
234.976 + get_token(mpl /* := */);
234.977 + /* skip optional comma */
234.978 + if (mpl->token == T_COMMA) get_token(mpl /* , */);
234.979 + /* read rows that contain tabbing data */
234.980 + while (is_symbol(mpl))
234.981 + { /* read subscript list */
234.982 + tuple = create_tuple(mpl);
234.983 + for (j = 1; j <= dim; j++)
234.984 + { /* read j-th subscript */
234.985 + if (!is_symbol(mpl))
234.986 + { int lack = slice_dimen(mpl, list) + dim - j + 1;
234.987 + xassert(tuple != NULL);
234.988 + xassert(lack > 1);
234.989 + error(mpl, "%d items missing in data group beginning wit"
234.990 + "h %s", lack, format_symbol(mpl, tuple->sym));
234.991 + }
234.992 + /* read and append j-th subscript to the n-tuple */
234.993 + tuple = expand_tuple(mpl, tuple, read_symbol(mpl));
234.994 + /* skip optional comma *between* <symbols> */
234.995 + if (j < dim && mpl->token == T_COMMA)
234.996 + get_token(mpl /* , */);
234.997 + }
234.998 + /* if the set is specified, add to it new n-tuple, which is a
234.999 + copy of the subscript list just read */
234.1000 + if (set != NULL)
234.1001 + check_then_add(mpl, set->array->head->value.set,
234.1002 + copy_tuple(mpl, tuple));
234.1003 + /* skip optional comma between <symbol> and <value> */
234.1004 + if (mpl->token == T_COMMA) get_token(mpl /* , */);
234.1005 + /* read values accordingly to the column list */
234.1006 + for (col = list; col != NULL; col = col->next)
234.1007 + { /* if the token is single point, no value is provided */
234.1008 + if (is_literal(mpl, "."))
234.1009 + { get_token(mpl /* . */);
234.1010 + continue;
234.1011 + }
234.1012 + /* read value and assign it to new parameter member */
234.1013 + if (!is_symbol(mpl))
234.1014 + { int lack = slice_dimen(mpl, col);
234.1015 + xassert(tuple != NULL);
234.1016 + if (lack == 1)
234.1017 + error(mpl, "one item missing in data group beginning "
234.1018 + "with %s", format_symbol(mpl, tuple->sym));
234.1019 + else
234.1020 + error(mpl, "%d items missing in data group beginning "
234.1021 + "with %s", lack, format_symbol(mpl, tuple->sym));
234.1022 + }
234.1023 + read_value(mpl, (PARAMETER *)col->sym, copy_tuple(mpl,
234.1024 + tuple));
234.1025 + /* skip optional comma preceding the next value */
234.1026 + if (col->next != NULL && mpl->token == T_COMMA)
234.1027 + get_token(mpl /* , */);
234.1028 + }
234.1029 + /* delete the original subscript list */
234.1030 + delete_tuple(mpl, tuple);
234.1031 + /* skip optional comma (only if there is next data group) */
234.1032 + if (mpl->token == T_COMMA)
234.1033 + { get_token(mpl /* , */);
234.1034 + if (!is_symbol(mpl)) unget_token(mpl /* , */);
234.1035 + }
234.1036 + }
234.1037 + /* delete the column list (it contains parameters, not symbols,
234.1038 + so nullify it before) */
234.1039 + for (col = list; col != NULL; col = col->next) col->sym = NULL;
234.1040 + delete_slice(mpl, list);
234.1041 + return;
234.1042 +}
234.1043 +
234.1044 +/*----------------------------------------------------------------------
234.1045 +-- parameter_data - read parameter data.
234.1046 +--
234.1047 +-- This routine reads parameter data using the syntax:
234.1048 +--
234.1049 +-- <parameter data> ::= param <default value> : <tabbing format> ;
234.1050 +-- <parameter data> ::= param <parameter name> <default value>
234.1051 +-- <assignments> ;
234.1052 +-- <parameter name> ::= <symbolic name>
234.1053 +-- <default value> ::= <empty>
234.1054 +-- <default value> ::= default <symbol>
234.1055 +-- <assignments> ::= <empty>
234.1056 +-- <assignments> ::= <assignments> , :=
234.1057 +-- <assignments> ::= <assignments> , [ <symbol list> ]
234.1058 +-- <assignments> ::= <assignments> , <plain format>
234.1059 +-- <assignemnts> ::= <assignments> , : <tabular format>
234.1060 +-- <assignments> ::= <assignments> , (tr) <tabular format>
234.1061 +-- <assignments> ::= <assignments> , (tr) : <tabular format>
234.1062 +--
234.1063 +-- Commae in <assignments> are optional and may be omitted anywhere. */
234.1064 +
234.1065 +void parameter_data(MPL *mpl)
234.1066 +{ PARAMETER *par;
234.1067 + SYMBOL *altval = NULL;
234.1068 + SLICE *slice;
234.1069 + int tr = 0;
234.1070 + xassert(is_literal(mpl, "param"));
234.1071 + get_token(mpl /* param */);
234.1072 + /* read optional default value */
234.1073 + if (is_literal(mpl, "default"))
234.1074 + { get_token(mpl /* default */);
234.1075 + if (!is_symbol(mpl))
234.1076 + error(mpl, "default value missing where expected");
234.1077 + altval = read_symbol(mpl);
234.1078 + /* if the default value follows the keyword 'param', the next
234.1079 + token must be only the colon */
234.1080 + if (mpl->token != T_COLON)
234.1081 + error(mpl, "colon missing where expected");
234.1082 + }
234.1083 + /* being used after the keyword 'param' or the optional default
234.1084 + value the colon begins data in the tabbing format */
234.1085 + if (mpl->token == T_COLON)
234.1086 + { get_token(mpl /* : */);
234.1087 + /* skip optional comma */
234.1088 + if (mpl->token == T_COMMA) get_token(mpl /* , */);
234.1089 + /* read parameter data in the tabbing format */
234.1090 + tabbing_format(mpl, altval);
234.1091 + /* on reading data in the tabbing format the default value is
234.1092 + always copied, so delete the original symbol */
234.1093 + if (altval != NULL) delete_symbol(mpl, altval);
234.1094 + /* the next token must be only semicolon */
234.1095 + if (mpl->token != T_SEMICOLON)
234.1096 + error(mpl, "symbol, number, or semicolon missing where expe"
234.1097 + "cted");
234.1098 + get_token(mpl /* ; */);
234.1099 + goto done;
234.1100 + }
234.1101 + /* in other cases there must be symbolic name of parameter, which
234.1102 + follows the keyword 'param' */
234.1103 + if (!is_symbol(mpl))
234.1104 + error(mpl, "parameter name missing where expected");
234.1105 + /* select the parameter to saturate it with data */
234.1106 + par = select_parameter(mpl, mpl->image);
234.1107 + get_token(mpl /* <symbol> */);
234.1108 + /* read optional default value */
234.1109 + if (is_literal(mpl, "default"))
234.1110 + { get_token(mpl /* default */);
234.1111 + if (!is_symbol(mpl))
234.1112 + error(mpl, "default value missing where expected");
234.1113 + altval = read_symbol(mpl);
234.1114 + /* set default value for the parameter */
234.1115 + set_default(mpl, par, altval);
234.1116 + }
234.1117 + /* create initial fake slice of all asterisks */
234.1118 + slice = fake_slice(mpl, par->dim);
234.1119 + /* read zero or more data assignments */
234.1120 + for (;;)
234.1121 + { /* skip optional comma */
234.1122 + if (mpl->token == T_COMMA) get_token(mpl /* , */);
234.1123 + /* process current assignment */
234.1124 + if (mpl->token == T_ASSIGN)
234.1125 + { /* assignment ligature is non-significant element */
234.1126 + get_token(mpl /* := */);
234.1127 + }
234.1128 + else if (mpl->token == T_LBRACKET)
234.1129 + { /* left bracket begins new slice; delete the current slice
234.1130 + and read new one */
234.1131 + delete_slice(mpl, slice);
234.1132 + slice = read_slice(mpl, par->name, par->dim);
234.1133 + /* each new slice resets the "transpose" indicator */
234.1134 + tr = 0;
234.1135 + }
234.1136 + else if (is_symbol(mpl))
234.1137 + { /* number or symbol begins data in the plain format */
234.1138 + plain_format(mpl, par, slice);
234.1139 + }
234.1140 + else if (mpl->token == T_COLON)
234.1141 + { /* colon begins data in the tabular format */
234.1142 + if (par->dim == 0)
234.1143 +err1: error(mpl, "%s not a subscripted parameter",
234.1144 + par->name);
234.1145 + if (slice_arity(mpl, slice) != 2)
234.1146 +err2: error(mpl, "slice currently used must specify 2 asterisk"
234.1147 + "s, not %d", slice_arity(mpl, slice));
234.1148 + get_token(mpl /* : */);
234.1149 + /* read parameter data in the tabular format */
234.1150 + tabular_format(mpl, par, slice, tr);
234.1151 + }
234.1152 + else if (mpl->token == T_LEFT)
234.1153 + { /* left parenthesis begins the "transpose" indicator, which
234.1154 + is followed by data in the tabular format */
234.1155 + get_token(mpl /* ( */);
234.1156 + if (!is_literal(mpl, "tr"))
234.1157 +err3: error(mpl, "transpose indicator (tr) incomplete");
234.1158 + if (par->dim == 0) goto err1;
234.1159 + if (slice_arity(mpl, slice) != 2) goto err2;
234.1160 + get_token(mpl /* tr */);
234.1161 + if (mpl->token != T_RIGHT) goto err3;
234.1162 + get_token(mpl /* ) */);
234.1163 + /* in this case the colon is optional */
234.1164 + if (mpl->token == T_COLON) get_token(mpl /* : */);
234.1165 + /* set the "transpose" indicator */
234.1166 + tr = 1;
234.1167 + /* read parameter data in the tabular format */
234.1168 + tabular_format(mpl, par, slice, tr);
234.1169 + }
234.1170 + else if (mpl->token == T_SEMICOLON)
234.1171 + { /* semicolon terminates the data block */
234.1172 + get_token(mpl /* ; */);
234.1173 + break;
234.1174 + }
234.1175 + else
234.1176 + error(mpl, "syntax error in parameter data block");
234.1177 + }
234.1178 + /* delete the current slice */
234.1179 + delete_slice(mpl, slice);
234.1180 +done: return;
234.1181 +}
234.1182 +
234.1183 +/*----------------------------------------------------------------------
234.1184 +-- data_section - read data section.
234.1185 +--
234.1186 +-- This routine reads data section using the syntax:
234.1187 +--
234.1188 +-- <data section> ::= <empty>
234.1189 +-- <data section> ::= <data section> <data block> ;
234.1190 +-- <data block> ::= <set data>
234.1191 +-- <data block> ::= <parameter data>
234.1192 +--
234.1193 +-- Reading data section is terminated by either the keyword 'end' or
234.1194 +-- the end of file. */
234.1195 +
234.1196 +void data_section(MPL *mpl)
234.1197 +{ while (!(mpl->token == T_EOF || is_literal(mpl, "end")))
234.1198 + { if (is_literal(mpl, "set"))
234.1199 + set_data(mpl);
234.1200 + else if (is_literal(mpl, "param"))
234.1201 + parameter_data(mpl);
234.1202 + else
234.1203 + error(mpl, "syntax error in data section");
234.1204 + }
234.1205 + return;
234.1206 +}
234.1207 +
234.1208 +/* eof */
235.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
235.2 +++ b/src/glpmpl03.c Mon Dec 06 13:09:21 2010 +0100
235.3 @@ -0,0 +1,6078 @@
235.4 +/* glpmpl03.c */
235.5 +
235.6 +/***********************************************************************
235.7 +* This code is part of GLPK (GNU Linear Programming Kit).
235.8 +*
235.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
235.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
235.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
235.12 +* E-mail: <mao@gnu.org>.
235.13 +*
235.14 +* GLPK is free software: you can redistribute it and/or modify it
235.15 +* under the terms of the GNU General Public License as published by
235.16 +* the Free Software Foundation, either version 3 of the License, or
235.17 +* (at your option) any later version.
235.18 +*
235.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
235.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
235.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
235.22 +* License for more details.
235.23 +*
235.24 +* You should have received a copy of the GNU General Public License
235.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
235.26 +***********************************************************************/
235.27 +
235.28 +#define _GLPSTD_ERRNO
235.29 +#define _GLPSTD_STDIO
235.30 +#include "glpenv.h"
235.31 +#include "glpmpl.h"
235.32 +
235.33 +/**********************************************************************/
235.34 +/* * * FLOATING-POINT NUMBERS * * */
235.35 +/**********************************************************************/
235.36 +
235.37 +/*----------------------------------------------------------------------
235.38 +-- fp_add - floating-point addition.
235.39 +--
235.40 +-- This routine computes the sum x + y. */
235.41 +
235.42 +double fp_add(MPL *mpl, double x, double y)
235.43 +{ if (x > 0.0 && y > 0.0 && x > + 0.999 * DBL_MAX - y ||
235.44 + x < 0.0 && y < 0.0 && x < - 0.999 * DBL_MAX - y)
235.45 + error(mpl, "%.*g + %.*g; floating-point overflow",
235.46 + DBL_DIG, x, DBL_DIG, y);
235.47 + return x + y;
235.48 +}
235.49 +
235.50 +/*----------------------------------------------------------------------
235.51 +-- fp_sub - floating-point subtraction.
235.52 +--
235.53 +-- This routine computes the difference x - y. */
235.54 +
235.55 +double fp_sub(MPL *mpl, double x, double y)
235.56 +{ if (x > 0.0 && y < 0.0 && x > + 0.999 * DBL_MAX + y ||
235.57 + x < 0.0 && y > 0.0 && x < - 0.999 * DBL_MAX + y)
235.58 + error(mpl, "%.*g - %.*g; floating-point overflow",
235.59 + DBL_DIG, x, DBL_DIG, y);
235.60 + return x - y;
235.61 +}
235.62 +
235.63 +/*----------------------------------------------------------------------
235.64 +-- fp_less - floating-point non-negative subtraction.
235.65 +--
235.66 +-- This routine computes the non-negative difference max(0, x - y). */
235.67 +
235.68 +double fp_less(MPL *mpl, double x, double y)
235.69 +{ if (x < y) return 0.0;
235.70 + if (x > 0.0 && y < 0.0 && x > + 0.999 * DBL_MAX + y)
235.71 + error(mpl, "%.*g less %.*g; floating-point overflow",
235.72 + DBL_DIG, x, DBL_DIG, y);
235.73 + return x - y;
235.74 +}
235.75 +
235.76 +/*----------------------------------------------------------------------
235.77 +-- fp_mul - floating-point multiplication.
235.78 +--
235.79 +-- This routine computes the product x * y. */
235.80 +
235.81 +double fp_mul(MPL *mpl, double x, double y)
235.82 +{ if (fabs(y) > 1.0 && fabs(x) > (0.999 * DBL_MAX) / fabs(y))
235.83 + error(mpl, "%.*g * %.*g; floating-point overflow",
235.84 + DBL_DIG, x, DBL_DIG, y);
235.85 + return x * y;
235.86 +}
235.87 +
235.88 +/*----------------------------------------------------------------------
235.89 +-- fp_div - floating-point division.
235.90 +--
235.91 +-- This routine computes the quotient x / y. */
235.92 +
235.93 +double fp_div(MPL *mpl, double x, double y)
235.94 +{ if (fabs(y) < DBL_MIN)
235.95 + error(mpl, "%.*g / %.*g; floating-point zero divide",
235.96 + DBL_DIG, x, DBL_DIG, y);
235.97 + if (fabs(y) < 1.0 && fabs(x) > (0.999 * DBL_MAX) * fabs(y))
235.98 + error(mpl, "%.*g / %.*g; floating-point overflow",
235.99 + DBL_DIG, x, DBL_DIG, y);
235.100 + return x / y;
235.101 +}
235.102 +
235.103 +/*----------------------------------------------------------------------
235.104 +-- fp_idiv - floating-point quotient of exact division.
235.105 +--
235.106 +-- This routine computes the quotient of exact division x div y. */
235.107 +
235.108 +double fp_idiv(MPL *mpl, double x, double y)
235.109 +{ if (fabs(y) < DBL_MIN)
235.110 + error(mpl, "%.*g div %.*g; floating-point zero divide",
235.111 + DBL_DIG, x, DBL_DIG, y);
235.112 + if (fabs(y) < 1.0 && fabs(x) > (0.999 * DBL_MAX) * fabs(y))
235.113 + error(mpl, "%.*g div %.*g; floating-point overflow",
235.114 + DBL_DIG, x, DBL_DIG, y);
235.115 + x /= y;
235.116 + return x > 0.0 ? floor(x) : x < 0.0 ? ceil(x) : 0.0;
235.117 +}
235.118 +
235.119 +/*----------------------------------------------------------------------
235.120 +-- fp_mod - floating-point remainder of exact division.
235.121 +--
235.122 +-- This routine computes the remainder of exact division x mod y.
235.123 +--
235.124 +-- NOTE: By definition x mod y = x - y * floor(x / y). */
235.125 +
235.126 +double fp_mod(MPL *mpl, double x, double y)
235.127 +{ double r;
235.128 + xassert(mpl == mpl);
235.129 + if (x == 0.0)
235.130 + r = 0.0;
235.131 + else if (y == 0.0)
235.132 + r = x;
235.133 + else
235.134 + { r = fmod(fabs(x), fabs(y));
235.135 + if (r != 0.0)
235.136 + { if (x < 0.0) r = - r;
235.137 + if (x > 0.0 && y < 0.0 || x < 0.0 && y > 0.0) r += y;
235.138 + }
235.139 + }
235.140 + return r;
235.141 +}
235.142 +
235.143 +/*----------------------------------------------------------------------
235.144 +-- fp_power - floating-point exponentiation (raise to power).
235.145 +--
235.146 +-- This routine computes the exponentiation x ** y. */
235.147 +
235.148 +double fp_power(MPL *mpl, double x, double y)
235.149 +{ double r;
235.150 + if (x == 0.0 && y <= 0.0 || x < 0.0 && y != floor(y))
235.151 + error(mpl, "%.*g ** %.*g; result undefined",
235.152 + DBL_DIG, x, DBL_DIG, y);
235.153 + if (x == 0.0) goto eval;
235.154 + if (fabs(x) > 1.0 && y > +1.0 &&
235.155 + +log(fabs(x)) > (0.999 * log(DBL_MAX)) / y ||
235.156 + fabs(x) < 1.0 && y < -1.0 &&
235.157 + +log(fabs(x)) < (0.999 * log(DBL_MAX)) / y)
235.158 + error(mpl, "%.*g ** %.*g; floating-point overflow",
235.159 + DBL_DIG, x, DBL_DIG, y);
235.160 + if (fabs(x) > 1.0 && y < -1.0 &&
235.161 + -log(fabs(x)) < (0.999 * log(DBL_MAX)) / y ||
235.162 + fabs(x) < 1.0 && y > +1.0 &&
235.163 + -log(fabs(x)) > (0.999 * log(DBL_MAX)) / y)
235.164 + r = 0.0;
235.165 + else
235.166 +eval: r = pow(x, y);
235.167 + return r;
235.168 +}
235.169 +
235.170 +/*----------------------------------------------------------------------
235.171 +-- fp_exp - floating-point base-e exponential.
235.172 +--
235.173 +-- This routine computes the base-e exponential e ** x. */
235.174 +
235.175 +double fp_exp(MPL *mpl, double x)
235.176 +{ if (x > 0.999 * log(DBL_MAX))
235.177 + error(mpl, "exp(%.*g); floating-point overflow", DBL_DIG, x);
235.178 + return exp(x);
235.179 +}
235.180 +
235.181 +/*----------------------------------------------------------------------
235.182 +-- fp_log - floating-point natural logarithm.
235.183 +--
235.184 +-- This routine computes the natural logarithm log x. */
235.185 +
235.186 +double fp_log(MPL *mpl, double x)
235.187 +{ if (x <= 0.0)
235.188 + error(mpl, "log(%.*g); non-positive argument", DBL_DIG, x);
235.189 + return log(x);
235.190 +}
235.191 +
235.192 +/*----------------------------------------------------------------------
235.193 +-- fp_log10 - floating-point common (decimal) logarithm.
235.194 +--
235.195 +-- This routine computes the common (decimal) logarithm lg x. */
235.196 +
235.197 +double fp_log10(MPL *mpl, double x)
235.198 +{ if (x <= 0.0)
235.199 + error(mpl, "log10(%.*g); non-positive argument", DBL_DIG, x);
235.200 + return log10(x);
235.201 +}
235.202 +
235.203 +/*----------------------------------------------------------------------
235.204 +-- fp_sqrt - floating-point square root.
235.205 +--
235.206 +-- This routine computes the square root x ** 0.5. */
235.207 +
235.208 +double fp_sqrt(MPL *mpl, double x)
235.209 +{ if (x < 0.0)
235.210 + error(mpl, "sqrt(%.*g); negative argument", DBL_DIG, x);
235.211 + return sqrt(x);
235.212 +}
235.213 +
235.214 +/*----------------------------------------------------------------------
235.215 +-- fp_sin - floating-point trigonometric sine.
235.216 +--
235.217 +-- This routine computes the trigonometric sine sin(x). */
235.218 +
235.219 +double fp_sin(MPL *mpl, double x)
235.220 +{ if (!(-1e6 <= x && x <= +1e6))
235.221 + error(mpl, "sin(%.*g); argument too large", DBL_DIG, x);
235.222 + return sin(x);
235.223 +}
235.224 +
235.225 +/*----------------------------------------------------------------------
235.226 +-- fp_cos - floating-point trigonometric cosine.
235.227 +--
235.228 +-- This routine computes the trigonometric cosine cos(x). */
235.229 +
235.230 +double fp_cos(MPL *mpl, double x)
235.231 +{ if (!(-1e6 <= x && x <= +1e6))
235.232 + error(mpl, "cos(%.*g); argument too large", DBL_DIG, x);
235.233 + return cos(x);
235.234 +}
235.235 +
235.236 +/*----------------------------------------------------------------------
235.237 +-- fp_atan - floating-point trigonometric arctangent.
235.238 +--
235.239 +-- This routine computes the trigonometric arctangent atan(x). */
235.240 +
235.241 +double fp_atan(MPL *mpl, double x)
235.242 +{ xassert(mpl == mpl);
235.243 + return atan(x);
235.244 +}
235.245 +
235.246 +/*----------------------------------------------------------------------
235.247 +-- fp_atan2 - floating-point trigonometric arctangent.
235.248 +--
235.249 +-- This routine computes the trigonometric arctangent atan(y / x). */
235.250 +
235.251 +double fp_atan2(MPL *mpl, double y, double x)
235.252 +{ xassert(mpl == mpl);
235.253 + return atan2(y, x);
235.254 +}
235.255 +
235.256 +/*----------------------------------------------------------------------
235.257 +-- fp_round - round floating-point value to n fractional digits.
235.258 +--
235.259 +-- This routine rounds given floating-point value x to n fractional
235.260 +-- digits with the formula:
235.261 +--
235.262 +-- round(x, n) = floor(x * 10^n + 0.5) / 10^n.
235.263 +--
235.264 +-- The parameter n is assumed to be integer. */
235.265 +
235.266 +double fp_round(MPL *mpl, double x, double n)
235.267 +{ double ten_to_n;
235.268 + if (n != floor(n))
235.269 + error(mpl, "round(%.*g, %.*g); non-integer second argument",
235.270 + DBL_DIG, x, DBL_DIG, n);
235.271 + if (n <= DBL_DIG + 2)
235.272 + { ten_to_n = pow(10.0, n);
235.273 + if (fabs(x) < (0.999 * DBL_MAX) / ten_to_n)
235.274 + { x = floor(x * ten_to_n + 0.5);
235.275 + if (x != 0.0) x /= ten_to_n;
235.276 + }
235.277 + }
235.278 + return x;
235.279 +}
235.280 +
235.281 +/*----------------------------------------------------------------------
235.282 +-- fp_trunc - truncate floating-point value to n fractional digits.
235.283 +--
235.284 +-- This routine truncates given floating-point value x to n fractional
235.285 +-- digits with the formula:
235.286 +--
235.287 +-- ( floor(x * 10^n) / 10^n, if x >= 0
235.288 +-- trunc(x, n) = <
235.289 +-- ( ceil(x * 10^n) / 10^n, if x < 0
235.290 +--
235.291 +-- The parameter n is assumed to be integer. */
235.292 +
235.293 +double fp_trunc(MPL *mpl, double x, double n)
235.294 +{ double ten_to_n;
235.295 + if (n != floor(n))
235.296 + error(mpl, "trunc(%.*g, %.*g); non-integer second argument",
235.297 + DBL_DIG, x, DBL_DIG, n);
235.298 + if (n <= DBL_DIG + 2)
235.299 + { ten_to_n = pow(10.0, n);
235.300 + if (fabs(x) < (0.999 * DBL_MAX) / ten_to_n)
235.301 + { x = (x >= 0.0 ? floor(x * ten_to_n) : ceil(x * ten_to_n));
235.302 + if (x != 0.0) x /= ten_to_n;
235.303 + }
235.304 + }
235.305 + return x;
235.306 +}
235.307 +
235.308 +/**********************************************************************/
235.309 +/* * * PSEUDO-RANDOM NUMBER GENERATORS * * */
235.310 +/**********************************************************************/
235.311 +
235.312 +/*----------------------------------------------------------------------
235.313 +-- fp_irand224 - pseudo-random integer in the range [0, 2^24).
235.314 +--
235.315 +-- This routine returns a next pseudo-random integer (converted to
235.316 +-- floating-point) which is uniformly distributed between 0 and 2^24-1,
235.317 +-- inclusive. */
235.318 +
235.319 +#define two_to_the_24 0x1000000
235.320 +
235.321 +double fp_irand224(MPL *mpl)
235.322 +{ return
235.323 + (double)rng_unif_rand(mpl->rand, two_to_the_24);
235.324 +}
235.325 +
235.326 +/*----------------------------------------------------------------------
235.327 +-- fp_uniform01 - pseudo-random number in the range [0, 1).
235.328 +--
235.329 +-- This routine returns a next pseudo-random number which is uniformly
235.330 +-- distributed in the range [0, 1). */
235.331 +
235.332 +#define two_to_the_31 ((unsigned int)0x80000000)
235.333 +
235.334 +double fp_uniform01(MPL *mpl)
235.335 +{ return
235.336 + (double)rng_next_rand(mpl->rand) / (double)two_to_the_31;
235.337 +}
235.338 +
235.339 +/*----------------------------------------------------------------------
235.340 +-- fp_uniform - pseudo-random number in the range [a, b).
235.341 +--
235.342 +-- This routine returns a next pseudo-random number which is uniformly
235.343 +-- distributed in the range [a, b). */
235.344 +
235.345 +double fp_uniform(MPL *mpl, double a, double b)
235.346 +{ double x;
235.347 + if (a >= b)
235.348 + error(mpl, "Uniform(%.*g, %.*g); invalid range",
235.349 + DBL_DIG, a, DBL_DIG, b);
235.350 + x = fp_uniform01(mpl);
235.351 +#if 0
235.352 + x = a * (1.0 - x) + b * x;
235.353 +#else
235.354 + x = fp_add(mpl, a * (1.0 - x), b * x);
235.355 +#endif
235.356 + return x;
235.357 +}
235.358 +
235.359 +/*----------------------------------------------------------------------
235.360 +-- fp_normal01 - Gaussian random variate with mu = 0 and sigma = 1.
235.361 +--
235.362 +-- This routine returns a Gaussian random variate with zero mean and
235.363 +-- unit standard deviation. The polar (Box-Mueller) method is used.
235.364 +--
235.365 +-- This code is a modified version of the routine gsl_ran_gaussian from
235.366 +-- the GNU Scientific Library Version 1.0. */
235.367 +
235.368 +double fp_normal01(MPL *mpl)
235.369 +{ double x, y, r2;
235.370 + do
235.371 + { /* choose x, y in uniform square (-1,-1) to (+1,+1) */
235.372 + x = -1.0 + 2.0 * fp_uniform01(mpl);
235.373 + y = -1.0 + 2.0 * fp_uniform01(mpl);
235.374 + /* see if it is in the unit circle */
235.375 + r2 = x * x + y * y;
235.376 + } while (r2 > 1.0 || r2 == 0.0);
235.377 + /* Box-Muller transform */
235.378 + return y * sqrt(-2.0 * log (r2) / r2);
235.379 +}
235.380 +
235.381 +/*----------------------------------------------------------------------
235.382 +-- fp_normal - Gaussian random variate with specified mu and sigma.
235.383 +--
235.384 +-- This routine returns a Gaussian random variate with mean mu and
235.385 +-- standard deviation sigma. */
235.386 +
235.387 +double fp_normal(MPL *mpl, double mu, double sigma)
235.388 +{ double x;
235.389 +#if 0
235.390 + x = mu + sigma * fp_normal01(mpl);
235.391 +#else
235.392 + x = fp_add(mpl, mu, fp_mul(mpl, sigma, fp_normal01(mpl)));
235.393 +#endif
235.394 + return x;
235.395 +}
235.396 +
235.397 +/**********************************************************************/
235.398 +/* * * SEGMENTED CHARACTER STRINGS * * */
235.399 +/**********************************************************************/
235.400 +
235.401 +/*----------------------------------------------------------------------
235.402 +-- create_string - create character string.
235.403 +--
235.404 +-- This routine creates a segmented character string, which is exactly
235.405 +-- equivalent to specified character string. */
235.406 +
235.407 +STRING *create_string
235.408 +( MPL *mpl,
235.409 + char buf[MAX_LENGTH+1] /* not changed */
235.410 +)
235.411 +#if 0
235.412 +{ STRING *head, *tail;
235.413 + int i, j;
235.414 + xassert(buf != NULL);
235.415 + xassert(strlen(buf) <= MAX_LENGTH);
235.416 + head = tail = dmp_get_atom(mpl->strings, sizeof(STRING));
235.417 + for (i = j = 0; ; i++)
235.418 + { if ((tail->seg[j++] = buf[i]) == '\0') break;
235.419 + if (j == STRSEG_SIZE)
235.420 +tail = (tail->next = dmp_get_atom(mpl->strings, sizeof(STRING))), j = 0;
235.421 + }
235.422 + tail->next = NULL;
235.423 + return head;
235.424 +}
235.425 +#else
235.426 +{ STRING *str;
235.427 + xassert(strlen(buf) <= MAX_LENGTH);
235.428 + str = dmp_get_atom(mpl->strings, strlen(buf)+1);
235.429 + strcpy(str, buf);
235.430 + return str;
235.431 +}
235.432 +#endif
235.433 +
235.434 +/*----------------------------------------------------------------------
235.435 +-- copy_string - make copy of character string.
235.436 +--
235.437 +-- This routine returns an exact copy of segmented character string. */
235.438 +
235.439 +STRING *copy_string
235.440 +( MPL *mpl,
235.441 + STRING *str /* not changed */
235.442 +)
235.443 +#if 0
235.444 +{ STRING *head, *tail;
235.445 + xassert(str != NULL);
235.446 + head = tail = dmp_get_atom(mpl->strings, sizeof(STRING));
235.447 + for (; str != NULL; str = str->next)
235.448 + { memcpy(tail->seg, str->seg, STRSEG_SIZE);
235.449 + if (str->next != NULL)
235.450 +tail = (tail->next = dmp_get_atom(mpl->strings, sizeof(STRING)));
235.451 + }
235.452 + tail->next = NULL;
235.453 + return head;
235.454 +}
235.455 +#else
235.456 +{ xassert(mpl == mpl);
235.457 + return create_string(mpl, str);
235.458 +}
235.459 +#endif
235.460 +
235.461 +/*----------------------------------------------------------------------
235.462 +-- compare_strings - compare one character string with another.
235.463 +--
235.464 +-- This routine compares one segmented character strings with another
235.465 +-- and returns the result of comparison as follows:
235.466 +--
235.467 +-- = 0 - both strings are identical;
235.468 +-- < 0 - the first string precedes the second one;
235.469 +-- > 0 - the first string follows the second one. */
235.470 +
235.471 +int compare_strings
235.472 +( MPL *mpl,
235.473 + STRING *str1, /* not changed */
235.474 + STRING *str2 /* not changed */
235.475 +)
235.476 +#if 0
235.477 +{ int j, c1, c2;
235.478 + xassert(mpl == mpl);
235.479 + for (;; str1 = str1->next, str2 = str2->next)
235.480 + { xassert(str1 != NULL);
235.481 + xassert(str2 != NULL);
235.482 + for (j = 0; j < STRSEG_SIZE; j++)
235.483 + { c1 = (unsigned char)str1->seg[j];
235.484 + c2 = (unsigned char)str2->seg[j];
235.485 + if (c1 < c2) return -1;
235.486 + if (c1 > c2) return +1;
235.487 + if (c1 == '\0') goto done;
235.488 + }
235.489 + }
235.490 +done: return 0;
235.491 +}
235.492 +#else
235.493 +{ xassert(mpl == mpl);
235.494 + return strcmp(str1, str2);
235.495 +}
235.496 +#endif
235.497 +
235.498 +/*----------------------------------------------------------------------
235.499 +-- fetch_string - extract content of character string.
235.500 +--
235.501 +-- This routine returns a character string, which is exactly equivalent
235.502 +-- to specified segmented character string. */
235.503 +
235.504 +char *fetch_string
235.505 +( MPL *mpl,
235.506 + STRING *str, /* not changed */
235.507 + char buf[MAX_LENGTH+1] /* modified */
235.508 +)
235.509 +#if 0
235.510 +{ int i, j;
235.511 + xassert(mpl == mpl);
235.512 + xassert(buf != NULL);
235.513 + for (i = 0; ; str = str->next)
235.514 + { xassert(str != NULL);
235.515 + for (j = 0; j < STRSEG_SIZE; j++)
235.516 + if ((buf[i++] = str->seg[j]) == '\0') goto done;
235.517 + }
235.518 +done: xassert(strlen(buf) <= MAX_LENGTH);
235.519 + return buf;
235.520 +}
235.521 +#else
235.522 +{ xassert(mpl == mpl);
235.523 + return strcpy(buf, str);
235.524 +}
235.525 +#endif
235.526 +
235.527 +/*----------------------------------------------------------------------
235.528 +-- delete_string - delete character string.
235.529 +--
235.530 +-- This routine deletes specified segmented character string. */
235.531 +
235.532 +void delete_string
235.533 +( MPL *mpl,
235.534 + STRING *str /* destroyed */
235.535 +)
235.536 +#if 0
235.537 +{ STRING *temp;
235.538 + xassert(str != NULL);
235.539 + while (str != NULL)
235.540 + { temp = str;
235.541 + str = str->next;
235.542 + dmp_free_atom(mpl->strings, temp, sizeof(STRING));
235.543 + }
235.544 + return;
235.545 +}
235.546 +#else
235.547 +{ dmp_free_atom(mpl->strings, str, strlen(str)+1);
235.548 + return;
235.549 +}
235.550 +#endif
235.551 +
235.552 +/**********************************************************************/
235.553 +/* * * SYMBOLS * * */
235.554 +/**********************************************************************/
235.555 +
235.556 +/*----------------------------------------------------------------------
235.557 +-- create_symbol_num - create symbol of numeric type.
235.558 +--
235.559 +-- This routine creates a symbol, which has a numeric value specified
235.560 +-- as floating-point number. */
235.561 +
235.562 +SYMBOL *create_symbol_num(MPL *mpl, double num)
235.563 +{ SYMBOL *sym;
235.564 + sym = dmp_get_atom(mpl->symbols, sizeof(SYMBOL));
235.565 + sym->num = num;
235.566 + sym->str = NULL;
235.567 + return sym;
235.568 +}
235.569 +
235.570 +/*----------------------------------------------------------------------
235.571 +-- create_symbol_str - create symbol of abstract type.
235.572 +--
235.573 +-- This routine creates a symbol, which has an abstract value specified
235.574 +-- as segmented character string. */
235.575 +
235.576 +SYMBOL *create_symbol_str
235.577 +( MPL *mpl,
235.578 + STRING *str /* destroyed */
235.579 +)
235.580 +{ SYMBOL *sym;
235.581 + xassert(str != NULL);
235.582 + sym = dmp_get_atom(mpl->symbols, sizeof(SYMBOL));
235.583 + sym->num = 0.0;
235.584 + sym->str = str;
235.585 + return sym;
235.586 +}
235.587 +
235.588 +/*----------------------------------------------------------------------
235.589 +-- copy_symbol - make copy of symbol.
235.590 +--
235.591 +-- This routine returns an exact copy of symbol. */
235.592 +
235.593 +SYMBOL *copy_symbol
235.594 +( MPL *mpl,
235.595 + SYMBOL *sym /* not changed */
235.596 +)
235.597 +{ SYMBOL *copy;
235.598 + xassert(sym != NULL);
235.599 + copy = dmp_get_atom(mpl->symbols, sizeof(SYMBOL));
235.600 + if (sym->str == NULL)
235.601 + { copy->num = sym->num;
235.602 + copy->str = NULL;
235.603 + }
235.604 + else
235.605 + { copy->num = 0.0;
235.606 + copy->str = copy_string(mpl, sym->str);
235.607 + }
235.608 + return copy;
235.609 +}
235.610 +
235.611 +/*----------------------------------------------------------------------
235.612 +-- compare_symbols - compare one symbol with another.
235.613 +--
235.614 +-- This routine compares one symbol with another and returns the result
235.615 +-- of comparison as follows:
235.616 +--
235.617 +-- = 0 - both symbols are identical;
235.618 +-- < 0 - the first symbol precedes the second one;
235.619 +-- > 0 - the first symbol follows the second one.
235.620 +--
235.621 +-- Note that the linear order, in which symbols follow each other, is
235.622 +-- implementation-dependent. It may be not an alphabetical order. */
235.623 +
235.624 +int compare_symbols
235.625 +( MPL *mpl,
235.626 + SYMBOL *sym1, /* not changed */
235.627 + SYMBOL *sym2 /* not changed */
235.628 +)
235.629 +{ xassert(sym1 != NULL);
235.630 + xassert(sym2 != NULL);
235.631 + /* let all numeric quantities precede all symbolic quantities */
235.632 + if (sym1->str == NULL && sym2->str == NULL)
235.633 + { if (sym1->num < sym2->num) return -1;
235.634 + if (sym1->num > sym2->num) return +1;
235.635 + return 0;
235.636 + }
235.637 + if (sym1->str == NULL) return -1;
235.638 + if (sym2->str == NULL) return +1;
235.639 + return compare_strings(mpl, sym1->str, sym2->str);
235.640 +}
235.641 +
235.642 +/*----------------------------------------------------------------------
235.643 +-- delete_symbol - delete symbol.
235.644 +--
235.645 +-- This routine deletes specified symbol. */
235.646 +
235.647 +void delete_symbol
235.648 +( MPL *mpl,
235.649 + SYMBOL *sym /* destroyed */
235.650 +)
235.651 +{ xassert(sym != NULL);
235.652 + if (sym->str != NULL) delete_string(mpl, sym->str);
235.653 + dmp_free_atom(mpl->symbols, sym, sizeof(SYMBOL));
235.654 + return;
235.655 +}
235.656 +
235.657 +/*----------------------------------------------------------------------
235.658 +-- format_symbol - format symbol for displaying or printing.
235.659 +--
235.660 +-- This routine converts specified symbol to a charater string, which
235.661 +-- is suitable for displaying or printing.
235.662 +--
235.663 +-- The resultant string is never longer than 255 characters. If it gets
235.664 +-- longer, it is truncated from the right and appended by dots. */
235.665 +
235.666 +char *format_symbol
235.667 +( MPL *mpl,
235.668 + SYMBOL *sym /* not changed */
235.669 +)
235.670 +{ char *buf = mpl->sym_buf;
235.671 + xassert(sym != NULL);
235.672 + if (sym->str == NULL)
235.673 + sprintf(buf, "%.*g", DBL_DIG, sym->num);
235.674 + else
235.675 + { char str[MAX_LENGTH+1];
235.676 + int quoted, j, len;
235.677 + fetch_string(mpl, sym->str, str);
235.678 + if (!(isalpha((unsigned char)str[0]) || str[0] == '_'))
235.679 + quoted = 1;
235.680 + else
235.681 + { quoted = 0;
235.682 + for (j = 1; str[j] != '\0'; j++)
235.683 + { if (!(isalnum((unsigned char)str[j]) ||
235.684 + strchr("+-._", (unsigned char)str[j]) != NULL))
235.685 + { quoted = 1;
235.686 + break;
235.687 + }
235.688 + }
235.689 + }
235.690 +# define safe_append(c) \
235.691 + (void)(len < 255 ? (buf[len++] = (char)(c)) : 0)
235.692 + buf[0] = '\0', len = 0;
235.693 + if (quoted) safe_append('\'');
235.694 + for (j = 0; str[j] != '\0'; j++)
235.695 + { if (quoted && str[j] == '\'') safe_append('\'');
235.696 + safe_append(str[j]);
235.697 + }
235.698 + if (quoted) safe_append('\'');
235.699 +# undef safe_append
235.700 + buf[len] = '\0';
235.701 + if (len == 255) strcpy(buf+252, "...");
235.702 + }
235.703 + xassert(strlen(buf) <= 255);
235.704 + return buf;
235.705 +}
235.706 +
235.707 +/*----------------------------------------------------------------------
235.708 +-- concat_symbols - concatenate one symbol with another.
235.709 +--
235.710 +-- This routine concatenates values of two given symbols and assigns
235.711 +-- the resultant character string to a new symbol, which is returned on
235.712 +-- exit. Both original symbols are destroyed. */
235.713 +
235.714 +SYMBOL *concat_symbols
235.715 +( MPL *mpl,
235.716 + SYMBOL *sym1, /* destroyed */
235.717 + SYMBOL *sym2 /* destroyed */
235.718 +)
235.719 +{ char str1[MAX_LENGTH+1], str2[MAX_LENGTH+1];
235.720 + xassert(MAX_LENGTH >= DBL_DIG + DBL_DIG);
235.721 + if (sym1->str == NULL)
235.722 + sprintf(str1, "%.*g", DBL_DIG, sym1->num);
235.723 + else
235.724 + fetch_string(mpl, sym1->str, str1);
235.725 + if (sym2->str == NULL)
235.726 + sprintf(str2, "%.*g", DBL_DIG, sym2->num);
235.727 + else
235.728 + fetch_string(mpl, sym2->str, str2);
235.729 + if (strlen(str1) + strlen(str2) > MAX_LENGTH)
235.730 + { char buf[255+1];
235.731 + strcpy(buf, format_symbol(mpl, sym1));
235.732 + xassert(strlen(buf) < sizeof(buf));
235.733 + error(mpl, "%s & %s; resultant symbol exceeds %d characters",
235.734 + buf, format_symbol(mpl, sym2), MAX_LENGTH);
235.735 + }
235.736 + delete_symbol(mpl, sym1);
235.737 + delete_symbol(mpl, sym2);
235.738 + return create_symbol_str(mpl, create_string(mpl, strcat(str1,
235.739 + str2)));
235.740 +}
235.741 +
235.742 +/**********************************************************************/
235.743 +/* * * N-TUPLES * * */
235.744 +/**********************************************************************/
235.745 +
235.746 +/*----------------------------------------------------------------------
235.747 +-- create_tuple - create n-tuple.
235.748 +--
235.749 +-- This routine creates a n-tuple, which initially has no components,
235.750 +-- i.e. which is 0-tuple. */
235.751 +
235.752 +TUPLE *create_tuple(MPL *mpl)
235.753 +{ TUPLE *tuple;
235.754 + xassert(mpl == mpl);
235.755 + tuple = NULL;
235.756 + return tuple;
235.757 +}
235.758 +
235.759 +/*----------------------------------------------------------------------
235.760 +-- expand_tuple - append symbol to n-tuple.
235.761 +--
235.762 +-- This routine expands n-tuple appending to it a given symbol, which
235.763 +-- becomes its new last component. */
235.764 +
235.765 +TUPLE *expand_tuple
235.766 +( MPL *mpl,
235.767 + TUPLE *tuple, /* destroyed */
235.768 + SYMBOL *sym /* destroyed */
235.769 +)
235.770 +{ TUPLE *tail, *temp;
235.771 + xassert(sym != NULL);
235.772 + /* create a new component */
235.773 + tail = dmp_get_atom(mpl->tuples, sizeof(TUPLE));
235.774 + tail->sym = sym;
235.775 + tail->next = NULL;
235.776 + /* and append it to the component list */
235.777 + if (tuple == NULL)
235.778 + tuple = tail;
235.779 + else
235.780 + { for (temp = tuple; temp->next != NULL; temp = temp->next);
235.781 + temp->next = tail;
235.782 + }
235.783 + return tuple;
235.784 +}
235.785 +
235.786 +/*----------------------------------------------------------------------
235.787 +-- tuple_dimen - determine dimension of n-tuple.
235.788 +--
235.789 +-- This routine returns dimension of n-tuple, i.e. number of components
235.790 +-- in the n-tuple. */
235.791 +
235.792 +int tuple_dimen
235.793 +( MPL *mpl,
235.794 + TUPLE *tuple /* not changed */
235.795 +)
235.796 +{ TUPLE *temp;
235.797 + int dim = 0;
235.798 + xassert(mpl == mpl);
235.799 + for (temp = tuple; temp != NULL; temp = temp->next) dim++;
235.800 + return dim;
235.801 +}
235.802 +
235.803 +/*----------------------------------------------------------------------
235.804 +-- copy_tuple - make copy of n-tuple.
235.805 +--
235.806 +-- This routine returns an exact copy of n-tuple. */
235.807 +
235.808 +TUPLE *copy_tuple
235.809 +( MPL *mpl,
235.810 + TUPLE *tuple /* not changed */
235.811 +)
235.812 +{ TUPLE *head, *tail;
235.813 + if (tuple == NULL)
235.814 + head = NULL;
235.815 + else
235.816 + { head = tail = dmp_get_atom(mpl->tuples, sizeof(TUPLE));
235.817 + for (; tuple != NULL; tuple = tuple->next)
235.818 + { xassert(tuple->sym != NULL);
235.819 + tail->sym = copy_symbol(mpl, tuple->sym);
235.820 + if (tuple->next != NULL)
235.821 +tail = (tail->next = dmp_get_atom(mpl->tuples, sizeof(TUPLE)));
235.822 + }
235.823 + tail->next = NULL;
235.824 + }
235.825 + return head;
235.826 +}
235.827 +
235.828 +/*----------------------------------------------------------------------
235.829 +-- compare_tuples - compare one n-tuple with another.
235.830 +--
235.831 +-- This routine compares two given n-tuples, which must have the same
235.832 +-- dimension (not checked for the sake of efficiency), and returns one
235.833 +-- of the following codes:
235.834 +--
235.835 +-- = 0 - both n-tuples are identical;
235.836 +-- < 0 - the first n-tuple precedes the second one;
235.837 +-- > 0 - the first n-tuple follows the second one.
235.838 +--
235.839 +-- Note that the linear order, in which n-tuples follow each other, is
235.840 +-- implementation-dependent. It may be not an alphabetical order. */
235.841 +
235.842 +int compare_tuples
235.843 +( MPL *mpl,
235.844 + TUPLE *tuple1, /* not changed */
235.845 + TUPLE *tuple2 /* not changed */
235.846 +)
235.847 +{ TUPLE *item1, *item2;
235.848 + int ret;
235.849 + xassert(mpl == mpl);
235.850 + for (item1 = tuple1, item2 = tuple2; item1 != NULL;
235.851 + item1 = item1->next, item2 = item2->next)
235.852 + { xassert(item2 != NULL);
235.853 + xassert(item1->sym != NULL);
235.854 + xassert(item2->sym != NULL);
235.855 + ret = compare_symbols(mpl, item1->sym, item2->sym);
235.856 + if (ret != 0) return ret;
235.857 + }
235.858 + xassert(item2 == NULL);
235.859 + return 0;
235.860 +}
235.861 +
235.862 +/*----------------------------------------------------------------------
235.863 +-- build_subtuple - build subtuple of given n-tuple.
235.864 +--
235.865 +-- This routine builds subtuple, which consists of first dim components
235.866 +-- of given n-tuple. */
235.867 +
235.868 +TUPLE *build_subtuple
235.869 +( MPL *mpl,
235.870 + TUPLE *tuple, /* not changed */
235.871 + int dim
235.872 +)
235.873 +{ TUPLE *head, *temp;
235.874 + int j;
235.875 + head = create_tuple(mpl);
235.876 + for (j = 1, temp = tuple; j <= dim; j++, temp = temp->next)
235.877 + { xassert(temp != NULL);
235.878 + head = expand_tuple(mpl, head, copy_symbol(mpl, temp->sym));
235.879 + }
235.880 + return head;
235.881 +}
235.882 +
235.883 +/*----------------------------------------------------------------------
235.884 +-- delete_tuple - delete n-tuple.
235.885 +--
235.886 +-- This routine deletes specified n-tuple. */
235.887 +
235.888 +void delete_tuple
235.889 +( MPL *mpl,
235.890 + TUPLE *tuple /* destroyed */
235.891 +)
235.892 +{ TUPLE *temp;
235.893 + while (tuple != NULL)
235.894 + { temp = tuple;
235.895 + tuple = temp->next;
235.896 + xassert(temp->sym != NULL);
235.897 + delete_symbol(mpl, temp->sym);
235.898 + dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE));
235.899 + }
235.900 + return;
235.901 +}
235.902 +
235.903 +/*----------------------------------------------------------------------
235.904 +-- format_tuple - format n-tuple for displaying or printing.
235.905 +--
235.906 +-- This routine converts specified n-tuple to a character string, which
235.907 +-- is suitable for displaying or printing.
235.908 +--
235.909 +-- The resultant string is never longer than 255 characters. If it gets
235.910 +-- longer, it is truncated from the right and appended by dots. */
235.911 +
235.912 +char *format_tuple
235.913 +( MPL *mpl,
235.914 + int c,
235.915 + TUPLE *tuple /* not changed */
235.916 +)
235.917 +{ TUPLE *temp;
235.918 + int dim, j, len;
235.919 + char *buf = mpl->tup_buf, str[255+1], *save;
235.920 +# define safe_append(c) \
235.921 + (void)(len < 255 ? (buf[len++] = (char)(c)) : 0)
235.922 + buf[0] = '\0', len = 0;
235.923 + dim = tuple_dimen(mpl, tuple);
235.924 + if (c == '[' && dim > 0) safe_append('[');
235.925 + if (c == '(' && dim > 1) safe_append('(');
235.926 + for (temp = tuple; temp != NULL; temp = temp->next)
235.927 + { if (temp != tuple) safe_append(',');
235.928 + xassert(temp->sym != NULL);
235.929 + save = mpl->sym_buf;
235.930 + mpl->sym_buf = str;
235.931 + format_symbol(mpl, temp->sym);
235.932 + mpl->sym_buf = save;
235.933 + xassert(strlen(str) < sizeof(str));
235.934 + for (j = 0; str[j] != '\0'; j++) safe_append(str[j]);
235.935 + }
235.936 + if (c == '[' && dim > 0) safe_append(']');
235.937 + if (c == '(' && dim > 1) safe_append(')');
235.938 +# undef safe_append
235.939 + buf[len] = '\0';
235.940 + if (len == 255) strcpy(buf+252, "...");
235.941 + xassert(strlen(buf) <= 255);
235.942 + return buf;
235.943 +}
235.944 +
235.945 +/**********************************************************************/
235.946 +/* * * ELEMENTAL SETS * * */
235.947 +/**********************************************************************/
235.948 +
235.949 +/*----------------------------------------------------------------------
235.950 +-- create_elemset - create elemental set.
235.951 +--
235.952 +-- This routine creates an elemental set, whose members are n-tuples of
235.953 +-- specified dimension. Being created the set is initially empty. */
235.954 +
235.955 +ELEMSET *create_elemset(MPL *mpl, int dim)
235.956 +{ ELEMSET *set;
235.957 + xassert(dim > 0);
235.958 + set = create_array(mpl, A_NONE, dim);
235.959 + return set;
235.960 +}
235.961 +
235.962 +/*----------------------------------------------------------------------
235.963 +-- find_tuple - check if elemental set contains given n-tuple.
235.964 +--
235.965 +-- This routine finds given n-tuple in specified elemental set in order
235.966 +-- to check if the set contains that n-tuple. If the n-tuple is found,
235.967 +-- the routine returns pointer to corresponding array member. Otherwise
235.968 +-- null pointer is returned. */
235.969 +
235.970 +MEMBER *find_tuple
235.971 +( MPL *mpl,
235.972 + ELEMSET *set, /* not changed */
235.973 + TUPLE *tuple /* not changed */
235.974 +)
235.975 +{ xassert(set != NULL);
235.976 + xassert(set->type == A_NONE);
235.977 + xassert(set->dim == tuple_dimen(mpl, tuple));
235.978 + return find_member(mpl, set, tuple);
235.979 +}
235.980 +
235.981 +/*----------------------------------------------------------------------
235.982 +-- add_tuple - add new n-tuple to elemental set.
235.983 +--
235.984 +-- This routine adds given n-tuple to specified elemental set.
235.985 +--
235.986 +-- For the sake of efficiency this routine doesn't check whether the
235.987 +-- set already contains the same n-tuple or not. Therefore the calling
235.988 +-- program should use the routine find_tuple (if necessary) in order to
235.989 +-- make sure that the given n-tuple is not contained in the set, since
235.990 +-- duplicate n-tuples within the same set are not allowed. */
235.991 +
235.992 +MEMBER *add_tuple
235.993 +( MPL *mpl,
235.994 + ELEMSET *set, /* modified */
235.995 + TUPLE *tuple /* destroyed */
235.996 +)
235.997 +{ MEMBER *memb;
235.998 + xassert(set != NULL);
235.999 + xassert(set->type == A_NONE);
235.1000 + xassert(set->dim == tuple_dimen(mpl, tuple));
235.1001 + memb = add_member(mpl, set, tuple);
235.1002 + memb->value.none = NULL;
235.1003 + return memb;
235.1004 +}
235.1005 +
235.1006 +/*----------------------------------------------------------------------
235.1007 +-- check_then_add - check and add new n-tuple to elemental set.
235.1008 +--
235.1009 +-- This routine is equivalent to the routine add_tuple except that it
235.1010 +-- does check for duplicate n-tuples. */
235.1011 +
235.1012 +MEMBER *check_then_add
235.1013 +( MPL *mpl,
235.1014 + ELEMSET *set, /* modified */
235.1015 + TUPLE *tuple /* destroyed */
235.1016 +)
235.1017 +{ if (find_tuple(mpl, set, tuple) != NULL)
235.1018 + error(mpl, "duplicate tuple %s detected", format_tuple(mpl,
235.1019 + '(', tuple));
235.1020 + return add_tuple(mpl, set, tuple);
235.1021 +}
235.1022 +
235.1023 +/*----------------------------------------------------------------------
235.1024 +-- copy_elemset - make copy of elemental set.
235.1025 +--
235.1026 +-- This routine makes an exact copy of elemental set. */
235.1027 +
235.1028 +ELEMSET *copy_elemset
235.1029 +( MPL *mpl,
235.1030 + ELEMSET *set /* not changed */
235.1031 +)
235.1032 +{ ELEMSET *copy;
235.1033 + MEMBER *memb;
235.1034 + xassert(set != NULL);
235.1035 + xassert(set->type == A_NONE);
235.1036 + xassert(set->dim > 0);
235.1037 + copy = create_elemset(mpl, set->dim);
235.1038 + for (memb = set->head; memb != NULL; memb = memb->next)
235.1039 + add_tuple(mpl, copy, copy_tuple(mpl, memb->tuple));
235.1040 + return copy;
235.1041 +}
235.1042 +
235.1043 +/*----------------------------------------------------------------------
235.1044 +-- delete_elemset - delete elemental set.
235.1045 +--
235.1046 +-- This routine deletes specified elemental set. */
235.1047 +
235.1048 +void delete_elemset
235.1049 +( MPL *mpl,
235.1050 + ELEMSET *set /* destroyed */
235.1051 +)
235.1052 +{ xassert(set != NULL);
235.1053 + xassert(set->type == A_NONE);
235.1054 + delete_array(mpl, set);
235.1055 + return;
235.1056 +}
235.1057 +
235.1058 +/*----------------------------------------------------------------------
235.1059 +-- arelset_size - compute size of "arithmetic" elemental set.
235.1060 +--
235.1061 +-- This routine computes the size of "arithmetic" elemental set, which
235.1062 +-- is specified in the form of arithmetic progression:
235.1063 +--
235.1064 +-- { t0 .. tf by dt }.
235.1065 +--
235.1066 +-- The size is computed using the formula:
235.1067 +--
235.1068 +-- n = max(0, floor((tf - t0) / dt) + 1). */
235.1069 +
235.1070 +int arelset_size(MPL *mpl, double t0, double tf, double dt)
235.1071 +{ double temp;
235.1072 + if (dt == 0.0)
235.1073 + error(mpl, "%.*g .. %.*g by %.*g; zero stride not allowed",
235.1074 + DBL_DIG, t0, DBL_DIG, tf, DBL_DIG, dt);
235.1075 + if (tf > 0.0 && t0 < 0.0 && tf > + 0.999 * DBL_MAX + t0)
235.1076 + temp = +DBL_MAX;
235.1077 + else if (tf < 0.0 && t0 > 0.0 && tf < - 0.999 * DBL_MAX + t0)
235.1078 + temp = -DBL_MAX;
235.1079 + else
235.1080 + temp = tf - t0;
235.1081 + if (fabs(dt) < 1.0 && fabs(temp) > (0.999 * DBL_MAX) * fabs(dt))
235.1082 + { if (temp > 0.0 && dt > 0.0 || temp < 0.0 && dt < 0.0)
235.1083 + temp = +DBL_MAX;
235.1084 + else
235.1085 + temp = 0.0;
235.1086 + }
235.1087 + else
235.1088 + { temp = floor(temp / dt) + 1.0;
235.1089 + if (temp < 0.0) temp = 0.0;
235.1090 + }
235.1091 + xassert(temp >= 0.0);
235.1092 + if (temp > (double)(INT_MAX - 1))
235.1093 + error(mpl, "%.*g .. %.*g by %.*g; set too large",
235.1094 + DBL_DIG, t0, DBL_DIG, tf, DBL_DIG, dt);
235.1095 + return (int)(temp + 0.5);
235.1096 +}
235.1097 +
235.1098 +/*----------------------------------------------------------------------
235.1099 +-- arelset_member - compute member of "arithmetic" elemental set.
235.1100 +--
235.1101 +-- This routine returns a numeric value of symbol, which is equivalent
235.1102 +-- to j-th member of given "arithmetic" elemental set specified in the
235.1103 +-- form of arithmetic progression:
235.1104 +--
235.1105 +-- { t0 .. tf by dt }.
235.1106 +--
235.1107 +-- The symbol value is computed with the formula:
235.1108 +--
235.1109 +-- j-th member = t0 + (j - 1) * dt,
235.1110 +--
235.1111 +-- The number j must satisfy to the restriction 1 <= j <= n, where n is
235.1112 +-- the set size computed by the routine arelset_size. */
235.1113 +
235.1114 +double arelset_member(MPL *mpl, double t0, double tf, double dt, int j)
235.1115 +{ xassert(1 <= j && j <= arelset_size(mpl, t0, tf, dt));
235.1116 + return t0 + (double)(j - 1) * dt;
235.1117 +}
235.1118 +
235.1119 +/*----------------------------------------------------------------------
235.1120 +-- create_arelset - create "arithmetic" elemental set.
235.1121 +--
235.1122 +-- This routine creates "arithmetic" elemental set, which is specified
235.1123 +-- in the form of arithmetic progression:
235.1124 +--
235.1125 +-- { t0 .. tf by dt }.
235.1126 +--
235.1127 +-- Components of this set are 1-tuples. */
235.1128 +
235.1129 +ELEMSET *create_arelset(MPL *mpl, double t0, double tf, double dt)
235.1130 +{ ELEMSET *set;
235.1131 + int j, n;
235.1132 + set = create_elemset(mpl, 1);
235.1133 + n = arelset_size(mpl, t0, tf, dt);
235.1134 + for (j = 1; j <= n; j++)
235.1135 + { add_tuple
235.1136 + ( mpl,
235.1137 + set,
235.1138 + expand_tuple
235.1139 + ( mpl,
235.1140 + create_tuple(mpl),
235.1141 + create_symbol_num
235.1142 + ( mpl,
235.1143 + arelset_member(mpl, t0, tf, dt, j)
235.1144 + )
235.1145 + )
235.1146 + );
235.1147 + }
235.1148 + return set;
235.1149 +}
235.1150 +
235.1151 +/*----------------------------------------------------------------------
235.1152 +-- set_union - union of two elemental sets.
235.1153 +--
235.1154 +-- This routine computes the union:
235.1155 +--
235.1156 +-- X U Y = { j | (j in X) or (j in Y) },
235.1157 +--
235.1158 +-- where X and Y are given elemental sets (destroyed on exit). */
235.1159 +
235.1160 +ELEMSET *set_union
235.1161 +( MPL *mpl,
235.1162 + ELEMSET *X, /* destroyed */
235.1163 + ELEMSET *Y /* destroyed */
235.1164 +)
235.1165 +{ MEMBER *memb;
235.1166 + xassert(X != NULL);
235.1167 + xassert(X->type == A_NONE);
235.1168 + xassert(X->dim > 0);
235.1169 + xassert(Y != NULL);
235.1170 + xassert(Y->type == A_NONE);
235.1171 + xassert(Y->dim > 0);
235.1172 + xassert(X->dim == Y->dim);
235.1173 + for (memb = Y->head; memb != NULL; memb = memb->next)
235.1174 + { if (find_tuple(mpl, X, memb->tuple) == NULL)
235.1175 + add_tuple(mpl, X, copy_tuple(mpl, memb->tuple));
235.1176 + }
235.1177 + delete_elemset(mpl, Y);
235.1178 + return X;
235.1179 +}
235.1180 +
235.1181 +/*----------------------------------------------------------------------
235.1182 +-- set_diff - difference between two elemental sets.
235.1183 +--
235.1184 +-- This routine computes the difference:
235.1185 +--
235.1186 +-- X \ Y = { j | (j in X) and (j not in Y) },
235.1187 +--
235.1188 +-- where X and Y are given elemental sets (destroyed on exit). */
235.1189 +
235.1190 +ELEMSET *set_diff
235.1191 +( MPL *mpl,
235.1192 + ELEMSET *X, /* destroyed */
235.1193 + ELEMSET *Y /* destroyed */
235.1194 +)
235.1195 +{ ELEMSET *Z;
235.1196 + MEMBER *memb;
235.1197 + xassert(X != NULL);
235.1198 + xassert(X->type == A_NONE);
235.1199 + xassert(X->dim > 0);
235.1200 + xassert(Y != NULL);
235.1201 + xassert(Y->type == A_NONE);
235.1202 + xassert(Y->dim > 0);
235.1203 + xassert(X->dim == Y->dim);
235.1204 + Z = create_elemset(mpl, X->dim);
235.1205 + for (memb = X->head; memb != NULL; memb = memb->next)
235.1206 + { if (find_tuple(mpl, Y, memb->tuple) == NULL)
235.1207 + add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
235.1208 + }
235.1209 + delete_elemset(mpl, X);
235.1210 + delete_elemset(mpl, Y);
235.1211 + return Z;
235.1212 +}
235.1213 +
235.1214 +/*----------------------------------------------------------------------
235.1215 +-- set_symdiff - symmetric difference between two elemental sets.
235.1216 +--
235.1217 +-- This routine computes the symmetric difference:
235.1218 +--
235.1219 +-- X (+) Y = (X \ Y) U (Y \ X),
235.1220 +--
235.1221 +-- where X and Y are given elemental sets (destroyed on exit). */
235.1222 +
235.1223 +ELEMSET *set_symdiff
235.1224 +( MPL *mpl,
235.1225 + ELEMSET *X, /* destroyed */
235.1226 + ELEMSET *Y /* destroyed */
235.1227 +)
235.1228 +{ ELEMSET *Z;
235.1229 + MEMBER *memb;
235.1230 + xassert(X != NULL);
235.1231 + xassert(X->type == A_NONE);
235.1232 + xassert(X->dim > 0);
235.1233 + xassert(Y != NULL);
235.1234 + xassert(Y->type == A_NONE);
235.1235 + xassert(Y->dim > 0);
235.1236 + xassert(X->dim == Y->dim);
235.1237 + /* Z := X \ Y */
235.1238 + Z = create_elemset(mpl, X->dim);
235.1239 + for (memb = X->head; memb != NULL; memb = memb->next)
235.1240 + { if (find_tuple(mpl, Y, memb->tuple) == NULL)
235.1241 + add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
235.1242 + }
235.1243 + /* Z := Z U (Y \ X) */
235.1244 + for (memb = Y->head; memb != NULL; memb = memb->next)
235.1245 + { if (find_tuple(mpl, X, memb->tuple) == NULL)
235.1246 + add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
235.1247 + }
235.1248 + delete_elemset(mpl, X);
235.1249 + delete_elemset(mpl, Y);
235.1250 + return Z;
235.1251 +}
235.1252 +
235.1253 +/*----------------------------------------------------------------------
235.1254 +-- set_inter - intersection of two elemental sets.
235.1255 +--
235.1256 +-- This routine computes the intersection:
235.1257 +--
235.1258 +-- X ^ Y = { j | (j in X) and (j in Y) },
235.1259 +--
235.1260 +-- where X and Y are given elemental sets (destroyed on exit). */
235.1261 +
235.1262 +ELEMSET *set_inter
235.1263 +( MPL *mpl,
235.1264 + ELEMSET *X, /* destroyed */
235.1265 + ELEMSET *Y /* destroyed */
235.1266 +)
235.1267 +{ ELEMSET *Z;
235.1268 + MEMBER *memb;
235.1269 + xassert(X != NULL);
235.1270 + xassert(X->type == A_NONE);
235.1271 + xassert(X->dim > 0);
235.1272 + xassert(Y != NULL);
235.1273 + xassert(Y->type == A_NONE);
235.1274 + xassert(Y->dim > 0);
235.1275 + xassert(X->dim == Y->dim);
235.1276 + Z = create_elemset(mpl, X->dim);
235.1277 + for (memb = X->head; memb != NULL; memb = memb->next)
235.1278 + { if (find_tuple(mpl, Y, memb->tuple) != NULL)
235.1279 + add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
235.1280 + }
235.1281 + delete_elemset(mpl, X);
235.1282 + delete_elemset(mpl, Y);
235.1283 + return Z;
235.1284 +}
235.1285 +
235.1286 +/*----------------------------------------------------------------------
235.1287 +-- set_cross - cross (Cartesian) product of two elemental sets.
235.1288 +--
235.1289 +-- This routine computes the cross (Cartesian) product:
235.1290 +--
235.1291 +-- X x Y = { (i,j) | (i in X) and (j in Y) },
235.1292 +--
235.1293 +-- where X and Y are given elemental sets (destroyed on exit). */
235.1294 +
235.1295 +ELEMSET *set_cross
235.1296 +( MPL *mpl,
235.1297 + ELEMSET *X, /* destroyed */
235.1298 + ELEMSET *Y /* destroyed */
235.1299 +)
235.1300 +{ ELEMSET *Z;
235.1301 + MEMBER *memx, *memy;
235.1302 + TUPLE *tuple, *temp;
235.1303 + xassert(X != NULL);
235.1304 + xassert(X->type == A_NONE);
235.1305 + xassert(X->dim > 0);
235.1306 + xassert(Y != NULL);
235.1307 + xassert(Y->type == A_NONE);
235.1308 + xassert(Y->dim > 0);
235.1309 + Z = create_elemset(mpl, X->dim + Y->dim);
235.1310 + for (memx = X->head; memx != NULL; memx = memx->next)
235.1311 + { for (memy = Y->head; memy != NULL; memy = memy->next)
235.1312 + { tuple = copy_tuple(mpl, memx->tuple);
235.1313 + for (temp = memy->tuple; temp != NULL; temp = temp->next)
235.1314 + tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
235.1315 + temp->sym));
235.1316 + add_tuple(mpl, Z, tuple);
235.1317 + }
235.1318 + }
235.1319 + delete_elemset(mpl, X);
235.1320 + delete_elemset(mpl, Y);
235.1321 + return Z;
235.1322 +}
235.1323 +
235.1324 +/**********************************************************************/
235.1325 +/* * * ELEMENTAL VARIABLES * * */
235.1326 +/**********************************************************************/
235.1327 +
235.1328 +/* (there are no specific routines for elemental variables) */
235.1329 +
235.1330 +/**********************************************************************/
235.1331 +/* * * LINEAR FORMS * * */
235.1332 +/**********************************************************************/
235.1333 +
235.1334 +/*----------------------------------------------------------------------
235.1335 +-- constant_term - create constant term.
235.1336 +--
235.1337 +-- This routine creates the linear form, which is a constant term. */
235.1338 +
235.1339 +FORMULA *constant_term(MPL *mpl, double coef)
235.1340 +{ FORMULA *form;
235.1341 + if (coef == 0.0)
235.1342 + form = NULL;
235.1343 + else
235.1344 + { form = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
235.1345 + form->coef = coef;
235.1346 + form->var = NULL;
235.1347 + form->next = NULL;
235.1348 + }
235.1349 + return form;
235.1350 +}
235.1351 +
235.1352 +/*----------------------------------------------------------------------
235.1353 +-- single_variable - create single variable.
235.1354 +--
235.1355 +-- This routine creates the linear form, which is a single elemental
235.1356 +-- variable. */
235.1357 +
235.1358 +FORMULA *single_variable
235.1359 +( MPL *mpl,
235.1360 + ELEMVAR *var /* referenced */
235.1361 +)
235.1362 +{ FORMULA *form;
235.1363 + xassert(var != NULL);
235.1364 + form = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
235.1365 + form->coef = 1.0;
235.1366 + form->var = var;
235.1367 + form->next = NULL;
235.1368 + return form;
235.1369 +}
235.1370 +
235.1371 +/*----------------------------------------------------------------------
235.1372 +-- copy_formula - make copy of linear form.
235.1373 +--
235.1374 +-- This routine returns an exact copy of linear form. */
235.1375 +
235.1376 +FORMULA *copy_formula
235.1377 +( MPL *mpl,
235.1378 + FORMULA *form /* not changed */
235.1379 +)
235.1380 +{ FORMULA *head, *tail;
235.1381 + if (form == NULL)
235.1382 + head = NULL;
235.1383 + else
235.1384 + { head = tail = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
235.1385 + for (; form != NULL; form = form->next)
235.1386 + { tail->coef = form->coef;
235.1387 + tail->var = form->var;
235.1388 + if (form->next != NULL)
235.1389 +tail = (tail->next = dmp_get_atom(mpl->formulae, sizeof(FORMULA)));
235.1390 + }
235.1391 + tail->next = NULL;
235.1392 + }
235.1393 + return head;
235.1394 +}
235.1395 +
235.1396 +/*----------------------------------------------------------------------
235.1397 +-- delete_formula - delete linear form.
235.1398 +--
235.1399 +-- This routine deletes specified linear form. */
235.1400 +
235.1401 +void delete_formula
235.1402 +( MPL *mpl,
235.1403 + FORMULA *form /* destroyed */
235.1404 +)
235.1405 +{ FORMULA *temp;
235.1406 + while (form != NULL)
235.1407 + { temp = form;
235.1408 + form = form->next;
235.1409 + dmp_free_atom(mpl->formulae, temp, sizeof(FORMULA));
235.1410 + }
235.1411 + return;
235.1412 +}
235.1413 +
235.1414 +/*----------------------------------------------------------------------
235.1415 +-- linear_comb - linear combination of two linear forms.
235.1416 +--
235.1417 +-- This routine computes the linear combination:
235.1418 +--
235.1419 +-- a * fx + b * fy,
235.1420 +--
235.1421 +-- where a and b are numeric coefficients, fx and fy are linear forms
235.1422 +-- (destroyed on exit). */
235.1423 +
235.1424 +FORMULA *linear_comb
235.1425 +( MPL *mpl,
235.1426 + double a, FORMULA *fx, /* destroyed */
235.1427 + double b, FORMULA *fy /* destroyed */
235.1428 +)
235.1429 +{ FORMULA *form = NULL, *term, *temp;
235.1430 + double c0 = 0.0;
235.1431 + for (term = fx; term != NULL; term = term->next)
235.1432 + { if (term->var == NULL)
235.1433 + c0 = fp_add(mpl, c0, fp_mul(mpl, a, term->coef));
235.1434 + else
235.1435 + term->var->temp =
235.1436 + fp_add(mpl, term->var->temp, fp_mul(mpl, a, term->coef));
235.1437 + }
235.1438 + for (term = fy; term != NULL; term = term->next)
235.1439 + { if (term->var == NULL)
235.1440 + c0 = fp_add(mpl, c0, fp_mul(mpl, b, term->coef));
235.1441 + else
235.1442 + term->var->temp =
235.1443 + fp_add(mpl, term->var->temp, fp_mul(mpl, b, term->coef));
235.1444 + }
235.1445 + for (term = fx; term != NULL; term = term->next)
235.1446 + { if (term->var != NULL && term->var->temp != 0.0)
235.1447 + { temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
235.1448 + temp->coef = term->var->temp, temp->var = term->var;
235.1449 + temp->next = form, form = temp;
235.1450 + term->var->temp = 0.0;
235.1451 + }
235.1452 + }
235.1453 + for (term = fy; term != NULL; term = term->next)
235.1454 + { if (term->var != NULL && term->var->temp != 0.0)
235.1455 + { temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
235.1456 + temp->coef = term->var->temp, temp->var = term->var;
235.1457 + temp->next = form, form = temp;
235.1458 + term->var->temp = 0.0;
235.1459 + }
235.1460 + }
235.1461 + if (c0 != 0.0)
235.1462 + { temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
235.1463 + temp->coef = c0, temp->var = NULL;
235.1464 + temp->next = form, form = temp;
235.1465 + }
235.1466 + delete_formula(mpl, fx);
235.1467 + delete_formula(mpl, fy);
235.1468 + return form;
235.1469 +}
235.1470 +
235.1471 +/*----------------------------------------------------------------------
235.1472 +-- remove_constant - remove constant term from linear form.
235.1473 +--
235.1474 +-- This routine removes constant term from linear form and stores its
235.1475 +-- value to given location. */
235.1476 +
235.1477 +FORMULA *remove_constant
235.1478 +( MPL *mpl,
235.1479 + FORMULA *form, /* destroyed */
235.1480 + double *coef /* modified */
235.1481 +)
235.1482 +{ FORMULA *head = NULL, *temp;
235.1483 + *coef = 0.0;
235.1484 + while (form != NULL)
235.1485 + { temp = form;
235.1486 + form = form->next;
235.1487 + if (temp->var == NULL)
235.1488 + { /* constant term */
235.1489 + *coef = fp_add(mpl, *coef, temp->coef);
235.1490 + dmp_free_atom(mpl->formulae, temp, sizeof(FORMULA));
235.1491 + }
235.1492 + else
235.1493 + { /* linear term */
235.1494 + temp->next = head;
235.1495 + head = temp;
235.1496 + }
235.1497 + }
235.1498 + return head;
235.1499 +}
235.1500 +
235.1501 +/*----------------------------------------------------------------------
235.1502 +-- reduce_terms - reduce identical terms in linear form.
235.1503 +--
235.1504 +-- This routine reduces identical terms in specified linear form. */
235.1505 +
235.1506 +FORMULA *reduce_terms
235.1507 +( MPL *mpl,
235.1508 + FORMULA *form /* destroyed */
235.1509 +)
235.1510 +{ FORMULA *term, *next_term;
235.1511 + double c0 = 0.0;
235.1512 + for (term = form; term != NULL; term = term->next)
235.1513 + { if (term->var == NULL)
235.1514 + c0 = fp_add(mpl, c0, term->coef);
235.1515 + else
235.1516 + term->var->temp = fp_add(mpl, term->var->temp, term->coef);
235.1517 + }
235.1518 + next_term = form, form = NULL;
235.1519 + for (term = next_term; term != NULL; term = next_term)
235.1520 + { next_term = term->next;
235.1521 + if (term->var == NULL && c0 != 0.0)
235.1522 + { term->coef = c0, c0 = 0.0;
235.1523 + term->next = form, form = term;
235.1524 + }
235.1525 + else if (term->var != NULL && term->var->temp != 0.0)
235.1526 + { term->coef = term->var->temp, term->var->temp = 0.0;
235.1527 + term->next = form, form = term;
235.1528 + }
235.1529 + else
235.1530 + dmp_free_atom(mpl->formulae, term, sizeof(FORMULA));
235.1531 + }
235.1532 + return form;
235.1533 +}
235.1534 +
235.1535 +/**********************************************************************/
235.1536 +/* * * ELEMENTAL CONSTRAINTS * * */
235.1537 +/**********************************************************************/
235.1538 +
235.1539 +/* (there are no specific routines for elemental constraints) */
235.1540 +
235.1541 +/**********************************************************************/
235.1542 +/* * * GENERIC VALUES * * */
235.1543 +/**********************************************************************/
235.1544 +
235.1545 +/*----------------------------------------------------------------------
235.1546 +-- delete_value - delete generic value.
235.1547 +--
235.1548 +-- This routine deletes specified generic value.
235.1549 +--
235.1550 +-- NOTE: The generic value to be deleted must be valid. */
235.1551 +
235.1552 +void delete_value
235.1553 +( MPL *mpl,
235.1554 + int type,
235.1555 + VALUE *value /* content destroyed */
235.1556 +)
235.1557 +{ xassert(value != NULL);
235.1558 + switch (type)
235.1559 + { case A_NONE:
235.1560 + value->none = NULL;
235.1561 + break;
235.1562 + case A_NUMERIC:
235.1563 + value->num = 0.0;
235.1564 + break;
235.1565 + case A_SYMBOLIC:
235.1566 + delete_symbol(mpl, value->sym), value->sym = NULL;
235.1567 + break;
235.1568 + case A_LOGICAL:
235.1569 + value->bit = 0;
235.1570 + break;
235.1571 + case A_TUPLE:
235.1572 + delete_tuple(mpl, value->tuple), value->tuple = NULL;
235.1573 + break;
235.1574 + case A_ELEMSET:
235.1575 + delete_elemset(mpl, value->set), value->set = NULL;
235.1576 + break;
235.1577 + case A_ELEMVAR:
235.1578 + value->var = NULL;
235.1579 + break;
235.1580 + case A_FORMULA:
235.1581 + delete_formula(mpl, value->form), value->form = NULL;
235.1582 + break;
235.1583 + case A_ELEMCON:
235.1584 + value->con = NULL;
235.1585 + break;
235.1586 + default:
235.1587 + xassert(type != type);
235.1588 + }
235.1589 + return;
235.1590 +}
235.1591 +
235.1592 +/**********************************************************************/
235.1593 +/* * * SYMBOLICALLY INDEXED ARRAYS * * */
235.1594 +/**********************************************************************/
235.1595 +
235.1596 +/*----------------------------------------------------------------------
235.1597 +-- create_array - create array.
235.1598 +--
235.1599 +-- This routine creates an array of specified type and dimension. Being
235.1600 +-- created the array is initially empty.
235.1601 +--
235.1602 +-- The type indicator determines generic values, which can be assigned
235.1603 +-- to the array members:
235.1604 +--
235.1605 +-- A_NONE - none (members have no assigned values)
235.1606 +-- A_NUMERIC - floating-point numbers
235.1607 +-- A_SYMBOLIC - symbols
235.1608 +-- A_ELEMSET - elemental sets
235.1609 +-- A_ELEMVAR - elemental variables
235.1610 +-- A_ELEMCON - elemental constraints
235.1611 +--
235.1612 +-- The dimension may be 0, in which case the array consists of the only
235.1613 +-- member (such arrays represent 0-dimensional objects). */
235.1614 +
235.1615 +ARRAY *create_array(MPL *mpl, int type, int dim)
235.1616 +{ ARRAY *array;
235.1617 + xassert(type == A_NONE || type == A_NUMERIC ||
235.1618 + type == A_SYMBOLIC || type == A_ELEMSET ||
235.1619 + type == A_ELEMVAR || type == A_ELEMCON);
235.1620 + xassert(dim >= 0);
235.1621 + array = dmp_get_atom(mpl->arrays, sizeof(ARRAY));
235.1622 + array->type = type;
235.1623 + array->dim = dim;
235.1624 + array->size = 0;
235.1625 + array->head = NULL;
235.1626 + array->tail = NULL;
235.1627 + array->tree = NULL;
235.1628 + array->prev = NULL;
235.1629 + array->next = mpl->a_list;
235.1630 + /* include the array in the global array list */
235.1631 + if (array->next != NULL) array->next->prev = array;
235.1632 + mpl->a_list = array;
235.1633 + return array;
235.1634 +}
235.1635 +
235.1636 +/*----------------------------------------------------------------------
235.1637 +-- find_member - find array member with given n-tuple.
235.1638 +--
235.1639 +-- This routine finds an array member, which has given n-tuple. If the
235.1640 +-- array is short, the linear search is used. Otherwise the routine
235.1641 +-- autimatically creates the search tree (i.e. the array index) to find
235.1642 +-- members for logarithmic time. */
235.1643 +
235.1644 +static int compare_member_tuples(void *info, const void *key1,
235.1645 + const void *key2)
235.1646 +{ /* this is an auxiliary routine used to compare keys, which are
235.1647 + n-tuples assigned to array members */
235.1648 + return compare_tuples((MPL *)info, (TUPLE *)key1, (TUPLE *)key2);
235.1649 +}
235.1650 +
235.1651 +MEMBER *find_member
235.1652 +( MPL *mpl,
235.1653 + ARRAY *array, /* not changed */
235.1654 + TUPLE *tuple /* not changed */
235.1655 +)
235.1656 +{ MEMBER *memb;
235.1657 + xassert(array != NULL);
235.1658 + /* the n-tuple must have the same dimension as the array */
235.1659 + xassert(tuple_dimen(mpl, tuple) == array->dim);
235.1660 + /* if the array is large enough, create the search tree and index
235.1661 + all existing members of the array */
235.1662 + if (array->size > 30 && array->tree == NULL)
235.1663 + { array->tree = avl_create_tree(compare_member_tuples, mpl);
235.1664 + for (memb = array->head; memb != NULL; memb = memb->next)
235.1665 +avl_set_node_link(avl_insert_node(array->tree, memb->tuple),
235.1666 + (void *)memb);
235.1667 + }
235.1668 + /* find a member, which has the given tuple */
235.1669 + if (array->tree == NULL)
235.1670 + { /* the search tree doesn't exist; use the linear search */
235.1671 + for (memb = array->head; memb != NULL; memb = memb->next)
235.1672 + if (compare_tuples(mpl, memb->tuple, tuple) == 0) break;
235.1673 + }
235.1674 + else
235.1675 + { /* the search tree exists; use the binary search */
235.1676 + AVLNODE *node;
235.1677 + node = avl_find_node(array->tree, tuple);
235.1678 +memb = (MEMBER *)(node == NULL ? NULL : avl_get_node_link(node));
235.1679 + }
235.1680 + return memb;
235.1681 +}
235.1682 +
235.1683 +/*----------------------------------------------------------------------
235.1684 +-- add_member - add new member to array.
235.1685 +--
235.1686 +-- This routine creates a new member with given n-tuple and adds it to
235.1687 +-- specified array.
235.1688 +--
235.1689 +-- For the sake of efficiency this routine doesn't check whether the
235.1690 +-- array already contains a member with the given n-tuple or not. Thus,
235.1691 +-- if necessary, the calling program should use the routine find_member
235.1692 +-- in order to be sure that the array contains no member with the same
235.1693 +-- n-tuple, because members with duplicate n-tuples are not allowed.
235.1694 +--
235.1695 +-- This routine assigns no generic value to the new member, because the
235.1696 +-- calling program must do that. */
235.1697 +
235.1698 +MEMBER *add_member
235.1699 +( MPL *mpl,
235.1700 + ARRAY *array, /* modified */
235.1701 + TUPLE *tuple /* destroyed */
235.1702 +)
235.1703 +{ MEMBER *memb;
235.1704 + xassert(array != NULL);
235.1705 + /* the n-tuple must have the same dimension as the array */
235.1706 + xassert(tuple_dimen(mpl, tuple) == array->dim);
235.1707 + /* create new member */
235.1708 + memb = dmp_get_atom(mpl->members, sizeof(MEMBER));
235.1709 + memb->tuple = tuple;
235.1710 + memb->next = NULL;
235.1711 + memset(&memb->value, '?', sizeof(VALUE));
235.1712 + /* and append it to the member list */
235.1713 + array->size++;
235.1714 + if (array->head == NULL)
235.1715 + array->head = memb;
235.1716 + else
235.1717 + array->tail->next = memb;
235.1718 + array->tail = memb;
235.1719 + /* if the search tree exists, index the new member */
235.1720 + if (array->tree != NULL)
235.1721 +avl_set_node_link(avl_insert_node(array->tree, memb->tuple),
235.1722 + (void *)memb);
235.1723 + return memb;
235.1724 +}
235.1725 +
235.1726 +/*----------------------------------------------------------------------
235.1727 +-- delete_array - delete array.
235.1728 +--
235.1729 +-- This routine deletes specified array.
235.1730 +--
235.1731 +-- Generic values assigned to the array members are not deleted by this
235.1732 +-- routine. The calling program itself must delete all assigned generic
235.1733 +-- values before deleting the array. */
235.1734 +
235.1735 +void delete_array
235.1736 +( MPL *mpl,
235.1737 + ARRAY *array /* destroyed */
235.1738 +)
235.1739 +{ MEMBER *memb;
235.1740 + xassert(array != NULL);
235.1741 + /* delete all existing array members */
235.1742 + while (array->head != NULL)
235.1743 + { memb = array->head;
235.1744 + array->head = memb->next;
235.1745 + delete_tuple(mpl, memb->tuple);
235.1746 + dmp_free_atom(mpl->members, memb, sizeof(MEMBER));
235.1747 + }
235.1748 + /* if the search tree exists, also delete it */
235.1749 + if (array->tree != NULL) avl_delete_tree(array->tree);
235.1750 + /* remove the array from the global array list */
235.1751 + if (array->prev == NULL)
235.1752 + mpl->a_list = array->next;
235.1753 + else
235.1754 + array->prev->next = array->next;
235.1755 + if (array->next == NULL)
235.1756 + ;
235.1757 + else
235.1758 + array->next->prev = array->prev;
235.1759 + /* delete the array descriptor */
235.1760 + dmp_free_atom(mpl->arrays, array, sizeof(ARRAY));
235.1761 + return;
235.1762 +}
235.1763 +
235.1764 +/**********************************************************************/
235.1765 +/* * * DOMAINS AND DUMMY INDICES * * */
235.1766 +/**********************************************************************/
235.1767 +
235.1768 +/*----------------------------------------------------------------------
235.1769 +-- assign_dummy_index - assign new value to dummy index.
235.1770 +--
235.1771 +-- This routine assigns new value to specified dummy index and, that is
235.1772 +-- important, invalidates all temporary resultant values, which depends
235.1773 +-- on that dummy index. */
235.1774 +
235.1775 +void assign_dummy_index
235.1776 +( MPL *mpl,
235.1777 + DOMAIN_SLOT *slot, /* modified */
235.1778 + SYMBOL *value /* not changed */
235.1779 +)
235.1780 +{ CODE *leaf, *code;
235.1781 + xassert(slot != NULL);
235.1782 + xassert(value != NULL);
235.1783 + /* delete the current value assigned to the dummy index */
235.1784 + if (slot->value != NULL)
235.1785 + { /* if the current value and the new one are identical, actual
235.1786 + assignment is not needed */
235.1787 + if (compare_symbols(mpl, slot->value, value) == 0) goto done;
235.1788 + /* delete a symbol, which is the current value */
235.1789 + delete_symbol(mpl, slot->value), slot->value = NULL;
235.1790 + }
235.1791 + /* now walk through all the pseudo-codes with op = O_INDEX, which
235.1792 + refer to the dummy index to be changed (these pseudo-codes are
235.1793 + leaves in the forest of *all* expressions in the database) */
235.1794 + for (leaf = slot->list; leaf != NULL; leaf = leaf->arg.index.
235.1795 + next)
235.1796 + { xassert(leaf->op == O_INDEX);
235.1797 + /* invalidate all resultant values, which depend on the dummy
235.1798 + index, walking from the current leaf toward the root of the
235.1799 + corresponding expression tree */
235.1800 + for (code = leaf; code != NULL; code = code->up)
235.1801 + { if (code->valid)
235.1802 + { /* invalidate and delete resultant value */
235.1803 + code->valid = 0;
235.1804 + delete_value(mpl, code->type, &code->value);
235.1805 + }
235.1806 + }
235.1807 + }
235.1808 + /* assign new value to the dummy index */
235.1809 + slot->value = copy_symbol(mpl, value);
235.1810 +done: return;
235.1811 +}
235.1812 +
235.1813 +/*----------------------------------------------------------------------
235.1814 +-- update_dummy_indices - update current values of dummy indices.
235.1815 +--
235.1816 +-- This routine assigns components of "backup" n-tuple to dummy indices
235.1817 +-- of specified domain block. If no "backup" n-tuple is defined for the
235.1818 +-- domain block, values of the dummy indices remain untouched. */
235.1819 +
235.1820 +void update_dummy_indices
235.1821 +( MPL *mpl,
235.1822 + DOMAIN_BLOCK *block /* not changed */
235.1823 +)
235.1824 +{ DOMAIN_SLOT *slot;
235.1825 + TUPLE *temp;
235.1826 + if (block->backup != NULL)
235.1827 + { for (slot = block->list, temp = block->backup; slot != NULL;
235.1828 + slot = slot->next, temp = temp->next)
235.1829 + { xassert(temp != NULL);
235.1830 + xassert(temp->sym != NULL);
235.1831 + assign_dummy_index(mpl, slot, temp->sym);
235.1832 + }
235.1833 + }
235.1834 + return;
235.1835 +}
235.1836 +
235.1837 +/*----------------------------------------------------------------------
235.1838 +-- enter_domain_block - enter domain block.
235.1839 +--
235.1840 +-- Let specified domain block have the form:
235.1841 +--
235.1842 +-- { ..., (j1, j2, ..., jn) in J, ... }
235.1843 +--
235.1844 +-- where j1, j2, ..., jn are dummy indices, J is a basic set.
235.1845 +--
235.1846 +-- This routine does the following:
235.1847 +--
235.1848 +-- 1. Checks if the given n-tuple is a member of the basic set J. Note
235.1849 +-- that J being *out of the scope* of the domain block cannot depend
235.1850 +-- on the dummy indices in the same and inner domain blocks, so it
235.1851 +-- can be computed before the dummy indices are assigned new values.
235.1852 +-- If this check fails, the routine returns with non-zero code.
235.1853 +--
235.1854 +-- 2. Saves current values of the dummy indices j1, j2, ..., jn.
235.1855 +--
235.1856 +-- 3. Assigns new values, which are components of the given n-tuple, to
235.1857 +-- the dummy indices j1, j2, ..., jn. If dimension of the n-tuple is
235.1858 +-- larger than n, its extra components n+1, n+2, ... are not used.
235.1859 +--
235.1860 +-- 4. Calls the formal routine func which either enters the next domain
235.1861 +-- block or evaluates some code within the domain scope.
235.1862 +--
235.1863 +-- 5. Restores former values of the dummy indices j1, j2, ..., jn.
235.1864 +--
235.1865 +-- Since current values assigned to the dummy indices on entry to this
235.1866 +-- routine are restored on exit, the formal routine func is allowed to
235.1867 +-- call this routine recursively. */
235.1868 +
235.1869 +int enter_domain_block
235.1870 +( MPL *mpl,
235.1871 + DOMAIN_BLOCK *block, /* not changed */
235.1872 + TUPLE *tuple, /* not changed */
235.1873 + void *info, void (*func)(MPL *mpl, void *info)
235.1874 +)
235.1875 +{ TUPLE *backup;
235.1876 + int ret = 0;
235.1877 + /* check if the given n-tuple is a member of the basic set */
235.1878 + xassert(block->code != NULL);
235.1879 + if (!is_member(mpl, block->code, tuple))
235.1880 + { ret = 1;
235.1881 + goto done;
235.1882 + }
235.1883 + /* save reference to "backup" n-tuple, which was used to assign
235.1884 + current values of the dummy indices (it is sufficient to save
235.1885 + reference, not value, because that n-tuple is defined in some
235.1886 + outer level of recursion and therefore cannot be changed on
235.1887 + this and deeper recursive calls) */
235.1888 + backup = block->backup;
235.1889 + /* set up new "backup" n-tuple, which defines new values of the
235.1890 + dummy indices */
235.1891 + block->backup = tuple;
235.1892 + /* assign new values to the dummy indices */
235.1893 + update_dummy_indices(mpl, block);
235.1894 + /* call the formal routine that does the rest part of the job */
235.1895 + func(mpl, info);
235.1896 + /* restore reference to the former "backup" n-tuple */
235.1897 + block->backup = backup;
235.1898 + /* restore former values of the dummy indices; note that if the
235.1899 + domain block just escaped has no other active instances which
235.1900 + may exist due to recursion (it is indicated by a null pointer
235.1901 + to the former n-tuple), former values of the dummy indices are
235.1902 + undefined; therefore in this case the routine keeps currently
235.1903 + assigned values of the dummy indices that involves keeping all
235.1904 + dependent temporary results and thereby, if this domain block
235.1905 + is not used recursively, allows improving efficiency */
235.1906 + update_dummy_indices(mpl, block);
235.1907 +done: return ret;
235.1908 +}
235.1909 +
235.1910 +/*----------------------------------------------------------------------
235.1911 +-- eval_within_domain - perform evaluation within domain scope.
235.1912 +--
235.1913 +-- This routine assigns new values (symbols) to all dummy indices of
235.1914 +-- specified domain and calls the formal routine func, which is used to
235.1915 +-- evaluate some code in the domain scope. Each free dummy index in the
235.1916 +-- domain is assigned a value specified in the corresponding component
235.1917 +-- of given n-tuple. Non-free dummy indices are assigned values, which
235.1918 +-- are computed by this routine.
235.1919 +--
235.1920 +-- Number of components in the given n-tuple must be the same as number
235.1921 +-- of free indices in the domain.
235.1922 +--
235.1923 +-- If the given n-tuple is not a member of the domain set, the routine
235.1924 +-- func is not called, and non-zero code is returned.
235.1925 +--
235.1926 +-- For the sake of convenience it is allowed to specify domain as NULL
235.1927 +-- (then n-tuple also must be 0-tuple, i.e. empty), in which case this
235.1928 +-- routine just calls the routine func and returns zero.
235.1929 +--
235.1930 +-- This routine allows recursive calls from the routine func providing
235.1931 +-- correct values of dummy indices for each instance.
235.1932 +--
235.1933 +-- NOTE: The n-tuple passed to this routine must not be changed by any
235.1934 +-- other routines called from the formal routine func until this
235.1935 +-- routine has returned. */
235.1936 +
235.1937 +struct eval_domain_info
235.1938 +{ /* working info used by the routine eval_within_domain */
235.1939 + DOMAIN *domain;
235.1940 + /* domain, which has to be entered */
235.1941 + DOMAIN_BLOCK *block;
235.1942 + /* domain block, which is currently processed */
235.1943 + TUPLE *tuple;
235.1944 + /* tail of original n-tuple, whose components have to be assigned
235.1945 + to free dummy indices in the current domain block */
235.1946 + void *info;
235.1947 + /* transit pointer passed to the formal routine func */
235.1948 + void (*func)(MPL *mpl, void *info);
235.1949 + /* routine, which has to be executed in the domain scope */
235.1950 + int failure;
235.1951 + /* this flag indicates that given n-tuple is not a member of the
235.1952 + domain set */
235.1953 +};
235.1954 +
235.1955 +static void eval_domain_func(MPL *mpl, void *_my_info)
235.1956 +{ /* this routine recursively enters into the domain scope and then
235.1957 + calls the routine func */
235.1958 + struct eval_domain_info *my_info = _my_info;
235.1959 + if (my_info->block != NULL)
235.1960 + { /* the current domain block to be entered exists */
235.1961 + DOMAIN_BLOCK *block;
235.1962 + DOMAIN_SLOT *slot;
235.1963 + TUPLE *tuple = NULL, *temp = NULL;
235.1964 + /* save pointer to the current domain block */
235.1965 + block = my_info->block;
235.1966 + /* and get ready to enter the next block (if it exists) */
235.1967 + my_info->block = block->next;
235.1968 + /* construct temporary n-tuple, whose components correspond to
235.1969 + dummy indices (slots) of the current domain; components of
235.1970 + the temporary n-tuple that correspond to free dummy indices
235.1971 + are assigned references (not values!) to symbols specified
235.1972 + in the corresponding components of the given n-tuple, while
235.1973 + other components that correspond to non-free dummy indices
235.1974 + are assigned symbolic values computed here */
235.1975 + for (slot = block->list; slot != NULL; slot = slot->next)
235.1976 + { /* create component that corresponds to the current slot */
235.1977 + if (tuple == NULL)
235.1978 + tuple = temp = dmp_get_atom(mpl->tuples, sizeof(TUPLE));
235.1979 + else
235.1980 +temp = (temp->next = dmp_get_atom(mpl->tuples, sizeof(TUPLE)));
235.1981 + if (slot->code == NULL)
235.1982 + { /* dummy index is free; take reference to symbol, which
235.1983 + is specified in the corresponding component of given
235.1984 + n-tuple */
235.1985 + xassert(my_info->tuple != NULL);
235.1986 + temp->sym = my_info->tuple->sym;
235.1987 + xassert(temp->sym != NULL);
235.1988 + my_info->tuple = my_info->tuple->next;
235.1989 + }
235.1990 + else
235.1991 + { /* dummy index is non-free; compute symbolic value to be
235.1992 + temporarily assigned to the dummy index */
235.1993 + temp->sym = eval_symbolic(mpl, slot->code);
235.1994 + }
235.1995 + }
235.1996 + temp->next = NULL;
235.1997 + /* enter the current domain block */
235.1998 + if (enter_domain_block(mpl, block, tuple, my_info,
235.1999 + eval_domain_func)) my_info->failure = 1;
235.2000 + /* delete temporary n-tuple as well as symbols that correspond
235.2001 + to non-free dummy indices (they were computed here) */
235.2002 + for (slot = block->list; slot != NULL; slot = slot->next)
235.2003 + { xassert(tuple != NULL);
235.2004 + temp = tuple;
235.2005 + tuple = tuple->next;
235.2006 + if (slot->code != NULL)
235.2007 + { /* dummy index is non-free; delete symbolic value */
235.2008 + delete_symbol(mpl, temp->sym);
235.2009 + }
235.2010 + /* delete component that corresponds to the current slot */
235.2011 + dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE));
235.2012 + }
235.2013 + }
235.2014 + else
235.2015 + { /* there are no more domain blocks, i.e. we have reached the
235.2016 + domain scope */
235.2017 + xassert(my_info->tuple == NULL);
235.2018 + /* check optional predicate specified for the domain */
235.2019 + if (my_info->domain->code != NULL && !eval_logical(mpl,
235.2020 + my_info->domain->code))
235.2021 + { /* the predicate is false */
235.2022 + my_info->failure = 2;
235.2023 + }
235.2024 + else
235.2025 + { /* the predicate is true; do the job */
235.2026 + my_info->func(mpl, my_info->info);
235.2027 + }
235.2028 + }
235.2029 + return;
235.2030 +}
235.2031 +
235.2032 +int eval_within_domain
235.2033 +( MPL *mpl,
235.2034 + DOMAIN *domain, /* not changed */
235.2035 + TUPLE *tuple, /* not changed */
235.2036 + void *info, void (*func)(MPL *mpl, void *info)
235.2037 +)
235.2038 +{ /* this routine performs evaluation within domain scope */
235.2039 + struct eval_domain_info _my_info, *my_info = &_my_info;
235.2040 + if (domain == NULL)
235.2041 + { xassert(tuple == NULL);
235.2042 + func(mpl, info);
235.2043 + my_info->failure = 0;
235.2044 + }
235.2045 + else
235.2046 + { xassert(tuple != NULL);
235.2047 + my_info->domain = domain;
235.2048 + my_info->block = domain->list;
235.2049 + my_info->tuple = tuple;
235.2050 + my_info->info = info;
235.2051 + my_info->func = func;
235.2052 + my_info->failure = 0;
235.2053 + /* enter the very first domain block */
235.2054 + eval_domain_func(mpl, my_info);
235.2055 + }
235.2056 + return my_info->failure;
235.2057 +}
235.2058 +
235.2059 +/*----------------------------------------------------------------------
235.2060 +-- loop_within_domain - perform iterations within domain scope.
235.2061 +--
235.2062 +-- This routine iteratively assigns new values (symbols) to the dummy
235.2063 +-- indices of specified domain by enumerating all n-tuples, which are
235.2064 +-- members of the domain set, and for every n-tuple it calls the formal
235.2065 +-- routine func to evaluate some code within the domain scope.
235.2066 +--
235.2067 +-- If the routine func returns non-zero, enumeration within the domain
235.2068 +-- is prematurely terminated.
235.2069 +--
235.2070 +-- For the sake of convenience it is allowed to specify domain as NULL,
235.2071 +-- in which case this routine just calls the routine func only once and
235.2072 +-- returns zero.
235.2073 +--
235.2074 +-- This routine allows recursive calls from the routine func providing
235.2075 +-- correct values of dummy indices for each instance. */
235.2076 +
235.2077 +struct loop_domain_info
235.2078 +{ /* working info used by the routine loop_within_domain */
235.2079 + DOMAIN *domain;
235.2080 + /* domain, which has to be entered */
235.2081 + DOMAIN_BLOCK *block;
235.2082 + /* domain block, which is currently processed */
235.2083 + int looping;
235.2084 + /* clearing this flag leads to terminating enumeration */
235.2085 + void *info;
235.2086 + /* transit pointer passed to the formal routine func */
235.2087 + int (*func)(MPL *mpl, void *info);
235.2088 + /* routine, which needs to be executed in the domain scope */
235.2089 +};
235.2090 +
235.2091 +static void loop_domain_func(MPL *mpl, void *_my_info)
235.2092 +{ /* this routine enumerates all n-tuples in the basic set of the
235.2093 + current domain block, enters recursively into the domain scope
235.2094 + for every n-tuple, and then calls the routine func */
235.2095 + struct loop_domain_info *my_info = _my_info;
235.2096 + if (my_info->block != NULL)
235.2097 + { /* the current domain block to be entered exists */
235.2098 + DOMAIN_BLOCK *block;
235.2099 + DOMAIN_SLOT *slot;
235.2100 + TUPLE *bound;
235.2101 + /* save pointer to the current domain block */
235.2102 + block = my_info->block;
235.2103 + /* and get ready to enter the next block (if it exists) */
235.2104 + my_info->block = block->next;
235.2105 + /* compute symbolic values, at which non-free dummy indices of
235.2106 + the current domain block are bound; since that values don't
235.2107 + depend on free dummy indices of the current block, they can
235.2108 + be computed once out of the enumeration loop */
235.2109 + bound = create_tuple(mpl);
235.2110 + for (slot = block->list; slot != NULL; slot = slot->next)
235.2111 + { if (slot->code != NULL)
235.2112 + bound = expand_tuple(mpl, bound, eval_symbolic(mpl,
235.2113 + slot->code));
235.2114 + }
235.2115 + /* start enumeration */
235.2116 + xassert(block->code != NULL);
235.2117 + if (block->code->op == O_DOTS)
235.2118 + { /* the basic set is "arithmetic", in which case it doesn't
235.2119 + need to be computed explicitly */
235.2120 + TUPLE *tuple;
235.2121 + int n, j;
235.2122 + double t0, tf, dt;
235.2123 + /* compute "parameters" of the basic set */
235.2124 + t0 = eval_numeric(mpl, block->code->arg.arg.x);
235.2125 + tf = eval_numeric(mpl, block->code->arg.arg.y);
235.2126 + if (block->code->arg.arg.z == NULL)
235.2127 + dt = 1.0;
235.2128 + else
235.2129 + dt = eval_numeric(mpl, block->code->arg.arg.z);
235.2130 + /* determine cardinality of the basic set */
235.2131 + n = arelset_size(mpl, t0, tf, dt);
235.2132 + /* create dummy 1-tuple for members of the basic set */
235.2133 + tuple = expand_tuple(mpl, create_tuple(mpl),
235.2134 + create_symbol_num(mpl, 0.0));
235.2135 + /* in case of "arithmetic" set there is exactly one dummy
235.2136 + index, which cannot be non-free */
235.2137 + xassert(bound == NULL);
235.2138 + /* walk through 1-tuples of the basic set */
235.2139 + for (j = 1; j <= n && my_info->looping; j++)
235.2140 + { /* construct dummy 1-tuple for the current member */
235.2141 + tuple->sym->num = arelset_member(mpl, t0, tf, dt, j);
235.2142 + /* enter the current domain block */
235.2143 + enter_domain_block(mpl, block, tuple, my_info,
235.2144 + loop_domain_func);
235.2145 + }
235.2146 + /* delete dummy 1-tuple */
235.2147 + delete_tuple(mpl, tuple);
235.2148 + }
235.2149 + else
235.2150 + { /* the basic set is of general kind, in which case it needs
235.2151 + to be explicitly computed */
235.2152 + ELEMSET *set;
235.2153 + MEMBER *memb;
235.2154 + TUPLE *temp1, *temp2;
235.2155 + /* compute the basic set */
235.2156 + set = eval_elemset(mpl, block->code);
235.2157 + /* walk through all n-tuples of the basic set */
235.2158 + for (memb = set->head; memb != NULL && my_info->looping;
235.2159 + memb = memb->next)
235.2160 + { /* all components of the current n-tuple that correspond
235.2161 + to non-free dummy indices must be feasible; otherwise
235.2162 + the n-tuple is not in the basic set */
235.2163 + temp1 = memb->tuple;
235.2164 + temp2 = bound;
235.2165 + for (slot = block->list; slot != NULL; slot = slot->next)
235.2166 + { xassert(temp1 != NULL);
235.2167 + if (slot->code != NULL)
235.2168 + { /* non-free dummy index */
235.2169 + xassert(temp2 != NULL);
235.2170 + if (compare_symbols(mpl, temp1->sym, temp2->sym)
235.2171 + != 0)
235.2172 + { /* the n-tuple is not in the basic set */
235.2173 + goto skip;
235.2174 + }
235.2175 + temp2 = temp2->next;
235.2176 + }
235.2177 + temp1 = temp1->next;
235.2178 + }
235.2179 + xassert(temp1 == NULL);
235.2180 + xassert(temp2 == NULL);
235.2181 + /* enter the current domain block */
235.2182 + enter_domain_block(mpl, block, memb->tuple, my_info,
235.2183 + loop_domain_func);
235.2184 +skip: ;
235.2185 + }
235.2186 + /* delete the basic set */
235.2187 + delete_elemset(mpl, set);
235.2188 + }
235.2189 + /* delete symbolic values binding non-free dummy indices */
235.2190 + delete_tuple(mpl, bound);
235.2191 + /* restore pointer to the current domain block */
235.2192 + my_info->block = block;
235.2193 + }
235.2194 + else
235.2195 + { /* there are no more domain blocks, i.e. we have reached the
235.2196 + domain scope */
235.2197 + /* check optional predicate specified for the domain */
235.2198 + if (my_info->domain->code != NULL && !eval_logical(mpl,
235.2199 + my_info->domain->code))
235.2200 + { /* the predicate is false */
235.2201 + /* nop */;
235.2202 + }
235.2203 + else
235.2204 + { /* the predicate is true; do the job */
235.2205 + my_info->looping = !my_info->func(mpl, my_info->info);
235.2206 + }
235.2207 + }
235.2208 + return;
235.2209 +}
235.2210 +
235.2211 +void loop_within_domain
235.2212 +( MPL *mpl,
235.2213 + DOMAIN *domain, /* not changed */
235.2214 + void *info, int (*func)(MPL *mpl, void *info)
235.2215 +)
235.2216 +{ /* this routine performs iterations within domain scope */
235.2217 + struct loop_domain_info _my_info, *my_info = &_my_info;
235.2218 + if (domain == NULL)
235.2219 + func(mpl, info);
235.2220 + else
235.2221 + { my_info->domain = domain;
235.2222 + my_info->block = domain->list;
235.2223 + my_info->looping = 1;
235.2224 + my_info->info = info;
235.2225 + my_info->func = func;
235.2226 + /* enter the very first domain block */
235.2227 + loop_domain_func(mpl, my_info);
235.2228 + }
235.2229 + return;
235.2230 +}
235.2231 +
235.2232 +/*----------------------------------------------------------------------
235.2233 +-- out_of_domain - raise domain exception.
235.2234 +--
235.2235 +-- This routine is called when a reference is made to a member of some
235.2236 +-- model object, but its n-tuple is out of the object domain. */
235.2237 +
235.2238 +void out_of_domain
235.2239 +( MPL *mpl,
235.2240 + char *name, /* not changed */
235.2241 + TUPLE *tuple /* not changed */
235.2242 +)
235.2243 +{ xassert(name != NULL);
235.2244 + xassert(tuple != NULL);
235.2245 + error(mpl, "%s%s out of domain", name, format_tuple(mpl, '[',
235.2246 + tuple));
235.2247 + /* no return */
235.2248 +}
235.2249 +
235.2250 +/*----------------------------------------------------------------------
235.2251 +-- get_domain_tuple - obtain current n-tuple from domain.
235.2252 +--
235.2253 +-- This routine constructs n-tuple, whose components are current values
235.2254 +-- assigned to *free* dummy indices of specified domain.
235.2255 +--
235.2256 +-- For the sake of convenience it is allowed to specify domain as NULL,
235.2257 +-- in which case this routine returns 0-tuple.
235.2258 +--
235.2259 +-- NOTE: This routine must not be called out of domain scope. */
235.2260 +
235.2261 +TUPLE *get_domain_tuple
235.2262 +( MPL *mpl,
235.2263 + DOMAIN *domain /* not changed */
235.2264 +)
235.2265 +{ DOMAIN_BLOCK *block;
235.2266 + DOMAIN_SLOT *slot;
235.2267 + TUPLE *tuple;
235.2268 + tuple = create_tuple(mpl);
235.2269 + if (domain != NULL)
235.2270 + { for (block = domain->list; block != NULL; block = block->next)
235.2271 + { for (slot = block->list; slot != NULL; slot = slot->next)
235.2272 + { if (slot->code == NULL)
235.2273 + { xassert(slot->value != NULL);
235.2274 + tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
235.2275 + slot->value));
235.2276 + }
235.2277 + }
235.2278 + }
235.2279 + }
235.2280 + return tuple;
235.2281 +}
235.2282 +
235.2283 +/*----------------------------------------------------------------------
235.2284 +-- clean_domain - clean domain.
235.2285 +--
235.2286 +-- This routine cleans specified domain that assumes deleting all stuff
235.2287 +-- dynamically allocated during the generation phase. */
235.2288 +
235.2289 +void clean_domain(MPL *mpl, DOMAIN *domain)
235.2290 +{ DOMAIN_BLOCK *block;
235.2291 + DOMAIN_SLOT *slot;
235.2292 + /* if no domain is specified, do nothing */
235.2293 + if (domain == NULL) goto done;
235.2294 + /* clean all domain blocks */
235.2295 + for (block = domain->list; block != NULL; block = block->next)
235.2296 + { /* clean all domain slots */
235.2297 + for (slot = block->list; slot != NULL; slot = slot->next)
235.2298 + { /* clean pseudo-code for computing bound value */
235.2299 + clean_code(mpl, slot->code);
235.2300 + /* delete symbolic value assigned to dummy index */
235.2301 + if (slot->value != NULL)
235.2302 + delete_symbol(mpl, slot->value), slot->value = NULL;
235.2303 + }
235.2304 + /* clean pseudo-code for computing basic set */
235.2305 + clean_code(mpl, block->code);
235.2306 + }
235.2307 + /* clean pseudo-code for computing domain predicate */
235.2308 + clean_code(mpl, domain->code);
235.2309 +done: return;
235.2310 +}
235.2311 +
235.2312 +/**********************************************************************/
235.2313 +/* * * MODEL SETS * * */
235.2314 +/**********************************************************************/
235.2315 +
235.2316 +/*----------------------------------------------------------------------
235.2317 +-- check_elem_set - check elemental set assigned to set member.
235.2318 +--
235.2319 +-- This routine checks if given elemental set being assigned to member
235.2320 +-- of specified model set satisfies to all restrictions.
235.2321 +--
235.2322 +-- NOTE: This routine must not be called out of domain scope. */
235.2323 +
235.2324 +void check_elem_set
235.2325 +( MPL *mpl,
235.2326 + SET *set, /* not changed */
235.2327 + TUPLE *tuple, /* not changed */
235.2328 + ELEMSET *refer /* not changed */
235.2329 +)
235.2330 +{ WITHIN *within;
235.2331 + MEMBER *memb;
235.2332 + int eqno;
235.2333 + /* elemental set must be within all specified supersets */
235.2334 + for (within = set->within, eqno = 1; within != NULL; within =
235.2335 + within->next, eqno++)
235.2336 + { xassert(within->code != NULL);
235.2337 + for (memb = refer->head; memb != NULL; memb = memb->next)
235.2338 + { if (!is_member(mpl, within->code, memb->tuple))
235.2339 + { char buf[255+1];
235.2340 + strcpy(buf, format_tuple(mpl, '(', memb->tuple));
235.2341 + xassert(strlen(buf) < sizeof(buf));
235.2342 + error(mpl, "%s%s contains %s which not within specified "
235.2343 + "set; see (%d)", set->name, format_tuple(mpl, '[',
235.2344 + tuple), buf, eqno);
235.2345 + }
235.2346 + }
235.2347 + }
235.2348 + return;
235.2349 +}
235.2350 +
235.2351 +/*----------------------------------------------------------------------
235.2352 +-- take_member_set - obtain elemental set assigned to set member.
235.2353 +--
235.2354 +-- This routine obtains a reference to elemental set assigned to given
235.2355 +-- member of specified model set and returns it on exit.
235.2356 +--
235.2357 +-- NOTE: This routine must not be called out of domain scope. */
235.2358 +
235.2359 +ELEMSET *take_member_set /* returns reference, not value */
235.2360 +( MPL *mpl,
235.2361 + SET *set, /* not changed */
235.2362 + TUPLE *tuple /* not changed */
235.2363 +)
235.2364 +{ MEMBER *memb;
235.2365 + ELEMSET *refer;
235.2366 + /* find member in the set array */
235.2367 + memb = find_member(mpl, set->array, tuple);
235.2368 + if (memb != NULL)
235.2369 + { /* member exists, so just take the reference */
235.2370 + refer = memb->value.set;
235.2371 + }
235.2372 + else if (set->assign != NULL)
235.2373 + { /* compute value using assignment expression */
235.2374 + refer = eval_elemset(mpl, set->assign);
235.2375 +add: /* check that the elemental set satisfies to all restrictions,
235.2376 + assign it to new member, and add the member to the array */
235.2377 + check_elem_set(mpl, set, tuple, refer);
235.2378 + memb = add_member(mpl, set->array, copy_tuple(mpl, tuple));
235.2379 + memb->value.set = refer;
235.2380 + }
235.2381 + else if (set->option != NULL)
235.2382 + { /* compute default elemental set */
235.2383 + refer = eval_elemset(mpl, set->option);
235.2384 + goto add;
235.2385 + }
235.2386 + else
235.2387 + { /* no value (elemental set) is provided */
235.2388 + error(mpl, "no value for %s%s", set->name, format_tuple(mpl,
235.2389 + '[', tuple));
235.2390 + }
235.2391 + return refer;
235.2392 +}
235.2393 +
235.2394 +/*----------------------------------------------------------------------
235.2395 +-- eval_member_set - evaluate elemental set assigned to set member.
235.2396 +--
235.2397 +-- This routine evaluates a reference to elemental set assigned to given
235.2398 +-- member of specified model set and returns it on exit. */
235.2399 +
235.2400 +struct eval_set_info
235.2401 +{ /* working info used by the routine eval_member_set */
235.2402 + SET *set;
235.2403 + /* model set */
235.2404 + TUPLE *tuple;
235.2405 + /* n-tuple, which defines set member */
235.2406 + MEMBER *memb;
235.2407 + /* normally this pointer is NULL; the routine uses this pointer
235.2408 + to check data provided in the data section, in which case it
235.2409 + points to a member currently checked; this check is performed
235.2410 + automatically only once when a reference to any member occurs
235.2411 + for the first time */
235.2412 + ELEMSET *refer;
235.2413 + /* evaluated reference to elemental set */
235.2414 +};
235.2415 +
235.2416 +static void eval_set_func(MPL *mpl, void *_info)
235.2417 +{ /* this is auxiliary routine to work within domain scope */
235.2418 + struct eval_set_info *info = _info;
235.2419 + if (info->memb != NULL)
235.2420 + { /* checking call; check elemental set being assigned */
235.2421 + check_elem_set(mpl, info->set, info->memb->tuple,
235.2422 + info->memb->value.set);
235.2423 + }
235.2424 + else
235.2425 + { /* normal call; evaluate member, which has given n-tuple */
235.2426 + info->refer = take_member_set(mpl, info->set, info->tuple);
235.2427 + }
235.2428 + return;
235.2429 +}
235.2430 +
235.2431 +#if 1 /* 12/XII-2008 */
235.2432 +static void saturate_set(MPL *mpl, SET *set)
235.2433 +{ GADGET *gadget = set->gadget;
235.2434 + ELEMSET *data;
235.2435 + MEMBER *elem, *memb;
235.2436 + TUPLE *tuple, *work[20];
235.2437 + int i;
235.2438 + xprintf("Generating %s...\n", set->name);
235.2439 + eval_whole_set(mpl, gadget->set);
235.2440 + /* gadget set must have exactly one member */
235.2441 + xassert(gadget->set->array != NULL);
235.2442 + xassert(gadget->set->array->head != NULL);
235.2443 + xassert(gadget->set->array->head == gadget->set->array->tail);
235.2444 + data = gadget->set->array->head->value.set;
235.2445 + xassert(data->type == A_NONE);
235.2446 + xassert(data->dim == gadget->set->dimen);
235.2447 + /* walk thru all elements of the plain set */
235.2448 + for (elem = data->head; elem != NULL; elem = elem->next)
235.2449 + { /* create a copy of n-tuple */
235.2450 + tuple = copy_tuple(mpl, elem->tuple);
235.2451 + /* rearrange component of the n-tuple */
235.2452 + for (i = 0; i < gadget->set->dimen; i++)
235.2453 + work[i] = NULL;
235.2454 + for (i = 0; tuple != NULL; tuple = tuple->next)
235.2455 + work[gadget->ind[i++]-1] = tuple;
235.2456 + xassert(i == gadget->set->dimen);
235.2457 + for (i = 0; i < gadget->set->dimen; i++)
235.2458 + { xassert(work[i] != NULL);
235.2459 + work[i]->next = work[i+1];
235.2460 + }
235.2461 + /* construct subscript list from first set->dim components */
235.2462 + if (set->dim == 0)
235.2463 + tuple = NULL;
235.2464 + else
235.2465 + tuple = work[0], work[set->dim-1]->next = NULL;
235.2466 + /* find corresponding member of the set to be initialized */
235.2467 + memb = find_member(mpl, set->array, tuple);
235.2468 + if (memb == NULL)
235.2469 + { /* not found; add new member to the set and assign it empty
235.2470 + elemental set */
235.2471 + memb = add_member(mpl, set->array, tuple);
235.2472 + memb->value.set = create_elemset(mpl, set->dimen);
235.2473 + }
235.2474 + else
235.2475 + { /* found; free subscript list */
235.2476 + delete_tuple(mpl, tuple);
235.2477 + }
235.2478 + /* construct new n-tuple from rest set->dimen components */
235.2479 + tuple = work[set->dim];
235.2480 + xassert(set->dim + set->dimen == gadget->set->dimen);
235.2481 + work[gadget->set->dimen-1]->next = NULL;
235.2482 + /* and add it to the elemental set assigned to the member
235.2483 + (no check for duplicates is needed) */
235.2484 + add_tuple(mpl, memb->value.set, tuple);
235.2485 + }
235.2486 + /* the set has been saturated with data */
235.2487 + set->data = 1;
235.2488 + return;
235.2489 +}
235.2490 +#endif
235.2491 +
235.2492 +ELEMSET *eval_member_set /* returns reference, not value */
235.2493 +( MPL *mpl,
235.2494 + SET *set, /* not changed */
235.2495 + TUPLE *tuple /* not changed */
235.2496 +)
235.2497 +{ /* this routine evaluates set member */
235.2498 + struct eval_set_info _info, *info = &_info;
235.2499 + xassert(set->dim == tuple_dimen(mpl, tuple));
235.2500 + info->set = set;
235.2501 + info->tuple = tuple;
235.2502 +#if 1 /* 12/XII-2008 */
235.2503 + if (set->gadget != NULL && set->data == 0)
235.2504 + { /* initialize the set with data from a plain set */
235.2505 + saturate_set(mpl, set);
235.2506 + }
235.2507 +#endif
235.2508 + if (set->data == 1)
235.2509 + { /* check data, which are provided in the data section, but not
235.2510 + checked yet */
235.2511 + /* save pointer to the last array member; note that during the
235.2512 + check new members may be added beyond the last member due to
235.2513 + references to the same parameter from default expression as
235.2514 + well as from expressions that define restricting supersets;
235.2515 + however, values assigned to the new members will be checked
235.2516 + by other routine, so we don't need to check them here */
235.2517 + MEMBER *tail = set->array->tail;
235.2518 + /* change the data status to prevent infinite recursive loop
235.2519 + due to references to the same set during the check */
235.2520 + set->data = 2;
235.2521 + /* check elemental sets assigned to array members in the data
235.2522 + section until the marked member has been reached */
235.2523 + for (info->memb = set->array->head; info->memb != NULL;
235.2524 + info->memb = info->memb->next)
235.2525 + { if (eval_within_domain(mpl, set->domain, info->memb->tuple,
235.2526 + info, eval_set_func))
235.2527 + out_of_domain(mpl, set->name, info->memb->tuple);
235.2528 + if (info->memb == tail) break;
235.2529 + }
235.2530 + /* the check has been finished */
235.2531 + }
235.2532 + /* evaluate member, which has given n-tuple */
235.2533 + info->memb = NULL;
235.2534 + if (eval_within_domain(mpl, info->set->domain, info->tuple, info,
235.2535 + eval_set_func))
235.2536 + out_of_domain(mpl, set->name, info->tuple);
235.2537 + /* bring evaluated reference to the calling program */
235.2538 + return info->refer;
235.2539 +}
235.2540 +
235.2541 +/*----------------------------------------------------------------------
235.2542 +-- eval_whole_set - evaluate model set over entire domain.
235.2543 +--
235.2544 +-- This routine evaluates all members of specified model set over entire
235.2545 +-- domain. */
235.2546 +
235.2547 +static int whole_set_func(MPL *mpl, void *info)
235.2548 +{ /* this is auxiliary routine to work within domain scope */
235.2549 + SET *set = (SET *)info;
235.2550 + TUPLE *tuple = get_domain_tuple(mpl, set->domain);
235.2551 + eval_member_set(mpl, set, tuple);
235.2552 + delete_tuple(mpl, tuple);
235.2553 + return 0;
235.2554 +}
235.2555 +
235.2556 +void eval_whole_set(MPL *mpl, SET *set)
235.2557 +{ loop_within_domain(mpl, set->domain, set, whole_set_func);
235.2558 + return;
235.2559 +}
235.2560 +
235.2561 +/*----------------------------------------------------------------------
235.2562 +-- clean set - clean model set.
235.2563 +--
235.2564 +-- This routine cleans specified model set that assumes deleting all
235.2565 +-- stuff dynamically allocated during the generation phase. */
235.2566 +
235.2567 +void clean_set(MPL *mpl, SET *set)
235.2568 +{ WITHIN *within;
235.2569 + MEMBER *memb;
235.2570 + /* clean subscript domain */
235.2571 + clean_domain(mpl, set->domain);
235.2572 + /* clean pseudo-code for computing supersets */
235.2573 + for (within = set->within; within != NULL; within = within->next)
235.2574 + clean_code(mpl, within->code);
235.2575 + /* clean pseudo-code for computing assigned value */
235.2576 + clean_code(mpl, set->assign);
235.2577 + /* clean pseudo-code for computing default value */
235.2578 + clean_code(mpl, set->option);
235.2579 + /* reset data status flag */
235.2580 + set->data = 0;
235.2581 + /* delete content array */
235.2582 + for (memb = set->array->head; memb != NULL; memb = memb->next)
235.2583 + delete_value(mpl, set->array->type, &memb->value);
235.2584 + delete_array(mpl, set->array), set->array = NULL;
235.2585 + return;
235.2586 +}
235.2587 +
235.2588 +/**********************************************************************/
235.2589 +/* * * MODEL PARAMETERS * * */
235.2590 +/**********************************************************************/
235.2591 +
235.2592 +/*----------------------------------------------------------------------
235.2593 +-- check_value_num - check numeric value assigned to parameter member.
235.2594 +--
235.2595 +-- This routine checks if numeric value being assigned to some member
235.2596 +-- of specified numeric model parameter satisfies to all restrictions.
235.2597 +--
235.2598 +-- NOTE: This routine must not be called out of domain scope. */
235.2599 +
235.2600 +void check_value_num
235.2601 +( MPL *mpl,
235.2602 + PARAMETER *par, /* not changed */
235.2603 + TUPLE *tuple, /* not changed */
235.2604 + double value
235.2605 +)
235.2606 +{ CONDITION *cond;
235.2607 + WITHIN *in;
235.2608 + int eqno;
235.2609 + /* the value must satisfy to the parameter type */
235.2610 + switch (par->type)
235.2611 + { case A_NUMERIC:
235.2612 + break;
235.2613 + case A_INTEGER:
235.2614 + if (value != floor(value))
235.2615 + error(mpl, "%s%s = %.*g not integer", par->name,
235.2616 + format_tuple(mpl, '[', tuple), DBL_DIG, value);
235.2617 + break;
235.2618 + case A_BINARY:
235.2619 + if (!(value == 0.0 || value == 1.0))
235.2620 + error(mpl, "%s%s = %.*g not binary", par->name,
235.2621 + format_tuple(mpl, '[', tuple), DBL_DIG, value);
235.2622 + break;
235.2623 + default:
235.2624 + xassert(par != par);
235.2625 + }
235.2626 + /* the value must satisfy to all specified conditions */
235.2627 + for (cond = par->cond, eqno = 1; cond != NULL; cond = cond->next,
235.2628 + eqno++)
235.2629 + { double bound;
235.2630 + char *rho;
235.2631 + xassert(cond->code != NULL);
235.2632 + bound = eval_numeric(mpl, cond->code);
235.2633 + switch (cond->rho)
235.2634 + { case O_LT:
235.2635 + if (!(value < bound))
235.2636 + { rho = "<";
235.2637 +err: error(mpl, "%s%s = %.*g not %s %.*g; see (%d)",
235.2638 + par->name, format_tuple(mpl, '[', tuple), DBL_DIG,
235.2639 + value, rho, DBL_DIG, bound, eqno);
235.2640 + }
235.2641 + break;
235.2642 + case O_LE:
235.2643 + if (!(value <= bound)) { rho = "<="; goto err; }
235.2644 + break;
235.2645 + case O_EQ:
235.2646 + if (!(value == bound)) { rho = "="; goto err; }
235.2647 + break;
235.2648 + case O_GE:
235.2649 + if (!(value >= bound)) { rho = ">="; goto err; }
235.2650 + break;
235.2651 + case O_GT:
235.2652 + if (!(value > bound)) { rho = ">"; goto err; }
235.2653 + break;
235.2654 + case O_NE:
235.2655 + if (!(value != bound)) { rho = "<>"; goto err; }
235.2656 + break;
235.2657 + default:
235.2658 + xassert(cond != cond);
235.2659 + }
235.2660 + }
235.2661 + /* the value must be in all specified supersets */
235.2662 + for (in = par->in, eqno = 1; in != NULL; in = in->next, eqno++)
235.2663 + { TUPLE *dummy;
235.2664 + xassert(in->code != NULL);
235.2665 + xassert(in->code->dim == 1);
235.2666 + dummy = expand_tuple(mpl, create_tuple(mpl),
235.2667 + create_symbol_num(mpl, value));
235.2668 + if (!is_member(mpl, in->code, dummy))
235.2669 + error(mpl, "%s%s = %.*g not in specified set; see (%d)",
235.2670 + par->name, format_tuple(mpl, '[', tuple), DBL_DIG,
235.2671 + value, eqno);
235.2672 + delete_tuple(mpl, dummy);
235.2673 + }
235.2674 + return;
235.2675 +}
235.2676 +
235.2677 +/*----------------------------------------------------------------------
235.2678 +-- take_member_num - obtain num. value assigned to parameter member.
235.2679 +--
235.2680 +-- This routine obtains a numeric value assigned to member of specified
235.2681 +-- numeric model parameter and returns it on exit.
235.2682 +--
235.2683 +-- NOTE: This routine must not be called out of domain scope. */
235.2684 +
235.2685 +double take_member_num
235.2686 +( MPL *mpl,
235.2687 + PARAMETER *par, /* not changed */
235.2688 + TUPLE *tuple /* not changed */
235.2689 +)
235.2690 +{ MEMBER *memb;
235.2691 + double value;
235.2692 + /* find member in the parameter array */
235.2693 + memb = find_member(mpl, par->array, tuple);
235.2694 + if (memb != NULL)
235.2695 + { /* member exists, so just take its value */
235.2696 + value = memb->value.num;
235.2697 + }
235.2698 + else if (par->assign != NULL)
235.2699 + { /* compute value using assignment expression */
235.2700 + value = eval_numeric(mpl, par->assign);
235.2701 +add: /* check that the value satisfies to all restrictions, assign
235.2702 + it to new member, and add the member to the array */
235.2703 + check_value_num(mpl, par, tuple, value);
235.2704 + memb = add_member(mpl, par->array, copy_tuple(mpl, tuple));
235.2705 + memb->value.num = value;
235.2706 + }
235.2707 + else if (par->option != NULL)
235.2708 + { /* compute default value */
235.2709 + value = eval_numeric(mpl, par->option);
235.2710 + goto add;
235.2711 + }
235.2712 + else if (par->defval != NULL)
235.2713 + { /* take default value provided in the data section */
235.2714 + if (par->defval->str != NULL)
235.2715 + error(mpl, "cannot convert %s to floating-point number",
235.2716 + format_symbol(mpl, par->defval));
235.2717 + value = par->defval->num;
235.2718 + goto add;
235.2719 + }
235.2720 + else
235.2721 + { /* no value is provided */
235.2722 + error(mpl, "no value for %s%s", par->name, format_tuple(mpl,
235.2723 + '[', tuple));
235.2724 + }
235.2725 + return value;
235.2726 +}
235.2727 +
235.2728 +/*----------------------------------------------------------------------
235.2729 +-- eval_member_num - evaluate num. value assigned to parameter member.
235.2730 +--
235.2731 +-- This routine evaluates a numeric value assigned to given member of
235.2732 +-- specified numeric model parameter and returns it on exit. */
235.2733 +
235.2734 +struct eval_num_info
235.2735 +{ /* working info used by the routine eval_member_num */
235.2736 + PARAMETER *par;
235.2737 + /* model parameter */
235.2738 + TUPLE *tuple;
235.2739 + /* n-tuple, which defines parameter member */
235.2740 + MEMBER *memb;
235.2741 + /* normally this pointer is NULL; the routine uses this pointer
235.2742 + to check data provided in the data section, in which case it
235.2743 + points to a member currently checked; this check is performed
235.2744 + automatically only once when a reference to any member occurs
235.2745 + for the first time */
235.2746 + double value;
235.2747 + /* evaluated numeric value */
235.2748 +};
235.2749 +
235.2750 +static void eval_num_func(MPL *mpl, void *_info)
235.2751 +{ /* this is auxiliary routine to work within domain scope */
235.2752 + struct eval_num_info *info = _info;
235.2753 + if (info->memb != NULL)
235.2754 + { /* checking call; check numeric value being assigned */
235.2755 + check_value_num(mpl, info->par, info->memb->tuple,
235.2756 + info->memb->value.num);
235.2757 + }
235.2758 + else
235.2759 + { /* normal call; evaluate member, which has given n-tuple */
235.2760 + info->value = take_member_num(mpl, info->par, info->tuple);
235.2761 + }
235.2762 + return;
235.2763 +}
235.2764 +
235.2765 +double eval_member_num
235.2766 +( MPL *mpl,
235.2767 + PARAMETER *par, /* not changed */
235.2768 + TUPLE *tuple /* not changed */
235.2769 +)
235.2770 +{ /* this routine evaluates numeric parameter member */
235.2771 + struct eval_num_info _info, *info = &_info;
235.2772 + xassert(par->type == A_NUMERIC || par->type == A_INTEGER ||
235.2773 + par->type == A_BINARY);
235.2774 + xassert(par->dim == tuple_dimen(mpl, tuple));
235.2775 + info->par = par;
235.2776 + info->tuple = tuple;
235.2777 + if (par->data == 1)
235.2778 + { /* check data, which are provided in the data section, but not
235.2779 + checked yet */
235.2780 + /* save pointer to the last array member; note that during the
235.2781 + check new members may be added beyond the last member due to
235.2782 + references to the same parameter from default expression as
235.2783 + well as from expressions that define restricting conditions;
235.2784 + however, values assigned to the new members will be checked
235.2785 + by other routine, so we don't need to check them here */
235.2786 + MEMBER *tail = par->array->tail;
235.2787 + /* change the data status to prevent infinite recursive loop
235.2788 + due to references to the same parameter during the check */
235.2789 + par->data = 2;
235.2790 + /* check values assigned to array members in the data section
235.2791 + until the marked member has been reached */
235.2792 + for (info->memb = par->array->head; info->memb != NULL;
235.2793 + info->memb = info->memb->next)
235.2794 + { if (eval_within_domain(mpl, par->domain, info->memb->tuple,
235.2795 + info, eval_num_func))
235.2796 + out_of_domain(mpl, par->name, info->memb->tuple);
235.2797 + if (info->memb == tail) break;
235.2798 + }
235.2799 + /* the check has been finished */
235.2800 + }
235.2801 + /* evaluate member, which has given n-tuple */
235.2802 + info->memb = NULL;
235.2803 + if (eval_within_domain(mpl, info->par->domain, info->tuple, info,
235.2804 + eval_num_func))
235.2805 + out_of_domain(mpl, par->name, info->tuple);
235.2806 + /* bring evaluated value to the calling program */
235.2807 + return info->value;
235.2808 +}
235.2809 +
235.2810 +/*----------------------------------------------------------------------
235.2811 +-- check_value_sym - check symbolic value assigned to parameter member.
235.2812 +--
235.2813 +-- This routine checks if symbolic value being assigned to some member
235.2814 +-- of specified symbolic model parameter satisfies to all restrictions.
235.2815 +--
235.2816 +-- NOTE: This routine must not be called out of domain scope. */
235.2817 +
235.2818 +void check_value_sym
235.2819 +( MPL *mpl,
235.2820 + PARAMETER *par, /* not changed */
235.2821 + TUPLE *tuple, /* not changed */
235.2822 + SYMBOL *value /* not changed */
235.2823 +)
235.2824 +{ CONDITION *cond;
235.2825 + WITHIN *in;
235.2826 + int eqno;
235.2827 + /* the value must satisfy to all specified conditions */
235.2828 + for (cond = par->cond, eqno = 1; cond != NULL; cond = cond->next,
235.2829 + eqno++)
235.2830 + { SYMBOL *bound;
235.2831 + char buf[255+1];
235.2832 + xassert(cond->code != NULL);
235.2833 + bound = eval_symbolic(mpl, cond->code);
235.2834 + switch (cond->rho)
235.2835 + {
235.2836 +#if 1 /* 13/VIII-2008 */
235.2837 + case O_LT:
235.2838 + if (!(compare_symbols(mpl, value, bound) < 0))
235.2839 + { strcpy(buf, format_symbol(mpl, bound));
235.2840 + xassert(strlen(buf) < sizeof(buf));
235.2841 + error(mpl, "%s%s = %s not < %s",
235.2842 + par->name, format_tuple(mpl, '[', tuple),
235.2843 + format_symbol(mpl, value), buf, eqno);
235.2844 + }
235.2845 + break;
235.2846 + case O_LE:
235.2847 + if (!(compare_symbols(mpl, value, bound) <= 0))
235.2848 + { strcpy(buf, format_symbol(mpl, bound));
235.2849 + xassert(strlen(buf) < sizeof(buf));
235.2850 + error(mpl, "%s%s = %s not <= %s",
235.2851 + par->name, format_tuple(mpl, '[', tuple),
235.2852 + format_symbol(mpl, value), buf, eqno);
235.2853 + }
235.2854 + break;
235.2855 +#endif
235.2856 + case O_EQ:
235.2857 + if (!(compare_symbols(mpl, value, bound) == 0))
235.2858 + { strcpy(buf, format_symbol(mpl, bound));
235.2859 + xassert(strlen(buf) < sizeof(buf));
235.2860 + error(mpl, "%s%s = %s not = %s",
235.2861 + par->name, format_tuple(mpl, '[', tuple),
235.2862 + format_symbol(mpl, value), buf, eqno);
235.2863 + }
235.2864 + break;
235.2865 +#if 1 /* 13/VIII-2008 */
235.2866 + case O_GE:
235.2867 + if (!(compare_symbols(mpl, value, bound) >= 0))
235.2868 + { strcpy(buf, format_symbol(mpl, bound));
235.2869 + xassert(strlen(buf) < sizeof(buf));
235.2870 + error(mpl, "%s%s = %s not >= %s",
235.2871 + par->name, format_tuple(mpl, '[', tuple),
235.2872 + format_symbol(mpl, value), buf, eqno);
235.2873 + }
235.2874 + break;
235.2875 + case O_GT:
235.2876 + if (!(compare_symbols(mpl, value, bound) > 0))
235.2877 + { strcpy(buf, format_symbol(mpl, bound));
235.2878 + xassert(strlen(buf) < sizeof(buf));
235.2879 + error(mpl, "%s%s = %s not > %s",
235.2880 + par->name, format_tuple(mpl, '[', tuple),
235.2881 + format_symbol(mpl, value), buf, eqno);
235.2882 + }
235.2883 + break;
235.2884 +#endif
235.2885 + case O_NE:
235.2886 + if (!(compare_symbols(mpl, value, bound) != 0))
235.2887 + { strcpy(buf, format_symbol(mpl, bound));
235.2888 + xassert(strlen(buf) < sizeof(buf));
235.2889 + error(mpl, "%s%s = %s not <> %s",
235.2890 + par->name, format_tuple(mpl, '[', tuple),
235.2891 + format_symbol(mpl, value), buf, eqno);
235.2892 + }
235.2893 + break;
235.2894 + default:
235.2895 + xassert(cond != cond);
235.2896 + }
235.2897 + delete_symbol(mpl, bound);
235.2898 + }
235.2899 + /* the value must be in all specified supersets */
235.2900 + for (in = par->in, eqno = 1; in != NULL; in = in->next, eqno++)
235.2901 + { TUPLE *dummy;
235.2902 + xassert(in->code != NULL);
235.2903 + xassert(in->code->dim == 1);
235.2904 + dummy = expand_tuple(mpl, create_tuple(mpl), copy_symbol(mpl,
235.2905 + value));
235.2906 + if (!is_member(mpl, in->code, dummy))
235.2907 + error(mpl, "%s%s = %s not in specified set; see (%d)",
235.2908 + par->name, format_tuple(mpl, '[', tuple),
235.2909 + format_symbol(mpl, value), eqno);
235.2910 + delete_tuple(mpl, dummy);
235.2911 + }
235.2912 + return;
235.2913 +}
235.2914 +
235.2915 +/*----------------------------------------------------------------------
235.2916 +-- take_member_sym - obtain symb. value assigned to parameter member.
235.2917 +--
235.2918 +-- This routine obtains a symbolic value assigned to member of specified
235.2919 +-- symbolic model parameter and returns it on exit.
235.2920 +--
235.2921 +-- NOTE: This routine must not be called out of domain scope. */
235.2922 +
235.2923 +SYMBOL *take_member_sym /* returns value, not reference */
235.2924 +( MPL *mpl,
235.2925 + PARAMETER *par, /* not changed */
235.2926 + TUPLE *tuple /* not changed */
235.2927 +)
235.2928 +{ MEMBER *memb;
235.2929 + SYMBOL *value;
235.2930 + /* find member in the parameter array */
235.2931 + memb = find_member(mpl, par->array, tuple);
235.2932 + if (memb != NULL)
235.2933 + { /* member exists, so just take its value */
235.2934 + value = copy_symbol(mpl, memb->value.sym);
235.2935 + }
235.2936 + else if (par->assign != NULL)
235.2937 + { /* compute value using assignment expression */
235.2938 + value = eval_symbolic(mpl, par->assign);
235.2939 +add: /* check that the value satisfies to all restrictions, assign
235.2940 + it to new member, and add the member to the array */
235.2941 + check_value_sym(mpl, par, tuple, value);
235.2942 + memb = add_member(mpl, par->array, copy_tuple(mpl, tuple));
235.2943 + memb->value.sym = copy_symbol(mpl, value);
235.2944 + }
235.2945 + else if (par->option != NULL)
235.2946 + { /* compute default value */
235.2947 + value = eval_symbolic(mpl, par->option);
235.2948 + goto add;
235.2949 + }
235.2950 + else if (par->defval != NULL)
235.2951 + { /* take default value provided in the data section */
235.2952 + value = copy_symbol(mpl, par->defval);
235.2953 + goto add;
235.2954 + }
235.2955 + else
235.2956 + { /* no value is provided */
235.2957 + error(mpl, "no value for %s%s", par->name, format_tuple(mpl,
235.2958 + '[', tuple));
235.2959 + }
235.2960 + return value;
235.2961 +}
235.2962 +
235.2963 +/*----------------------------------------------------------------------
235.2964 +-- eval_member_sym - evaluate symb. value assigned to parameter member.
235.2965 +--
235.2966 +-- This routine evaluates a symbolic value assigned to given member of
235.2967 +-- specified symbolic model parameter and returns it on exit. */
235.2968 +
235.2969 +struct eval_sym_info
235.2970 +{ /* working info used by the routine eval_member_sym */
235.2971 + PARAMETER *par;
235.2972 + /* model parameter */
235.2973 + TUPLE *tuple;
235.2974 + /* n-tuple, which defines parameter member */
235.2975 + MEMBER *memb;
235.2976 + /* normally this pointer is NULL; the routine uses this pointer
235.2977 + to check data provided in the data section, in which case it
235.2978 + points to a member currently checked; this check is performed
235.2979 + automatically only once when a reference to any member occurs
235.2980 + for the first time */
235.2981 + SYMBOL *value;
235.2982 + /* evaluated symbolic value */
235.2983 +};
235.2984 +
235.2985 +static void eval_sym_func(MPL *mpl, void *_info)
235.2986 +{ /* this is auxiliary routine to work within domain scope */
235.2987 + struct eval_sym_info *info = _info;
235.2988 + if (info->memb != NULL)
235.2989 + { /* checking call; check symbolic value being assigned */
235.2990 + check_value_sym(mpl, info->par, info->memb->tuple,
235.2991 + info->memb->value.sym);
235.2992 + }
235.2993 + else
235.2994 + { /* normal call; evaluate member, which has given n-tuple */
235.2995 + info->value = take_member_sym(mpl, info->par, info->tuple);
235.2996 + }
235.2997 + return;
235.2998 +}
235.2999 +
235.3000 +SYMBOL *eval_member_sym /* returns value, not reference */
235.3001 +( MPL *mpl,
235.3002 + PARAMETER *par, /* not changed */
235.3003 + TUPLE *tuple /* not changed */
235.3004 +)
235.3005 +{ /* this routine evaluates symbolic parameter member */
235.3006 + struct eval_sym_info _info, *info = &_info;
235.3007 + xassert(par->type == A_SYMBOLIC);
235.3008 + xassert(par->dim == tuple_dimen(mpl, tuple));
235.3009 + info->par = par;
235.3010 + info->tuple = tuple;
235.3011 + if (par->data == 1)
235.3012 + { /* check data, which are provided in the data section, but not
235.3013 + checked yet */
235.3014 + /* save pointer to the last array member; note that during the
235.3015 + check new members may be added beyond the last member due to
235.3016 + references to the same parameter from default expression as
235.3017 + well as from expressions that define restricting conditions;
235.3018 + however, values assigned to the new members will be checked
235.3019 + by other routine, so we don't need to check them here */
235.3020 + MEMBER *tail = par->array->tail;
235.3021 + /* change the data status to prevent infinite recursive loop
235.3022 + due to references to the same parameter during the check */
235.3023 + par->data = 2;
235.3024 + /* check values assigned to array members in the data section
235.3025 + until the marked member has been reached */
235.3026 + for (info->memb = par->array->head; info->memb != NULL;
235.3027 + info->memb = info->memb->next)
235.3028 + { if (eval_within_domain(mpl, par->domain, info->memb->tuple,
235.3029 + info, eval_sym_func))
235.3030 + out_of_domain(mpl, par->name, info->memb->tuple);
235.3031 + if (info->memb == tail) break;
235.3032 + }
235.3033 + /* the check has been finished */
235.3034 + }
235.3035 + /* evaluate member, which has given n-tuple */
235.3036 + info->memb = NULL;
235.3037 + if (eval_within_domain(mpl, info->par->domain, info->tuple, info,
235.3038 + eval_sym_func))
235.3039 + out_of_domain(mpl, par->name, info->tuple);
235.3040 + /* bring evaluated value to the calling program */
235.3041 + return info->value;
235.3042 +}
235.3043 +
235.3044 +/*----------------------------------------------------------------------
235.3045 +-- eval_whole_par - evaluate model parameter over entire domain.
235.3046 +--
235.3047 +-- This routine evaluates all members of specified model parameter over
235.3048 +-- entire domain. */
235.3049 +
235.3050 +static int whole_par_func(MPL *mpl, void *info)
235.3051 +{ /* this is auxiliary routine to work within domain scope */
235.3052 + PARAMETER *par = (PARAMETER *)info;
235.3053 + TUPLE *tuple = get_domain_tuple(mpl, par->domain);
235.3054 + switch (par->type)
235.3055 + { case A_NUMERIC:
235.3056 + case A_INTEGER:
235.3057 + case A_BINARY:
235.3058 + eval_member_num(mpl, par, tuple);
235.3059 + break;
235.3060 + case A_SYMBOLIC:
235.3061 + delete_symbol(mpl, eval_member_sym(mpl, par, tuple));
235.3062 + break;
235.3063 + default:
235.3064 + xassert(par != par);
235.3065 + }
235.3066 + delete_tuple(mpl, tuple);
235.3067 + return 0;
235.3068 +}
235.3069 +
235.3070 +void eval_whole_par(MPL *mpl, PARAMETER *par)
235.3071 +{ loop_within_domain(mpl, par->domain, par, whole_par_func);
235.3072 + return;
235.3073 +}
235.3074 +
235.3075 +/*----------------------------------------------------------------------
235.3076 +-- clean_parameter - clean model parameter.
235.3077 +--
235.3078 +-- This routine cleans specified model parameter that assumes deleting
235.3079 +-- all stuff dynamically allocated during the generation phase. */
235.3080 +
235.3081 +void clean_parameter(MPL *mpl, PARAMETER *par)
235.3082 +{ CONDITION *cond;
235.3083 + WITHIN *in;
235.3084 + MEMBER *memb;
235.3085 + /* clean subscript domain */
235.3086 + clean_domain(mpl, par->domain);
235.3087 + /* clean pseudo-code for computing restricting conditions */
235.3088 + for (cond = par->cond; cond != NULL; cond = cond->next)
235.3089 + clean_code(mpl, cond->code);
235.3090 + /* clean pseudo-code for computing restricting supersets */
235.3091 + for (in = par->in; in != NULL; in = in->next)
235.3092 + clean_code(mpl, in->code);
235.3093 + /* clean pseudo-code for computing assigned value */
235.3094 + clean_code(mpl, par->assign);
235.3095 + /* clean pseudo-code for computing default value */
235.3096 + clean_code(mpl, par->option);
235.3097 + /* reset data status flag */
235.3098 + par->data = 0;
235.3099 + /* delete default symbolic value */
235.3100 + if (par->defval != NULL)
235.3101 + delete_symbol(mpl, par->defval), par->defval = NULL;
235.3102 + /* delete content array */
235.3103 + for (memb = par->array->head; memb != NULL; memb = memb->next)
235.3104 + delete_value(mpl, par->array->type, &memb->value);
235.3105 + delete_array(mpl, par->array), par->array = NULL;
235.3106 + return;
235.3107 +}
235.3108 +
235.3109 +/**********************************************************************/
235.3110 +/* * * MODEL VARIABLES * * */
235.3111 +/**********************************************************************/
235.3112 +
235.3113 +/*----------------------------------------------------------------------
235.3114 +-- take_member_var - obtain reference to elemental variable.
235.3115 +--
235.3116 +-- This routine obtains a reference to elemental variable assigned to
235.3117 +-- given member of specified model variable and returns it on exit. If
235.3118 +-- necessary, new elemental variable is created.
235.3119 +--
235.3120 +-- NOTE: This routine must not be called out of domain scope. */
235.3121 +
235.3122 +ELEMVAR *take_member_var /* returns reference */
235.3123 +( MPL *mpl,
235.3124 + VARIABLE *var, /* not changed */
235.3125 + TUPLE *tuple /* not changed */
235.3126 +)
235.3127 +{ MEMBER *memb;
235.3128 + ELEMVAR *refer;
235.3129 + /* find member in the variable array */
235.3130 + memb = find_member(mpl, var->array, tuple);
235.3131 + if (memb != NULL)
235.3132 + { /* member exists, so just take the reference */
235.3133 + refer = memb->value.var;
235.3134 + }
235.3135 + else
235.3136 + { /* member is referenced for the first time and therefore does
235.3137 + not exist; create new elemental variable, assign it to new
235.3138 + member, and add the member to the variable array */
235.3139 + memb = add_member(mpl, var->array, copy_tuple(mpl, tuple));
235.3140 + refer = (memb->value.var =
235.3141 + dmp_get_atom(mpl->elemvars, sizeof(ELEMVAR)));
235.3142 + refer->j = 0;
235.3143 + refer->var = var;
235.3144 + refer->memb = memb;
235.3145 + /* compute lower bound */
235.3146 + if (var->lbnd == NULL)
235.3147 + refer->lbnd = 0.0;
235.3148 + else
235.3149 + refer->lbnd = eval_numeric(mpl, var->lbnd);
235.3150 + /* compute upper bound */
235.3151 + if (var->ubnd == NULL)
235.3152 + refer->ubnd = 0.0;
235.3153 + else if (var->ubnd == var->lbnd)
235.3154 + refer->ubnd = refer->lbnd;
235.3155 + else
235.3156 + refer->ubnd = eval_numeric(mpl, var->ubnd);
235.3157 + /* nullify working quantity */
235.3158 + refer->temp = 0.0;
235.3159 +#if 1 /* 15/V-2010 */
235.3160 + /* solution has not been obtained by the solver yet */
235.3161 + refer->stat = 0;
235.3162 + refer->prim = refer->dual = 0.0;
235.3163 +#endif
235.3164 + }
235.3165 + return refer;
235.3166 +}
235.3167 +
235.3168 +/*----------------------------------------------------------------------
235.3169 +-- eval_member_var - evaluate reference to elemental variable.
235.3170 +--
235.3171 +-- This routine evaluates a reference to elemental variable assigned to
235.3172 +-- member of specified model variable and returns it on exit. */
235.3173 +
235.3174 +struct eval_var_info
235.3175 +{ /* working info used by the routine eval_member_var */
235.3176 + VARIABLE *var;
235.3177 + /* model variable */
235.3178 + TUPLE *tuple;
235.3179 + /* n-tuple, which defines variable member */
235.3180 + ELEMVAR *refer;
235.3181 + /* evaluated reference to elemental variable */
235.3182 +};
235.3183 +
235.3184 +static void eval_var_func(MPL *mpl, void *_info)
235.3185 +{ /* this is auxiliary routine to work within domain scope */
235.3186 + struct eval_var_info *info = _info;
235.3187 + info->refer = take_member_var(mpl, info->var, info->tuple);
235.3188 + return;
235.3189 +}
235.3190 +
235.3191 +ELEMVAR *eval_member_var /* returns reference */
235.3192 +( MPL *mpl,
235.3193 + VARIABLE *var, /* not changed */
235.3194 + TUPLE *tuple /* not changed */
235.3195 +)
235.3196 +{ /* this routine evaluates variable member */
235.3197 + struct eval_var_info _info, *info = &_info;
235.3198 + xassert(var->dim == tuple_dimen(mpl, tuple));
235.3199 + info->var = var;
235.3200 + info->tuple = tuple;
235.3201 + /* evaluate member, which has given n-tuple */
235.3202 + if (eval_within_domain(mpl, info->var->domain, info->tuple, info,
235.3203 + eval_var_func))
235.3204 + out_of_domain(mpl, var->name, info->tuple);
235.3205 + /* bring evaluated reference to the calling program */
235.3206 + return info->refer;
235.3207 +}
235.3208 +
235.3209 +/*----------------------------------------------------------------------
235.3210 +-- eval_whole_var - evaluate model variable over entire domain.
235.3211 +--
235.3212 +-- This routine evaluates all members of specified model variable over
235.3213 +-- entire domain. */
235.3214 +
235.3215 +static int whole_var_func(MPL *mpl, void *info)
235.3216 +{ /* this is auxiliary routine to work within domain scope */
235.3217 + VARIABLE *var = (VARIABLE *)info;
235.3218 + TUPLE *tuple = get_domain_tuple(mpl, var->domain);
235.3219 + eval_member_var(mpl, var, tuple);
235.3220 + delete_tuple(mpl, tuple);
235.3221 + return 0;
235.3222 +}
235.3223 +
235.3224 +void eval_whole_var(MPL *mpl, VARIABLE *var)
235.3225 +{ loop_within_domain(mpl, var->domain, var, whole_var_func);
235.3226 + return;
235.3227 +}
235.3228 +
235.3229 +/*----------------------------------------------------------------------
235.3230 +-- clean_variable - clean model variable.
235.3231 +--
235.3232 +-- This routine cleans specified model variable that assumes deleting
235.3233 +-- all stuff dynamically allocated during the generation phase. */
235.3234 +
235.3235 +void clean_variable(MPL *mpl, VARIABLE *var)
235.3236 +{ MEMBER *memb;
235.3237 + /* clean subscript domain */
235.3238 + clean_domain(mpl, var->domain);
235.3239 + /* clean code for computing lower bound */
235.3240 + clean_code(mpl, var->lbnd);
235.3241 + /* clean code for computing upper bound */
235.3242 + if (var->ubnd != var->lbnd) clean_code(mpl, var->ubnd);
235.3243 + /* delete content array */
235.3244 + for (memb = var->array->head; memb != NULL; memb = memb->next)
235.3245 + dmp_free_atom(mpl->elemvars, memb->value.var, sizeof(ELEMVAR));
235.3246 + delete_array(mpl, var->array), var->array = NULL;
235.3247 + return;
235.3248 +}
235.3249 +
235.3250 +/**********************************************************************/
235.3251 +/* * * MODEL CONSTRAINTS AND OBJECTIVES * * */
235.3252 +/**********************************************************************/
235.3253 +
235.3254 +/*----------------------------------------------------------------------
235.3255 +-- take_member_con - obtain reference to elemental constraint.
235.3256 +--
235.3257 +-- This routine obtains a reference to elemental constraint assigned
235.3258 +-- to given member of specified model constraint and returns it on exit.
235.3259 +-- If necessary, new elemental constraint is created.
235.3260 +--
235.3261 +-- NOTE: This routine must not be called out of domain scope. */
235.3262 +
235.3263 +ELEMCON *take_member_con /* returns reference */
235.3264 +( MPL *mpl,
235.3265 + CONSTRAINT *con, /* not changed */
235.3266 + TUPLE *tuple /* not changed */
235.3267 +)
235.3268 +{ MEMBER *memb;
235.3269 + ELEMCON *refer;
235.3270 + /* find member in the constraint array */
235.3271 + memb = find_member(mpl, con->array, tuple);
235.3272 + if (memb != NULL)
235.3273 + { /* member exists, so just take the reference */
235.3274 + refer = memb->value.con;
235.3275 + }
235.3276 + else
235.3277 + { /* member is referenced for the first time and therefore does
235.3278 + not exist; create new elemental constraint, assign it to new
235.3279 + member, and add the member to the constraint array */
235.3280 + memb = add_member(mpl, con->array, copy_tuple(mpl, tuple));
235.3281 + refer = (memb->value.con =
235.3282 + dmp_get_atom(mpl->elemcons, sizeof(ELEMCON)));
235.3283 + refer->i = 0;
235.3284 + refer->con = con;
235.3285 + refer->memb = memb;
235.3286 + /* compute linear form */
235.3287 + xassert(con->code != NULL);
235.3288 + refer->form = eval_formula(mpl, con->code);
235.3289 + /* compute lower and upper bounds */
235.3290 + if (con->lbnd == NULL && con->ubnd == NULL)
235.3291 + { /* objective has no bounds */
235.3292 + double temp;
235.3293 + xassert(con->type == A_MINIMIZE || con->type == A_MAXIMIZE);
235.3294 + /* carry the constant term to the right-hand side */
235.3295 + refer->form = remove_constant(mpl, refer->form, &temp);
235.3296 + refer->lbnd = refer->ubnd = - temp;
235.3297 + }
235.3298 + else if (con->lbnd != NULL && con->ubnd == NULL)
235.3299 + { /* constraint a * x + b >= c * y + d is transformed to the
235.3300 + standard form a * x - c * y >= d - b */
235.3301 + double temp;
235.3302 + xassert(con->type == A_CONSTRAINT);
235.3303 + refer->form = linear_comb(mpl,
235.3304 + +1.0, refer->form,
235.3305 + -1.0, eval_formula(mpl, con->lbnd));
235.3306 + refer->form = remove_constant(mpl, refer->form, &temp);
235.3307 + refer->lbnd = - temp;
235.3308 + refer->ubnd = 0.0;
235.3309 + }
235.3310 + else if (con->lbnd == NULL && con->ubnd != NULL)
235.3311 + { /* constraint a * x + b <= c * y + d is transformed to the
235.3312 + standard form a * x - c * y <= d - b */
235.3313 + double temp;
235.3314 + xassert(con->type == A_CONSTRAINT);
235.3315 + refer->form = linear_comb(mpl,
235.3316 + +1.0, refer->form,
235.3317 + -1.0, eval_formula(mpl, con->ubnd));
235.3318 + refer->form = remove_constant(mpl, refer->form, &temp);
235.3319 + refer->lbnd = 0.0;
235.3320 + refer->ubnd = - temp;
235.3321 + }
235.3322 + else if (con->lbnd == con->ubnd)
235.3323 + { /* constraint a * x + b = c * y + d is transformed to the
235.3324 + standard form a * x - c * y = d - b */
235.3325 + double temp;
235.3326 + xassert(con->type == A_CONSTRAINT);
235.3327 + refer->form = linear_comb(mpl,
235.3328 + +1.0, refer->form,
235.3329 + -1.0, eval_formula(mpl, con->lbnd));
235.3330 + refer->form = remove_constant(mpl, refer->form, &temp);
235.3331 + refer->lbnd = refer->ubnd = - temp;
235.3332 + }
235.3333 + else
235.3334 + { /* ranged constraint c <= a * x + b <= d is transformed to
235.3335 + the standard form c - b <= a * x <= d - b */
235.3336 + double temp, temp1, temp2;
235.3337 + xassert(con->type == A_CONSTRAINT);
235.3338 + refer->form = remove_constant(mpl, refer->form, &temp);
235.3339 + xassert(remove_constant(mpl, eval_formula(mpl, con->lbnd),
235.3340 + &temp1) == NULL);
235.3341 + xassert(remove_constant(mpl, eval_formula(mpl, con->ubnd),
235.3342 + &temp2) == NULL);
235.3343 + refer->lbnd = fp_sub(mpl, temp1, temp);
235.3344 + refer->ubnd = fp_sub(mpl, temp2, temp);
235.3345 + }
235.3346 +#if 1 /* 15/V-2010 */
235.3347 + /* solution has not been obtained by the solver yet */
235.3348 + refer->stat = 0;
235.3349 + refer->prim = refer->dual = 0.0;
235.3350 +#endif
235.3351 + }
235.3352 + return refer;
235.3353 +}
235.3354 +
235.3355 +/*----------------------------------------------------------------------
235.3356 +-- eval_member_con - evaluate reference to elemental constraint.
235.3357 +--
235.3358 +-- This routine evaluates a reference to elemental constraint assigned
235.3359 +-- to member of specified model constraint and returns it on exit. */
235.3360 +
235.3361 +struct eval_con_info
235.3362 +{ /* working info used by the routine eval_member_con */
235.3363 + CONSTRAINT *con;
235.3364 + /* model constraint */
235.3365 + TUPLE *tuple;
235.3366 + /* n-tuple, which defines constraint member */
235.3367 + ELEMCON *refer;
235.3368 + /* evaluated reference to elemental constraint */
235.3369 +};
235.3370 +
235.3371 +static void eval_con_func(MPL *mpl, void *_info)
235.3372 +{ /* this is auxiliary routine to work within domain scope */
235.3373 + struct eval_con_info *info = _info;
235.3374 + info->refer = take_member_con(mpl, info->con, info->tuple);
235.3375 + return;
235.3376 +}
235.3377 +
235.3378 +ELEMCON *eval_member_con /* returns reference */
235.3379 +( MPL *mpl,
235.3380 + CONSTRAINT *con, /* not changed */
235.3381 + TUPLE *tuple /* not changed */
235.3382 +)
235.3383 +{ /* this routine evaluates constraint member */
235.3384 + struct eval_con_info _info, *info = &_info;
235.3385 + xassert(con->dim == tuple_dimen(mpl, tuple));
235.3386 + info->con = con;
235.3387 + info->tuple = tuple;
235.3388 + /* evaluate member, which has given n-tuple */
235.3389 + if (eval_within_domain(mpl, info->con->domain, info->tuple, info,
235.3390 + eval_con_func))
235.3391 + out_of_domain(mpl, con->name, info->tuple);
235.3392 + /* bring evaluated reference to the calling program */
235.3393 + return info->refer;
235.3394 +}
235.3395 +
235.3396 +/*----------------------------------------------------------------------
235.3397 +-- eval_whole_con - evaluate model constraint over entire domain.
235.3398 +--
235.3399 +-- This routine evaluates all members of specified model constraint over
235.3400 +-- entire domain. */
235.3401 +
235.3402 +static int whole_con_func(MPL *mpl, void *info)
235.3403 +{ /* this is auxiliary routine to work within domain scope */
235.3404 + CONSTRAINT *con = (CONSTRAINT *)info;
235.3405 + TUPLE *tuple = get_domain_tuple(mpl, con->domain);
235.3406 + eval_member_con(mpl, con, tuple);
235.3407 + delete_tuple(mpl, tuple);
235.3408 + return 0;
235.3409 +}
235.3410 +
235.3411 +void eval_whole_con(MPL *mpl, CONSTRAINT *con)
235.3412 +{ loop_within_domain(mpl, con->domain, con, whole_con_func);
235.3413 + return;
235.3414 +}
235.3415 +
235.3416 +/*----------------------------------------------------------------------
235.3417 +-- clean_constraint - clean model constraint.
235.3418 +--
235.3419 +-- This routine cleans specified model constraint that assumes deleting
235.3420 +-- all stuff dynamically allocated during the generation phase. */
235.3421 +
235.3422 +void clean_constraint(MPL *mpl, CONSTRAINT *con)
235.3423 +{ MEMBER *memb;
235.3424 + /* clean subscript domain */
235.3425 + clean_domain(mpl, con->domain);
235.3426 + /* clean code for computing main linear form */
235.3427 + clean_code(mpl, con->code);
235.3428 + /* clean code for computing lower bound */
235.3429 + clean_code(mpl, con->lbnd);
235.3430 + /* clean code for computing upper bound */
235.3431 + if (con->ubnd != con->lbnd) clean_code(mpl, con->ubnd);
235.3432 + /* delete content array */
235.3433 + for (memb = con->array->head; memb != NULL; memb = memb->next)
235.3434 + { delete_formula(mpl, memb->value.con->form);
235.3435 + dmp_free_atom(mpl->elemcons, memb->value.con, sizeof(ELEMCON));
235.3436 + }
235.3437 + delete_array(mpl, con->array), con->array = NULL;
235.3438 + return;
235.3439 +}
235.3440 +
235.3441 +/**********************************************************************/
235.3442 +/* * * PSEUDO-CODE * * */
235.3443 +/**********************************************************************/
235.3444 +
235.3445 +/*----------------------------------------------------------------------
235.3446 +-- eval_numeric - evaluate pseudo-code to determine numeric value.
235.3447 +--
235.3448 +-- This routine evaluates specified pseudo-code to determine resultant
235.3449 +-- numeric value, which is returned on exit. */
235.3450 +
235.3451 +struct iter_num_info
235.3452 +{ /* working info used by the routine iter_num_func */
235.3453 + CODE *code;
235.3454 + /* pseudo-code for iterated operation to be performed */
235.3455 + double value;
235.3456 + /* resultant value */
235.3457 +};
235.3458 +
235.3459 +static int iter_num_func(MPL *mpl, void *_info)
235.3460 +{ /* this is auxiliary routine used to perform iterated operation
235.3461 + on numeric "integrand" within domain scope */
235.3462 + struct iter_num_info *info = _info;
235.3463 + double temp;
235.3464 + temp = eval_numeric(mpl, info->code->arg.loop.x);
235.3465 + switch (info->code->op)
235.3466 + { case O_SUM:
235.3467 + /* summation over domain */
235.3468 + info->value = fp_add(mpl, info->value, temp);
235.3469 + break;
235.3470 + case O_PROD:
235.3471 + /* multiplication over domain */
235.3472 + info->value = fp_mul(mpl, info->value, temp);
235.3473 + break;
235.3474 + case O_MINIMUM:
235.3475 + /* minimum over domain */
235.3476 + if (info->value > temp) info->value = temp;
235.3477 + break;
235.3478 + case O_MAXIMUM:
235.3479 + /* maximum over domain */
235.3480 + if (info->value < temp) info->value = temp;
235.3481 + break;
235.3482 + default:
235.3483 + xassert(info != info);
235.3484 + }
235.3485 + return 0;
235.3486 +}
235.3487 +
235.3488 +double eval_numeric(MPL *mpl, CODE *code)
235.3489 +{ double value;
235.3490 + xassert(code != NULL);
235.3491 + xassert(code->type == A_NUMERIC);
235.3492 + xassert(code->dim == 0);
235.3493 + /* if the operation has a side effect, invalidate and delete the
235.3494 + resultant value */
235.3495 + if (code->vflag && code->valid)
235.3496 + { code->valid = 0;
235.3497 + delete_value(mpl, code->type, &code->value);
235.3498 + }
235.3499 + /* if resultant value is valid, no evaluation is needed */
235.3500 + if (code->valid)
235.3501 + { value = code->value.num;
235.3502 + goto done;
235.3503 + }
235.3504 + /* evaluate pseudo-code recursively */
235.3505 + switch (code->op)
235.3506 + { case O_NUMBER:
235.3507 + /* take floating-point number */
235.3508 + value = code->arg.num;
235.3509 + break;
235.3510 + case O_MEMNUM:
235.3511 + /* take member of numeric parameter */
235.3512 + { TUPLE *tuple;
235.3513 + ARG_LIST *e;
235.3514 + tuple = create_tuple(mpl);
235.3515 + for (e = code->arg.par.list; e != NULL; e = e->next)
235.3516 + tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
235.3517 + e->x));
235.3518 + value = eval_member_num(mpl, code->arg.par.par, tuple);
235.3519 + delete_tuple(mpl, tuple);
235.3520 + }
235.3521 + break;
235.3522 + case O_MEMVAR:
235.3523 + /* take computed value of elemental variable */
235.3524 + { TUPLE *tuple;
235.3525 + ARG_LIST *e;
235.3526 +#if 1 /* 15/V-2010 */
235.3527 + ELEMVAR *var;
235.3528 +#endif
235.3529 + tuple = create_tuple(mpl);
235.3530 + for (e = code->arg.var.list; e != NULL; e = e->next)
235.3531 + tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
235.3532 + e->x));
235.3533 +#if 0 /* 15/V-2010 */
235.3534 + value = eval_member_var(mpl, code->arg.var.var, tuple)
235.3535 + ->value;
235.3536 +#else
235.3537 + var = eval_member_var(mpl, code->arg.var.var, tuple);
235.3538 + switch (code->arg.var.suff)
235.3539 + { case DOT_LB:
235.3540 + if (var->var->lbnd == NULL)
235.3541 + value = -DBL_MAX;
235.3542 + else
235.3543 + value = var->lbnd;
235.3544 + break;
235.3545 + case DOT_UB:
235.3546 + if (var->var->ubnd == NULL)
235.3547 + value = +DBL_MAX;
235.3548 + else
235.3549 + value = var->ubnd;
235.3550 + break;
235.3551 + case DOT_STATUS:
235.3552 + value = var->stat;
235.3553 + break;
235.3554 + case DOT_VAL:
235.3555 + value = var->prim;
235.3556 + break;
235.3557 + case DOT_DUAL:
235.3558 + value = var->dual;
235.3559 + break;
235.3560 + default:
235.3561 + xassert(code != code);
235.3562 + }
235.3563 +#endif
235.3564 + delete_tuple(mpl, tuple);
235.3565 + }
235.3566 + break;
235.3567 +#if 1 /* 15/V-2010 */
235.3568 + case O_MEMCON:
235.3569 + /* take computed value of elemental constraint */
235.3570 + { TUPLE *tuple;
235.3571 + ARG_LIST *e;
235.3572 + ELEMCON *con;
235.3573 + tuple = create_tuple(mpl);
235.3574 + for (e = code->arg.con.list; e != NULL; e = e->next)
235.3575 + tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
235.3576 + e->x));
235.3577 + con = eval_member_con(mpl, code->arg.con.con, tuple);
235.3578 + switch (code->arg.con.suff)
235.3579 + { case DOT_LB:
235.3580 + if (con->con->lbnd == NULL)
235.3581 + value = -DBL_MAX;
235.3582 + else
235.3583 + value = con->lbnd;
235.3584 + break;
235.3585 + case DOT_UB:
235.3586 + if (con->con->ubnd == NULL)
235.3587 + value = +DBL_MAX;
235.3588 + else
235.3589 + value = con->ubnd;
235.3590 + break;
235.3591 + case DOT_STATUS:
235.3592 + value = con->stat;
235.3593 + break;
235.3594 + case DOT_VAL:
235.3595 + value = con->prim;
235.3596 + break;
235.3597 + case DOT_DUAL:
235.3598 + value = con->dual;
235.3599 + break;
235.3600 + default:
235.3601 + xassert(code != code);
235.3602 + }
235.3603 + delete_tuple(mpl, tuple);
235.3604 + }
235.3605 + break;
235.3606 +#endif
235.3607 + case O_IRAND224:
235.3608 + /* pseudo-random in [0, 2^24-1] */
235.3609 + value = fp_irand224(mpl);
235.3610 + break;
235.3611 + case O_UNIFORM01:
235.3612 + /* pseudo-random in [0, 1) */
235.3613 + value = fp_uniform01(mpl);
235.3614 + break;
235.3615 + case O_NORMAL01:
235.3616 + /* gaussian random, mu = 0, sigma = 1 */
235.3617 + value = fp_normal01(mpl);
235.3618 + break;
235.3619 + case O_GMTIME:
235.3620 + /* current calendar time */
235.3621 + value = fn_gmtime(mpl);
235.3622 + break;
235.3623 + case O_CVTNUM:
235.3624 + /* conversion to numeric */
235.3625 + { SYMBOL *sym;
235.3626 + sym = eval_symbolic(mpl, code->arg.arg.x);
235.3627 +#if 0 /* 23/XI-2008 */
235.3628 + if (sym->str != NULL)
235.3629 + error(mpl, "cannot convert %s to floating-point numbe"
235.3630 + "r", format_symbol(mpl, sym));
235.3631 + value = sym->num;
235.3632 +#else
235.3633 + if (sym->str == NULL)
235.3634 + value = sym->num;
235.3635 + else
235.3636 + { if (str2num(sym->str, &value))
235.3637 + error(mpl, "cannot convert %s to floating-point nu"
235.3638 + "mber", format_symbol(mpl, sym));
235.3639 + }
235.3640 +#endif
235.3641 + delete_symbol(mpl, sym);
235.3642 + }
235.3643 + break;
235.3644 + case O_PLUS:
235.3645 + /* unary plus */
235.3646 + value = + eval_numeric(mpl, code->arg.arg.x);
235.3647 + break;
235.3648 + case O_MINUS:
235.3649 + /* unary minus */
235.3650 + value = - eval_numeric(mpl, code->arg.arg.x);
235.3651 + break;
235.3652 + case O_ABS:
235.3653 + /* absolute value */
235.3654 + value = fabs(eval_numeric(mpl, code->arg.arg.x));
235.3655 + break;
235.3656 + case O_CEIL:
235.3657 + /* round upward ("ceiling of x") */
235.3658 + value = ceil(eval_numeric(mpl, code->arg.arg.x));
235.3659 + break;
235.3660 + case O_FLOOR:
235.3661 + /* round downward ("floor of x") */
235.3662 + value = floor(eval_numeric(mpl, code->arg.arg.x));
235.3663 + break;
235.3664 + case O_EXP:
235.3665 + /* base-e exponential */
235.3666 + value = fp_exp(mpl, eval_numeric(mpl, code->arg.arg.x));
235.3667 + break;
235.3668 + case O_LOG:
235.3669 + /* natural logarithm */
235.3670 + value = fp_log(mpl, eval_numeric(mpl, code->arg.arg.x));
235.3671 + break;
235.3672 + case O_LOG10:
235.3673 + /* common (decimal) logarithm */
235.3674 + value = fp_log10(mpl, eval_numeric(mpl, code->arg.arg.x));
235.3675 + break;
235.3676 + case O_SQRT:
235.3677 + /* square root */
235.3678 + value = fp_sqrt(mpl, eval_numeric(mpl, code->arg.arg.x));
235.3679 + break;
235.3680 + case O_SIN:
235.3681 + /* trigonometric sine */
235.3682 + value = fp_sin(mpl, eval_numeric(mpl, code->arg.arg.x));
235.3683 + break;
235.3684 + case O_COS:
235.3685 + /* trigonometric cosine */
235.3686 + value = fp_cos(mpl, eval_numeric(mpl, code->arg.arg.x));
235.3687 + break;
235.3688 + case O_ATAN:
235.3689 + /* trigonometric arctangent (one argument) */
235.3690 + value = fp_atan(mpl, eval_numeric(mpl, code->arg.arg.x));
235.3691 + break;
235.3692 + case O_ATAN2:
235.3693 + /* trigonometric arctangent (two arguments) */
235.3694 + value = fp_atan2(mpl,
235.3695 + eval_numeric(mpl, code->arg.arg.x),
235.3696 + eval_numeric(mpl, code->arg.arg.y));
235.3697 + break;
235.3698 + case O_ROUND:
235.3699 + /* round to nearest integer */
235.3700 + value = fp_round(mpl,
235.3701 + eval_numeric(mpl, code->arg.arg.x), 0.0);
235.3702 + break;
235.3703 + case O_ROUND2:
235.3704 + /* round to n fractional digits */
235.3705 + value = fp_round(mpl,
235.3706 + eval_numeric(mpl, code->arg.arg.x),
235.3707 + eval_numeric(mpl, code->arg.arg.y));
235.3708 + break;
235.3709 + case O_TRUNC:
235.3710 + /* truncate to nearest integer */
235.3711 + value = fp_trunc(mpl,
235.3712 + eval_numeric(mpl, code->arg.arg.x), 0.0);
235.3713 + break;
235.3714 + case O_TRUNC2:
235.3715 + /* truncate to n fractional digits */
235.3716 + value = fp_trunc(mpl,
235.3717 + eval_numeric(mpl, code->arg.arg.x),
235.3718 + eval_numeric(mpl, code->arg.arg.y));
235.3719 + break;
235.3720 + case O_ADD:
235.3721 + /* addition */
235.3722 + value = fp_add(mpl,
235.3723 + eval_numeric(mpl, code->arg.arg.x),
235.3724 + eval_numeric(mpl, code->arg.arg.y));
235.3725 + break;
235.3726 + case O_SUB:
235.3727 + /* subtraction */
235.3728 + value = fp_sub(mpl,
235.3729 + eval_numeric(mpl, code->arg.arg.x),
235.3730 + eval_numeric(mpl, code->arg.arg.y));
235.3731 + break;
235.3732 + case O_LESS:
235.3733 + /* non-negative subtraction */
235.3734 + value = fp_less(mpl,
235.3735 + eval_numeric(mpl, code->arg.arg.x),
235.3736 + eval_numeric(mpl, code->arg.arg.y));
235.3737 + break;
235.3738 + case O_MUL:
235.3739 + /* multiplication */
235.3740 + value = fp_mul(mpl,
235.3741 + eval_numeric(mpl, code->arg.arg.x),
235.3742 + eval_numeric(mpl, code->arg.arg.y));
235.3743 + break;
235.3744 + case O_DIV:
235.3745 + /* division */
235.3746 + value = fp_div(mpl,
235.3747 + eval_numeric(mpl, code->arg.arg.x),
235.3748 + eval_numeric(mpl, code->arg.arg.y));
235.3749 + break;
235.3750 + case O_IDIV:
235.3751 + /* quotient of exact division */
235.3752 + value = fp_idiv(mpl,
235.3753 + eval_numeric(mpl, code->arg.arg.x),
235.3754 + eval_numeric(mpl, code->arg.arg.y));
235.3755 + break;
235.3756 + case O_MOD:
235.3757 + /* remainder of exact division */
235.3758 + value = fp_mod(mpl,
235.3759 + eval_numeric(mpl, code->arg.arg.x),
235.3760 + eval_numeric(mpl, code->arg.arg.y));
235.3761 + break;
235.3762 + case O_POWER:
235.3763 + /* exponentiation (raise to power) */
235.3764 + value = fp_power(mpl,
235.3765 + eval_numeric(mpl, code->arg.arg.x),
235.3766 + eval_numeric(mpl, code->arg.arg.y));
235.3767 + break;
235.3768 + case O_UNIFORM:
235.3769 + /* pseudo-random in [a, b) */
235.3770 + value = fp_uniform(mpl,
235.3771 + eval_numeric(mpl, code->arg.arg.x),
235.3772 + eval_numeric(mpl, code->arg.arg.y));
235.3773 + break;
235.3774 + case O_NORMAL:
235.3775 + /* gaussian random, given mu and sigma */
235.3776 + value = fp_normal(mpl,
235.3777 + eval_numeric(mpl, code->arg.arg.x),
235.3778 + eval_numeric(mpl, code->arg.arg.y));
235.3779 + break;
235.3780 + case O_CARD:
235.3781 + { ELEMSET *set;
235.3782 + set = eval_elemset(mpl, code->arg.arg.x);
235.3783 + value = set->size;
235.3784 + delete_array(mpl, set);
235.3785 + }
235.3786 + break;
235.3787 + case O_LENGTH:
235.3788 + { SYMBOL *sym;
235.3789 + char str[MAX_LENGTH+1];
235.3790 + sym = eval_symbolic(mpl, code->arg.arg.x);
235.3791 + if (sym->str == NULL)
235.3792 + sprintf(str, "%.*g", DBL_DIG, sym->num);
235.3793 + else
235.3794 + fetch_string(mpl, sym->str, str);
235.3795 + delete_symbol(mpl, sym);
235.3796 + value = strlen(str);
235.3797 + }
235.3798 + break;
235.3799 + case O_STR2TIME:
235.3800 + { SYMBOL *sym;
235.3801 + char str[MAX_LENGTH+1], fmt[MAX_LENGTH+1];
235.3802 + sym = eval_symbolic(mpl, code->arg.arg.x);
235.3803 + if (sym->str == NULL)
235.3804 + sprintf(str, "%.*g", DBL_DIG, sym->num);
235.3805 + else
235.3806 + fetch_string(mpl, sym->str, str);
235.3807 + delete_symbol(mpl, sym);
235.3808 + sym = eval_symbolic(mpl, code->arg.arg.y);
235.3809 + if (sym->str == NULL)
235.3810 + sprintf(fmt, "%.*g", DBL_DIG, sym->num);
235.3811 + else
235.3812 + fetch_string(mpl, sym->str, fmt);
235.3813 + delete_symbol(mpl, sym);
235.3814 + value = fn_str2time(mpl, str, fmt);
235.3815 + }
235.3816 + break;
235.3817 + case O_FORK:
235.3818 + /* if-then-else */
235.3819 + if (eval_logical(mpl, code->arg.arg.x))
235.3820 + value = eval_numeric(mpl, code->arg.arg.y);
235.3821 + else if (code->arg.arg.z == NULL)
235.3822 + value = 0.0;
235.3823 + else
235.3824 + value = eval_numeric(mpl, code->arg.arg.z);
235.3825 + break;
235.3826 + case O_MIN:
235.3827 + /* minimal value (n-ary) */
235.3828 + { ARG_LIST *e;
235.3829 + double temp;
235.3830 + value = +DBL_MAX;
235.3831 + for (e = code->arg.list; e != NULL; e = e->next)
235.3832 + { temp = eval_numeric(mpl, e->x);
235.3833 + if (value > temp) value = temp;
235.3834 + }
235.3835 + }
235.3836 + break;
235.3837 + case O_MAX:
235.3838 + /* maximal value (n-ary) */
235.3839 + { ARG_LIST *e;
235.3840 + double temp;
235.3841 + value = -DBL_MAX;
235.3842 + for (e = code->arg.list; e != NULL; e = e->next)
235.3843 + { temp = eval_numeric(mpl, e->x);
235.3844 + if (value < temp) value = temp;
235.3845 + }
235.3846 + }
235.3847 + break;
235.3848 + case O_SUM:
235.3849 + /* summation over domain */
235.3850 + { struct iter_num_info _info, *info = &_info;
235.3851 + info->code = code;
235.3852 + info->value = 0.0;
235.3853 + loop_within_domain(mpl, code->arg.loop.domain, info,
235.3854 + iter_num_func);
235.3855 + value = info->value;
235.3856 + }
235.3857 + break;
235.3858 + case O_PROD:
235.3859 + /* multiplication over domain */
235.3860 + { struct iter_num_info _info, *info = &_info;
235.3861 + info->code = code;
235.3862 + info->value = 1.0;
235.3863 + loop_within_domain(mpl, code->arg.loop.domain, info,
235.3864 + iter_num_func);
235.3865 + value = info->value;
235.3866 + }
235.3867 + break;
235.3868 + case O_MINIMUM:
235.3869 + /* minimum over domain */
235.3870 + { struct iter_num_info _info, *info = &_info;
235.3871 + info->code = code;
235.3872 + info->value = +DBL_MAX;
235.3873 + loop_within_domain(mpl, code->arg.loop.domain, info,
235.3874 + iter_num_func);
235.3875 + if (info->value == +DBL_MAX)
235.3876 + error(mpl, "min{} over empty set; result undefined");
235.3877 + value = info->value;
235.3878 + }
235.3879 + break;
235.3880 + case O_MAXIMUM:
235.3881 + /* maximum over domain */
235.3882 + { struct iter_num_info _info, *info = &_info;
235.3883 + info->code = code;
235.3884 + info->value = -DBL_MAX;
235.3885 + loop_within_domain(mpl, code->arg.loop.domain, info,
235.3886 + iter_num_func);
235.3887 + if (info->value == -DBL_MAX)
235.3888 + error(mpl, "max{} over empty set; result undefined");
235.3889 + value = info->value;
235.3890 + }
235.3891 + break;
235.3892 + default:
235.3893 + xassert(code != code);
235.3894 + }
235.3895 + /* save resultant value */
235.3896 + xassert(!code->valid);
235.3897 + code->valid = 1;
235.3898 + code->value.num = value;
235.3899 +done: return value;
235.3900 +}
235.3901 +
235.3902 +/*----------------------------------------------------------------------
235.3903 +-- eval_symbolic - evaluate pseudo-code to determine symbolic value.
235.3904 +--
235.3905 +-- This routine evaluates specified pseudo-code to determine resultant
235.3906 +-- symbolic value, which is returned on exit. */
235.3907 +
235.3908 +SYMBOL *eval_symbolic(MPL *mpl, CODE *code)
235.3909 +{ SYMBOL *value;
235.3910 + xassert(code != NULL);
235.3911 + xassert(code->type == A_SYMBOLIC);
235.3912 + xassert(code->dim == 0);
235.3913 + /* if the operation has a side effect, invalidate and delete the
235.3914 + resultant value */
235.3915 + if (code->vflag && code->valid)
235.3916 + { code->valid = 0;
235.3917 + delete_value(mpl, code->type, &code->value);
235.3918 + }
235.3919 + /* if resultant value is valid, no evaluation is needed */
235.3920 + if (code->valid)
235.3921 + { value = copy_symbol(mpl, code->value.sym);
235.3922 + goto done;
235.3923 + }
235.3924 + /* evaluate pseudo-code recursively */
235.3925 + switch (code->op)
235.3926 + { case O_STRING:
235.3927 + /* take character string */
235.3928 + value = create_symbol_str(mpl, create_string(mpl,
235.3929 + code->arg.str));
235.3930 + break;
235.3931 + case O_INDEX:
235.3932 + /* take dummy index */
235.3933 + xassert(code->arg.index.slot->value != NULL);
235.3934 + value = copy_symbol(mpl, code->arg.index.slot->value);
235.3935 + break;
235.3936 + case O_MEMSYM:
235.3937 + /* take member of symbolic parameter */
235.3938 + { TUPLE *tuple;
235.3939 + ARG_LIST *e;
235.3940 + tuple = create_tuple(mpl);
235.3941 + for (e = code->arg.par.list; e != NULL; e = e->next)
235.3942 + tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
235.3943 + e->x));
235.3944 + value = eval_member_sym(mpl, code->arg.par.par, tuple);
235.3945 + delete_tuple(mpl, tuple);
235.3946 + }
235.3947 + break;
235.3948 + case O_CVTSYM:
235.3949 + /* conversion to symbolic */
235.3950 + value = create_symbol_num(mpl, eval_numeric(mpl,
235.3951 + code->arg.arg.x));
235.3952 + break;
235.3953 + case O_CONCAT:
235.3954 + /* concatenation */
235.3955 + value = concat_symbols(mpl,
235.3956 + eval_symbolic(mpl, code->arg.arg.x),
235.3957 + eval_symbolic(mpl, code->arg.arg.y));
235.3958 + break;
235.3959 + case O_FORK:
235.3960 + /* if-then-else */
235.3961 + if (eval_logical(mpl, code->arg.arg.x))
235.3962 + value = eval_symbolic(mpl, code->arg.arg.y);
235.3963 + else if (code->arg.arg.z == NULL)
235.3964 + value = create_symbol_num(mpl, 0.0);
235.3965 + else
235.3966 + value = eval_symbolic(mpl, code->arg.arg.z);
235.3967 + break;
235.3968 + case O_SUBSTR:
235.3969 + case O_SUBSTR3:
235.3970 + { double pos, len;
235.3971 + char str[MAX_LENGTH+1];
235.3972 + value = eval_symbolic(mpl, code->arg.arg.x);
235.3973 + if (value->str == NULL)
235.3974 + sprintf(str, "%.*g", DBL_DIG, value->num);
235.3975 + else
235.3976 + fetch_string(mpl, value->str, str);
235.3977 + delete_symbol(mpl, value);
235.3978 + if (code->op == O_SUBSTR)
235.3979 + { pos = eval_numeric(mpl, code->arg.arg.y);
235.3980 + if (pos != floor(pos))
235.3981 + error(mpl, "substr('...', %.*g); non-integer secon"
235.3982 + "d argument", DBL_DIG, pos);
235.3983 + if (pos < 1 || pos > strlen(str) + 1)
235.3984 + error(mpl, "substr('...', %.*g); substring out of "
235.3985 + "range", DBL_DIG, pos);
235.3986 + }
235.3987 + else
235.3988 + { pos = eval_numeric(mpl, code->arg.arg.y);
235.3989 + len = eval_numeric(mpl, code->arg.arg.z);
235.3990 + if (pos != floor(pos) || len != floor(len))
235.3991 + error(mpl, "substr('...', %.*g, %.*g); non-integer"
235.3992 + " second and/or third argument", DBL_DIG, pos,
235.3993 + DBL_DIG, len);
235.3994 + if (pos < 1 || len < 0 || pos + len > strlen(str) + 1)
235.3995 + error(mpl, "substr('...', %.*g, %.*g); substring o"
235.3996 + "ut of range", DBL_DIG, pos, DBL_DIG, len);
235.3997 + str[(int)pos + (int)len - 1] = '\0';
235.3998 + }
235.3999 + value = create_symbol_str(mpl, create_string(mpl, str +
235.4000 + (int)pos - 1));
235.4001 + }
235.4002 + break;
235.4003 + case O_TIME2STR:
235.4004 + { double num;
235.4005 + SYMBOL *sym;
235.4006 + char str[MAX_LENGTH+1], fmt[MAX_LENGTH+1];
235.4007 + num = eval_numeric(mpl, code->arg.arg.x);
235.4008 + sym = eval_symbolic(mpl, code->arg.arg.y);
235.4009 + if (sym->str == NULL)
235.4010 + sprintf(fmt, "%.*g", DBL_DIG, sym->num);
235.4011 + else
235.4012 + fetch_string(mpl, sym->str, fmt);
235.4013 + delete_symbol(mpl, sym);
235.4014 + fn_time2str(mpl, str, num, fmt);
235.4015 + value = create_symbol_str(mpl, create_string(mpl, str));
235.4016 + }
235.4017 + break;
235.4018 + default:
235.4019 + xassert(code != code);
235.4020 + }
235.4021 + /* save resultant value */
235.4022 + xassert(!code->valid);
235.4023 + code->valid = 1;
235.4024 + code->value.sym = copy_symbol(mpl, value);
235.4025 +done: return value;
235.4026 +}
235.4027 +
235.4028 +/*----------------------------------------------------------------------
235.4029 +-- eval_logical - evaluate pseudo-code to determine logical value.
235.4030 +--
235.4031 +-- This routine evaluates specified pseudo-code to determine resultant
235.4032 +-- logical value, which is returned on exit. */
235.4033 +
235.4034 +struct iter_log_info
235.4035 +{ /* working info used by the routine iter_log_func */
235.4036 + CODE *code;
235.4037 + /* pseudo-code for iterated operation to be performed */
235.4038 + int value;
235.4039 + /* resultant value */
235.4040 +};
235.4041 +
235.4042 +static int iter_log_func(MPL *mpl, void *_info)
235.4043 +{ /* this is auxiliary routine used to perform iterated operation
235.4044 + on logical "integrand" within domain scope */
235.4045 + struct iter_log_info *info = _info;
235.4046 + int ret = 0;
235.4047 + switch (info->code->op)
235.4048 + { case O_FORALL:
235.4049 + /* conjunction over domain */
235.4050 + info->value &= eval_logical(mpl, info->code->arg.loop.x);
235.4051 + if (!info->value) ret = 1;
235.4052 + break;
235.4053 + case O_EXISTS:
235.4054 + /* disjunction over domain */
235.4055 + info->value |= eval_logical(mpl, info->code->arg.loop.x);
235.4056 + if (info->value) ret = 1;
235.4057 + break;
235.4058 + default:
235.4059 + xassert(info != info);
235.4060 + }
235.4061 + return ret;
235.4062 +}
235.4063 +
235.4064 +int eval_logical(MPL *mpl, CODE *code)
235.4065 +{ int value;
235.4066 + xassert(code->type == A_LOGICAL);
235.4067 + xassert(code->dim == 0);
235.4068 + /* if the operation has a side effect, invalidate and delete the
235.4069 + resultant value */
235.4070 + if (code->vflag && code->valid)
235.4071 + { code->valid = 0;
235.4072 + delete_value(mpl, code->type, &code->value);
235.4073 + }
235.4074 + /* if resultant value is valid, no evaluation is needed */
235.4075 + if (code->valid)
235.4076 + { value = code->value.bit;
235.4077 + goto done;
235.4078 + }
235.4079 + /* evaluate pseudo-code recursively */
235.4080 + switch (code->op)
235.4081 + { case O_CVTLOG:
235.4082 + /* conversion to logical */
235.4083 + value = (eval_numeric(mpl, code->arg.arg.x) != 0.0);
235.4084 + break;
235.4085 + case O_NOT:
235.4086 + /* negation (logical "not") */
235.4087 + value = !eval_logical(mpl, code->arg.arg.x);
235.4088 + break;
235.4089 + case O_LT:
235.4090 + /* comparison on 'less than' */
235.4091 +#if 0 /* 02/VIII-2008 */
235.4092 + value = (eval_numeric(mpl, code->arg.arg.x) <
235.4093 + eval_numeric(mpl, code->arg.arg.y));
235.4094 +#else
235.4095 + xassert(code->arg.arg.x != NULL);
235.4096 + if (code->arg.arg.x->type == A_NUMERIC)
235.4097 + value = (eval_numeric(mpl, code->arg.arg.x) <
235.4098 + eval_numeric(mpl, code->arg.arg.y));
235.4099 + else
235.4100 + { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
235.4101 + SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
235.4102 + value = (compare_symbols(mpl, sym1, sym2) < 0);
235.4103 + delete_symbol(mpl, sym1);
235.4104 + delete_symbol(mpl, sym2);
235.4105 + }
235.4106 +#endif
235.4107 + break;
235.4108 + case O_LE:
235.4109 + /* comparison on 'not greater than' */
235.4110 +#if 0 /* 02/VIII-2008 */
235.4111 + value = (eval_numeric(mpl, code->arg.arg.x) <=
235.4112 + eval_numeric(mpl, code->arg.arg.y));
235.4113 +#else
235.4114 + xassert(code->arg.arg.x != NULL);
235.4115 + if (code->arg.arg.x->type == A_NUMERIC)
235.4116 + value = (eval_numeric(mpl, code->arg.arg.x) <=
235.4117 + eval_numeric(mpl, code->arg.arg.y));
235.4118 + else
235.4119 + { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
235.4120 + SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
235.4121 + value = (compare_symbols(mpl, sym1, sym2) <= 0);
235.4122 + delete_symbol(mpl, sym1);
235.4123 + delete_symbol(mpl, sym2);
235.4124 + }
235.4125 +#endif
235.4126 + break;
235.4127 + case O_EQ:
235.4128 + /* comparison on 'equal to' */
235.4129 + xassert(code->arg.arg.x != NULL);
235.4130 + if (code->arg.arg.x->type == A_NUMERIC)
235.4131 + value = (eval_numeric(mpl, code->arg.arg.x) ==
235.4132 + eval_numeric(mpl, code->arg.arg.y));
235.4133 + else
235.4134 + { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
235.4135 + SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
235.4136 + value = (compare_symbols(mpl, sym1, sym2) == 0);
235.4137 + delete_symbol(mpl, sym1);
235.4138 + delete_symbol(mpl, sym2);
235.4139 + }
235.4140 + break;
235.4141 + case O_GE:
235.4142 + /* comparison on 'not less than' */
235.4143 +#if 0 /* 02/VIII-2008 */
235.4144 + value = (eval_numeric(mpl, code->arg.arg.x) >=
235.4145 + eval_numeric(mpl, code->arg.arg.y));
235.4146 +#else
235.4147 + xassert(code->arg.arg.x != NULL);
235.4148 + if (code->arg.arg.x->type == A_NUMERIC)
235.4149 + value = (eval_numeric(mpl, code->arg.arg.x) >=
235.4150 + eval_numeric(mpl, code->arg.arg.y));
235.4151 + else
235.4152 + { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
235.4153 + SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
235.4154 + value = (compare_symbols(mpl, sym1, sym2) >= 0);
235.4155 + delete_symbol(mpl, sym1);
235.4156 + delete_symbol(mpl, sym2);
235.4157 + }
235.4158 +#endif
235.4159 + break;
235.4160 + case O_GT:
235.4161 + /* comparison on 'greater than' */
235.4162 +#if 0 /* 02/VIII-2008 */
235.4163 + value = (eval_numeric(mpl, code->arg.arg.x) >
235.4164 + eval_numeric(mpl, code->arg.arg.y));
235.4165 +#else
235.4166 + xassert(code->arg.arg.x != NULL);
235.4167 + if (code->arg.arg.x->type == A_NUMERIC)
235.4168 + value = (eval_numeric(mpl, code->arg.arg.x) >
235.4169 + eval_numeric(mpl, code->arg.arg.y));
235.4170 + else
235.4171 + { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
235.4172 + SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
235.4173 + value = (compare_symbols(mpl, sym1, sym2) > 0);
235.4174 + delete_symbol(mpl, sym1);
235.4175 + delete_symbol(mpl, sym2);
235.4176 + }
235.4177 +#endif
235.4178 + break;
235.4179 + case O_NE:
235.4180 + /* comparison on 'not equal to' */
235.4181 + xassert(code->arg.arg.x != NULL);
235.4182 + if (code->arg.arg.x->type == A_NUMERIC)
235.4183 + value = (eval_numeric(mpl, code->arg.arg.x) !=
235.4184 + eval_numeric(mpl, code->arg.arg.y));
235.4185 + else
235.4186 + { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
235.4187 + SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
235.4188 + value = (compare_symbols(mpl, sym1, sym2) != 0);
235.4189 + delete_symbol(mpl, sym1);
235.4190 + delete_symbol(mpl, sym2);
235.4191 + }
235.4192 + break;
235.4193 + case O_AND:
235.4194 + /* conjunction (logical "and") */
235.4195 + value = eval_logical(mpl, code->arg.arg.x) &&
235.4196 + eval_logical(mpl, code->arg.arg.y);
235.4197 + break;
235.4198 + case O_OR:
235.4199 + /* disjunction (logical "or") */
235.4200 + value = eval_logical(mpl, code->arg.arg.x) ||
235.4201 + eval_logical(mpl, code->arg.arg.y);
235.4202 + break;
235.4203 + case O_IN:
235.4204 + /* test on 'x in Y' */
235.4205 + { TUPLE *tuple;
235.4206 + tuple = eval_tuple(mpl, code->arg.arg.x);
235.4207 + value = is_member(mpl, code->arg.arg.y, tuple);
235.4208 + delete_tuple(mpl, tuple);
235.4209 + }
235.4210 + break;
235.4211 + case O_NOTIN:
235.4212 + /* test on 'x not in Y' */
235.4213 + { TUPLE *tuple;
235.4214 + tuple = eval_tuple(mpl, code->arg.arg.x);
235.4215 + value = !is_member(mpl, code->arg.arg.y, tuple);
235.4216 + delete_tuple(mpl, tuple);
235.4217 + }
235.4218 + break;
235.4219 + case O_WITHIN:
235.4220 + /* test on 'X within Y' */
235.4221 + { ELEMSET *set;
235.4222 + MEMBER *memb;
235.4223 + set = eval_elemset(mpl, code->arg.arg.x);
235.4224 + value = 1;
235.4225 + for (memb = set->head; memb != NULL; memb = memb->next)
235.4226 + { if (!is_member(mpl, code->arg.arg.y, memb->tuple))
235.4227 + { value = 0;
235.4228 + break;
235.4229 + }
235.4230 + }
235.4231 + delete_elemset(mpl, set);
235.4232 + }
235.4233 + break;
235.4234 + case O_NOTWITHIN:
235.4235 + /* test on 'X not within Y' */
235.4236 + { ELEMSET *set;
235.4237 + MEMBER *memb;
235.4238 + set = eval_elemset(mpl, code->arg.arg.x);
235.4239 + value = 1;
235.4240 + for (memb = set->head; memb != NULL; memb = memb->next)
235.4241 + { if (is_member(mpl, code->arg.arg.y, memb->tuple))
235.4242 + { value = 0;
235.4243 + break;
235.4244 + }
235.4245 + }
235.4246 + delete_elemset(mpl, set);
235.4247 + }
235.4248 + break;
235.4249 + case O_FORALL:
235.4250 + /* conjunction (A-quantification) */
235.4251 + { struct iter_log_info _info, *info = &_info;
235.4252 + info->code = code;
235.4253 + info->value = 1;
235.4254 + loop_within_domain(mpl, code->arg.loop.domain, info,
235.4255 + iter_log_func);
235.4256 + value = info->value;
235.4257 + }
235.4258 + break;
235.4259 + case O_EXISTS:
235.4260 + /* disjunction (E-quantification) */
235.4261 + { struct iter_log_info _info, *info = &_info;
235.4262 + info->code = code;
235.4263 + info->value = 0;
235.4264 + loop_within_domain(mpl, code->arg.loop.domain, info,
235.4265 + iter_log_func);
235.4266 + value = info->value;
235.4267 + }
235.4268 + break;
235.4269 + default:
235.4270 + xassert(code != code);
235.4271 + }
235.4272 + /* save resultant value */
235.4273 + xassert(!code->valid);
235.4274 + code->valid = 1;
235.4275 + code->value.bit = value;
235.4276 +done: return value;
235.4277 +}
235.4278 +
235.4279 +/*----------------------------------------------------------------------
235.4280 +-- eval_tuple - evaluate pseudo-code to construct n-tuple.
235.4281 +--
235.4282 +-- This routine evaluates specified pseudo-code to construct resultant
235.4283 +-- n-tuple, which is returned on exit. */
235.4284 +
235.4285 +TUPLE *eval_tuple(MPL *mpl, CODE *code)
235.4286 +{ TUPLE *value;
235.4287 + xassert(code != NULL);
235.4288 + xassert(code->type == A_TUPLE);
235.4289 + xassert(code->dim > 0);
235.4290 + /* if the operation has a side effect, invalidate and delete the
235.4291 + resultant value */
235.4292 + if (code->vflag && code->valid)
235.4293 + { code->valid = 0;
235.4294 + delete_value(mpl, code->type, &code->value);
235.4295 + }
235.4296 + /* if resultant value is valid, no evaluation is needed */
235.4297 + if (code->valid)
235.4298 + { value = copy_tuple(mpl, code->value.tuple);
235.4299 + goto done;
235.4300 + }
235.4301 + /* evaluate pseudo-code recursively */
235.4302 + switch (code->op)
235.4303 + { case O_TUPLE:
235.4304 + /* make n-tuple */
235.4305 + { ARG_LIST *e;
235.4306 + value = create_tuple(mpl);
235.4307 + for (e = code->arg.list; e != NULL; e = e->next)
235.4308 + value = expand_tuple(mpl, value, eval_symbolic(mpl,
235.4309 + e->x));
235.4310 + }
235.4311 + break;
235.4312 + case O_CVTTUP:
235.4313 + /* convert to 1-tuple */
235.4314 + value = expand_tuple(mpl, create_tuple(mpl),
235.4315 + eval_symbolic(mpl, code->arg.arg.x));
235.4316 + break;
235.4317 + default:
235.4318 + xassert(code != code);
235.4319 + }
235.4320 + /* save resultant value */
235.4321 + xassert(!code->valid);
235.4322 + code->valid = 1;
235.4323 + code->value.tuple = copy_tuple(mpl, value);
235.4324 +done: return value;
235.4325 +}
235.4326 +
235.4327 +/*----------------------------------------------------------------------
235.4328 +-- eval_elemset - evaluate pseudo-code to construct elemental set.
235.4329 +--
235.4330 +-- This routine evaluates specified pseudo-code to construct resultant
235.4331 +-- elemental set, which is returned on exit. */
235.4332 +
235.4333 +struct iter_set_info
235.4334 +{ /* working info used by the routine iter_set_func */
235.4335 + CODE *code;
235.4336 + /* pseudo-code for iterated operation to be performed */
235.4337 + ELEMSET *value;
235.4338 + /* resultant value */
235.4339 +};
235.4340 +
235.4341 +static int iter_set_func(MPL *mpl, void *_info)
235.4342 +{ /* this is auxiliary routine used to perform iterated operation
235.4343 + on n-tuple "integrand" within domain scope */
235.4344 + struct iter_set_info *info = _info;
235.4345 + TUPLE *tuple;
235.4346 + switch (info->code->op)
235.4347 + { case O_SETOF:
235.4348 + /* compute next n-tuple and add it to the set; in this case
235.4349 + duplicate n-tuples are silently ignored */
235.4350 + tuple = eval_tuple(mpl, info->code->arg.loop.x);
235.4351 + if (find_tuple(mpl, info->value, tuple) == NULL)
235.4352 + add_tuple(mpl, info->value, tuple);
235.4353 + else
235.4354 + delete_tuple(mpl, tuple);
235.4355 + break;
235.4356 + case O_BUILD:
235.4357 + /* construct next n-tuple using current values assigned to
235.4358 + *free* dummy indices as its components and add it to the
235.4359 + set; in this case duplicate n-tuples cannot appear */
235.4360 + add_tuple(mpl, info->value, get_domain_tuple(mpl,
235.4361 + info->code->arg.loop.domain));
235.4362 + break;
235.4363 + default:
235.4364 + xassert(info != info);
235.4365 + }
235.4366 + return 0;
235.4367 +}
235.4368 +
235.4369 +ELEMSET *eval_elemset(MPL *mpl, CODE *code)
235.4370 +{ ELEMSET *value;
235.4371 + xassert(code != NULL);
235.4372 + xassert(code->type == A_ELEMSET);
235.4373 + xassert(code->dim > 0);
235.4374 + /* if the operation has a side effect, invalidate and delete the
235.4375 + resultant value */
235.4376 + if (code->vflag && code->valid)
235.4377 + { code->valid = 0;
235.4378 + delete_value(mpl, code->type, &code->value);
235.4379 + }
235.4380 + /* if resultant value is valid, no evaluation is needed */
235.4381 + if (code->valid)
235.4382 + { value = copy_elemset(mpl, code->value.set);
235.4383 + goto done;
235.4384 + }
235.4385 + /* evaluate pseudo-code recursively */
235.4386 + switch (code->op)
235.4387 + { case O_MEMSET:
235.4388 + /* take member of set */
235.4389 + { TUPLE *tuple;
235.4390 + ARG_LIST *e;
235.4391 + tuple = create_tuple(mpl);
235.4392 + for (e = code->arg.set.list; e != NULL; e = e->next)
235.4393 + tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
235.4394 + e->x));
235.4395 + value = copy_elemset(mpl,
235.4396 + eval_member_set(mpl, code->arg.set.set, tuple));
235.4397 + delete_tuple(mpl, tuple);
235.4398 + }
235.4399 + break;
235.4400 + case O_MAKE:
235.4401 + /* make elemental set of n-tuples */
235.4402 + { ARG_LIST *e;
235.4403 + value = create_elemset(mpl, code->dim);
235.4404 + for (e = code->arg.list; e != NULL; e = e->next)
235.4405 + check_then_add(mpl, value, eval_tuple(mpl, e->x));
235.4406 + }
235.4407 + break;
235.4408 + case O_UNION:
235.4409 + /* union of two elemental sets */
235.4410 + value = set_union(mpl,
235.4411 + eval_elemset(mpl, code->arg.arg.x),
235.4412 + eval_elemset(mpl, code->arg.arg.y));
235.4413 + break;
235.4414 + case O_DIFF:
235.4415 + /* difference between two elemental sets */
235.4416 + value = set_diff(mpl,
235.4417 + eval_elemset(mpl, code->arg.arg.x),
235.4418 + eval_elemset(mpl, code->arg.arg.y));
235.4419 + break;
235.4420 + case O_SYMDIFF:
235.4421 + /* symmetric difference between two elemental sets */
235.4422 + value = set_symdiff(mpl,
235.4423 + eval_elemset(mpl, code->arg.arg.x),
235.4424 + eval_elemset(mpl, code->arg.arg.y));
235.4425 + break;
235.4426 + case O_INTER:
235.4427 + /* intersection of two elemental sets */
235.4428 + value = set_inter(mpl,
235.4429 + eval_elemset(mpl, code->arg.arg.x),
235.4430 + eval_elemset(mpl, code->arg.arg.y));
235.4431 + break;
235.4432 + case O_CROSS:
235.4433 + /* cross (Cartesian) product of two elemental sets */
235.4434 + value = set_cross(mpl,
235.4435 + eval_elemset(mpl, code->arg.arg.x),
235.4436 + eval_elemset(mpl, code->arg.arg.y));
235.4437 + break;
235.4438 + case O_DOTS:
235.4439 + /* build "arithmetic" elemental set */
235.4440 + value = create_arelset(mpl,
235.4441 + eval_numeric(mpl, code->arg.arg.x),
235.4442 + eval_numeric(mpl, code->arg.arg.y),
235.4443 + code->arg.arg.z == NULL ? 1.0 : eval_numeric(mpl,
235.4444 + code->arg.arg.z));
235.4445 + break;
235.4446 + case O_FORK:
235.4447 + /* if-then-else */
235.4448 + if (eval_logical(mpl, code->arg.arg.x))
235.4449 + value = eval_elemset(mpl, code->arg.arg.y);
235.4450 + else
235.4451 + value = eval_elemset(mpl, code->arg.arg.z);
235.4452 + break;
235.4453 + case O_SETOF:
235.4454 + /* compute elemental set */
235.4455 + { struct iter_set_info _info, *info = &_info;
235.4456 + info->code = code;
235.4457 + info->value = create_elemset(mpl, code->dim);
235.4458 + loop_within_domain(mpl, code->arg.loop.domain, info,
235.4459 + iter_set_func);
235.4460 + value = info->value;
235.4461 + }
235.4462 + break;
235.4463 + case O_BUILD:
235.4464 + /* build elemental set identical to domain set */
235.4465 + { struct iter_set_info _info, *info = &_info;
235.4466 + info->code = code;
235.4467 + info->value = create_elemset(mpl, code->dim);
235.4468 + loop_within_domain(mpl, code->arg.loop.domain, info,
235.4469 + iter_set_func);
235.4470 + value = info->value;
235.4471 + }
235.4472 + break;
235.4473 + default:
235.4474 + xassert(code != code);
235.4475 + }
235.4476 + /* save resultant value */
235.4477 + xassert(!code->valid);
235.4478 + code->valid = 1;
235.4479 + code->value.set = copy_elemset(mpl, value);
235.4480 +done: return value;
235.4481 +}
235.4482 +
235.4483 +/*----------------------------------------------------------------------
235.4484 +-- is_member - check if n-tuple is in set specified by pseudo-code.
235.4485 +--
235.4486 +-- This routine checks if given n-tuple is a member of elemental set
235.4487 +-- specified in the form of pseudo-code (i.e. by expression).
235.4488 +--
235.4489 +-- The n-tuple may have more components that dimension of the elemental
235.4490 +-- set, in which case the extra components are ignored. */
235.4491 +
235.4492 +static void null_func(MPL *mpl, void *info)
235.4493 +{ /* this is dummy routine used to enter the domain scope */
235.4494 + xassert(mpl == mpl);
235.4495 + xassert(info == NULL);
235.4496 + return;
235.4497 +}
235.4498 +
235.4499 +int is_member(MPL *mpl, CODE *code, TUPLE *tuple)
235.4500 +{ int value;
235.4501 + xassert(code != NULL);
235.4502 + xassert(code->type == A_ELEMSET);
235.4503 + xassert(code->dim > 0);
235.4504 + xassert(tuple != NULL);
235.4505 + switch (code->op)
235.4506 + { case O_MEMSET:
235.4507 + /* check if given n-tuple is member of elemental set, which
235.4508 + is assigned to member of model set */
235.4509 + { ARG_LIST *e;
235.4510 + TUPLE *temp;
235.4511 + ELEMSET *set;
235.4512 + /* evaluate reference to elemental set */
235.4513 + temp = create_tuple(mpl);
235.4514 + for (e = code->arg.set.list; e != NULL; e = e->next)
235.4515 + temp = expand_tuple(mpl, temp, eval_symbolic(mpl,
235.4516 + e->x));
235.4517 + set = eval_member_set(mpl, code->arg.set.set, temp);
235.4518 + delete_tuple(mpl, temp);
235.4519 + /* check if the n-tuple is contained in the set array */
235.4520 + temp = build_subtuple(mpl, tuple, set->dim);
235.4521 + value = (find_tuple(mpl, set, temp) != NULL);
235.4522 + delete_tuple(mpl, temp);
235.4523 + }
235.4524 + break;
235.4525 + case O_MAKE:
235.4526 + /* check if given n-tuple is member of literal set */
235.4527 + { ARG_LIST *e;
235.4528 + TUPLE *temp, *that;
235.4529 + value = 0;
235.4530 + temp = build_subtuple(mpl, tuple, code->dim);
235.4531 + for (e = code->arg.list; e != NULL; e = e->next)
235.4532 + { that = eval_tuple(mpl, e->x);
235.4533 + value = (compare_tuples(mpl, temp, that) == 0);
235.4534 + delete_tuple(mpl, that);
235.4535 + if (value) break;
235.4536 + }
235.4537 + delete_tuple(mpl, temp);
235.4538 + }
235.4539 + break;
235.4540 + case O_UNION:
235.4541 + value = is_member(mpl, code->arg.arg.x, tuple) ||
235.4542 + is_member(mpl, code->arg.arg.y, tuple);
235.4543 + break;
235.4544 + case O_DIFF:
235.4545 + value = is_member(mpl, code->arg.arg.x, tuple) &&
235.4546 + !is_member(mpl, code->arg.arg.y, tuple);
235.4547 + break;
235.4548 + case O_SYMDIFF:
235.4549 + { int in1 = is_member(mpl, code->arg.arg.x, tuple);
235.4550 + int in2 = is_member(mpl, code->arg.arg.y, tuple);
235.4551 + value = (in1 && !in2) || (!in1 && in2);
235.4552 + }
235.4553 + break;
235.4554 + case O_INTER:
235.4555 + value = is_member(mpl, code->arg.arg.x, tuple) &&
235.4556 + is_member(mpl, code->arg.arg.y, tuple);
235.4557 + break;
235.4558 + case O_CROSS:
235.4559 + { int j;
235.4560 + value = is_member(mpl, code->arg.arg.x, tuple);
235.4561 + if (value)
235.4562 + { for (j = 1; j <= code->arg.arg.x->dim; j++)
235.4563 + { xassert(tuple != NULL);
235.4564 + tuple = tuple->next;
235.4565 + }
235.4566 + value = is_member(mpl, code->arg.arg.y, tuple);
235.4567 + }
235.4568 + }
235.4569 + break;
235.4570 + case O_DOTS:
235.4571 + /* check if given 1-tuple is member of "arithmetic" set */
235.4572 + { int j;
235.4573 + double x, t0, tf, dt;
235.4574 + xassert(code->dim == 1);
235.4575 + /* compute "parameters" of the "arithmetic" set */
235.4576 + t0 = eval_numeric(mpl, code->arg.arg.x);
235.4577 + tf = eval_numeric(mpl, code->arg.arg.y);
235.4578 + if (code->arg.arg.z == NULL)
235.4579 + dt = 1.0;
235.4580 + else
235.4581 + dt = eval_numeric(mpl, code->arg.arg.z);
235.4582 + /* make sure the parameters are correct */
235.4583 + arelset_size(mpl, t0, tf, dt);
235.4584 + /* if component of 1-tuple is symbolic, not numeric, the
235.4585 + 1-tuple cannot be member of "arithmetic" set */
235.4586 + xassert(tuple->sym != NULL);
235.4587 + if (tuple->sym->str != NULL)
235.4588 + { value = 0;
235.4589 + break;
235.4590 + }
235.4591 + /* determine numeric value of the component */
235.4592 + x = tuple->sym->num;
235.4593 + /* if the component value is out of the set range, the
235.4594 + 1-tuple is not in the set */
235.4595 + if (dt > 0.0 && !(t0 <= x && x <= tf) ||
235.4596 + dt < 0.0 && !(tf <= x && x <= t0))
235.4597 + { value = 0;
235.4598 + break;
235.4599 + }
235.4600 + /* estimate ordinal number of the 1-tuple in the set */
235.4601 + j = (int)(((x - t0) / dt) + 0.5) + 1;
235.4602 + /* perform the main check */
235.4603 + value = (arelset_member(mpl, t0, tf, dt, j) == x);
235.4604 + }
235.4605 + break;
235.4606 + case O_FORK:
235.4607 + /* check if given n-tuple is member of conditional set */
235.4608 + if (eval_logical(mpl, code->arg.arg.x))
235.4609 + value = is_member(mpl, code->arg.arg.y, tuple);
235.4610 + else
235.4611 + value = is_member(mpl, code->arg.arg.z, tuple);
235.4612 + break;
235.4613 + case O_SETOF:
235.4614 + /* check if given n-tuple is member of computed set */
235.4615 + /* it is not clear how to efficiently perform the check not
235.4616 + computing the entire elemental set :+( */
235.4617 + error(mpl, "implementation restriction; in/within setof{} n"
235.4618 + "ot allowed");
235.4619 + break;
235.4620 + case O_BUILD:
235.4621 + /* check if given n-tuple is member of domain set */
235.4622 + { TUPLE *temp;
235.4623 + temp = build_subtuple(mpl, tuple, code->dim);
235.4624 + /* try to enter the domain scope; if it is successful,
235.4625 + the n-tuple is in the domain set */
235.4626 + value = (eval_within_domain(mpl, code->arg.loop.domain,
235.4627 + temp, NULL, null_func) == 0);
235.4628 + delete_tuple(mpl, temp);
235.4629 + }
235.4630 + break;
235.4631 + default:
235.4632 + xassert(code != code);
235.4633 + }
235.4634 + return value;
235.4635 +}
235.4636 +
235.4637 +/*----------------------------------------------------------------------
235.4638 +-- eval_formula - evaluate pseudo-code to construct linear form.
235.4639 +--
235.4640 +-- This routine evaluates specified pseudo-code to construct resultant
235.4641 +-- linear form, which is returned on exit. */
235.4642 +
235.4643 +struct iter_form_info
235.4644 +{ /* working info used by the routine iter_form_func */
235.4645 + CODE *code;
235.4646 + /* pseudo-code for iterated operation to be performed */
235.4647 + FORMULA *value;
235.4648 + /* resultant value */
235.4649 + FORMULA *tail;
235.4650 + /* pointer to the last term */
235.4651 +};
235.4652 +
235.4653 +static int iter_form_func(MPL *mpl, void *_info)
235.4654 +{ /* this is auxiliary routine used to perform iterated operation
235.4655 + on linear form "integrand" within domain scope */
235.4656 + struct iter_form_info *info = _info;
235.4657 + switch (info->code->op)
235.4658 + { case O_SUM:
235.4659 + /* summation over domain */
235.4660 +#if 0
235.4661 + info->value =
235.4662 + linear_comb(mpl,
235.4663 + +1.0, info->value,
235.4664 + +1.0, eval_formula(mpl, info->code->arg.loop.x));
235.4665 +#else
235.4666 + /* the routine linear_comb needs to look through all terms
235.4667 + of both linear forms to reduce identical terms, so using
235.4668 + it here is not a good idea (for example, evaluation of
235.4669 + sum{i in 1..n} x[i] required quadratic time); the better
235.4670 + idea is to gather all terms of the integrand in one list
235.4671 + and reduce identical terms only once after all terms of
235.4672 + the resultant linear form have been evaluated */
235.4673 + { FORMULA *form, *term;
235.4674 + form = eval_formula(mpl, info->code->arg.loop.x);
235.4675 + if (info->value == NULL)
235.4676 + { xassert(info->tail == NULL);
235.4677 + info->value = form;
235.4678 + }
235.4679 + else
235.4680 + { xassert(info->tail != NULL);
235.4681 + info->tail->next = form;
235.4682 + }
235.4683 + for (term = form; term != NULL; term = term->next)
235.4684 + info->tail = term;
235.4685 + }
235.4686 +#endif
235.4687 + break;
235.4688 + default:
235.4689 + xassert(info != info);
235.4690 + }
235.4691 + return 0;
235.4692 +}
235.4693 +
235.4694 +FORMULA *eval_formula(MPL *mpl, CODE *code)
235.4695 +{ FORMULA *value;
235.4696 + xassert(code != NULL);
235.4697 + xassert(code->type == A_FORMULA);
235.4698 + xassert(code->dim == 0);
235.4699 + /* if the operation has a side effect, invalidate and delete the
235.4700 + resultant value */
235.4701 + if (code->vflag && code->valid)
235.4702 + { code->valid = 0;
235.4703 + delete_value(mpl, code->type, &code->value);
235.4704 + }
235.4705 + /* if resultant value is valid, no evaluation is needed */
235.4706 + if (code->valid)
235.4707 + { value = copy_formula(mpl, code->value.form);
235.4708 + goto done;
235.4709 + }
235.4710 + /* evaluate pseudo-code recursively */
235.4711 + switch (code->op)
235.4712 + { case O_MEMVAR:
235.4713 + /* take member of variable */
235.4714 + { TUPLE *tuple;
235.4715 + ARG_LIST *e;
235.4716 + tuple = create_tuple(mpl);
235.4717 + for (e = code->arg.var.list; e != NULL; e = e->next)
235.4718 + tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
235.4719 + e->x));
235.4720 +#if 1 /* 15/V-2010 */
235.4721 + xassert(code->arg.var.suff == DOT_NONE);
235.4722 +#endif
235.4723 + value = single_variable(mpl,
235.4724 + eval_member_var(mpl, code->arg.var.var, tuple));
235.4725 + delete_tuple(mpl, tuple);
235.4726 + }
235.4727 + break;
235.4728 + case O_CVTLFM:
235.4729 + /* convert to linear form */
235.4730 + value = constant_term(mpl, eval_numeric(mpl,
235.4731 + code->arg.arg.x));
235.4732 + break;
235.4733 + case O_PLUS:
235.4734 + /* unary plus */
235.4735 + value = linear_comb(mpl,
235.4736 + 0.0, constant_term(mpl, 0.0),
235.4737 + +1.0, eval_formula(mpl, code->arg.arg.x));
235.4738 + break;
235.4739 + case O_MINUS:
235.4740 + /* unary minus */
235.4741 + value = linear_comb(mpl,
235.4742 + 0.0, constant_term(mpl, 0.0),
235.4743 + -1.0, eval_formula(mpl, code->arg.arg.x));
235.4744 + break;
235.4745 + case O_ADD:
235.4746 + /* addition */
235.4747 + value = linear_comb(mpl,
235.4748 + +1.0, eval_formula(mpl, code->arg.arg.x),
235.4749 + +1.0, eval_formula(mpl, code->arg.arg.y));
235.4750 + break;
235.4751 + case O_SUB:
235.4752 + /* subtraction */
235.4753 + value = linear_comb(mpl,
235.4754 + +1.0, eval_formula(mpl, code->arg.arg.x),
235.4755 + -1.0, eval_formula(mpl, code->arg.arg.y));
235.4756 + break;
235.4757 + case O_MUL:
235.4758 + /* multiplication */
235.4759 + xassert(code->arg.arg.x != NULL);
235.4760 + xassert(code->arg.arg.y != NULL);
235.4761 + if (code->arg.arg.x->type == A_NUMERIC)
235.4762 + { xassert(code->arg.arg.y->type == A_FORMULA);
235.4763 + value = linear_comb(mpl,
235.4764 + eval_numeric(mpl, code->arg.arg.x),
235.4765 + eval_formula(mpl, code->arg.arg.y),
235.4766 + 0.0, constant_term(mpl, 0.0));
235.4767 + }
235.4768 + else
235.4769 + { xassert(code->arg.arg.x->type == A_FORMULA);
235.4770 + xassert(code->arg.arg.y->type == A_NUMERIC);
235.4771 + value = linear_comb(mpl,
235.4772 + eval_numeric(mpl, code->arg.arg.y),
235.4773 + eval_formula(mpl, code->arg.arg.x),
235.4774 + 0.0, constant_term(mpl, 0.0));
235.4775 + }
235.4776 + break;
235.4777 + case O_DIV:
235.4778 + /* division */
235.4779 + value = linear_comb(mpl,
235.4780 + fp_div(mpl, 1.0, eval_numeric(mpl, code->arg.arg.y)),
235.4781 + eval_formula(mpl, code->arg.arg.x),
235.4782 + 0.0, constant_term(mpl, 0.0));
235.4783 + break;
235.4784 + case O_FORK:
235.4785 + /* if-then-else */
235.4786 + if (eval_logical(mpl, code->arg.arg.x))
235.4787 + value = eval_formula(mpl, code->arg.arg.y);
235.4788 + else if (code->arg.arg.z == NULL)
235.4789 + value = constant_term(mpl, 0.0);
235.4790 + else
235.4791 + value = eval_formula(mpl, code->arg.arg.z);
235.4792 + break;
235.4793 + case O_SUM:
235.4794 + /* summation over domain */
235.4795 + { struct iter_form_info _info, *info = &_info;
235.4796 + info->code = code;
235.4797 + info->value = constant_term(mpl, 0.0);
235.4798 + info->tail = NULL;
235.4799 + loop_within_domain(mpl, code->arg.loop.domain, info,
235.4800 + iter_form_func);
235.4801 + value = reduce_terms(mpl, info->value);
235.4802 + }
235.4803 + break;
235.4804 + default:
235.4805 + xassert(code != code);
235.4806 + }
235.4807 + /* save resultant value */
235.4808 + xassert(!code->valid);
235.4809 + code->valid = 1;
235.4810 + code->value.form = copy_formula(mpl, value);
235.4811 +done: return value;
235.4812 +}
235.4813 +
235.4814 +/*----------------------------------------------------------------------
235.4815 +-- clean_code - clean pseudo-code.
235.4816 +--
235.4817 +-- This routine recursively cleans specified pseudo-code that assumes
235.4818 +-- deleting all temporary resultant values. */
235.4819 +
235.4820 +void clean_code(MPL *mpl, CODE *code)
235.4821 +{ ARG_LIST *e;
235.4822 + /* if no pseudo-code is specified, do nothing */
235.4823 + if (code == NULL) goto done;
235.4824 + /* if resultant value is valid (exists), delete it */
235.4825 + if (code->valid)
235.4826 + { code->valid = 0;
235.4827 + delete_value(mpl, code->type, &code->value);
235.4828 + }
235.4829 + /* recursively clean pseudo-code for operands */
235.4830 + switch (code->op)
235.4831 + { case O_NUMBER:
235.4832 + case O_STRING:
235.4833 + case O_INDEX:
235.4834 + break;
235.4835 + case O_MEMNUM:
235.4836 + case O_MEMSYM:
235.4837 + for (e = code->arg.par.list; e != NULL; e = e->next)
235.4838 + clean_code(mpl, e->x);
235.4839 + break;
235.4840 + case O_MEMSET:
235.4841 + for (e = code->arg.set.list; e != NULL; e = e->next)
235.4842 + clean_code(mpl, e->x);
235.4843 + break;
235.4844 + case O_MEMVAR:
235.4845 + for (e = code->arg.var.list; e != NULL; e = e->next)
235.4846 + clean_code(mpl, e->x);
235.4847 + break;
235.4848 +#if 1 /* 15/V-2010 */
235.4849 + case O_MEMCON:
235.4850 + for (e = code->arg.con.list; e != NULL; e = e->next)
235.4851 + clean_code(mpl, e->x);
235.4852 + break;
235.4853 +#endif
235.4854 + case O_TUPLE:
235.4855 + case O_MAKE:
235.4856 + for (e = code->arg.list; e != NULL; e = e->next)
235.4857 + clean_code(mpl, e->x);
235.4858 + break;
235.4859 + case O_SLICE:
235.4860 + xassert(code != code);
235.4861 + case O_IRAND224:
235.4862 + case O_UNIFORM01:
235.4863 + case O_NORMAL01:
235.4864 + case O_GMTIME:
235.4865 + break;
235.4866 + case O_CVTNUM:
235.4867 + case O_CVTSYM:
235.4868 + case O_CVTLOG:
235.4869 + case O_CVTTUP:
235.4870 + case O_CVTLFM:
235.4871 + case O_PLUS:
235.4872 + case O_MINUS:
235.4873 + case O_NOT:
235.4874 + case O_ABS:
235.4875 + case O_CEIL:
235.4876 + case O_FLOOR:
235.4877 + case O_EXP:
235.4878 + case O_LOG:
235.4879 + case O_LOG10:
235.4880 + case O_SQRT:
235.4881 + case O_SIN:
235.4882 + case O_COS:
235.4883 + case O_ATAN:
235.4884 + case O_ROUND:
235.4885 + case O_TRUNC:
235.4886 + case O_CARD:
235.4887 + case O_LENGTH:
235.4888 + /* unary operation */
235.4889 + clean_code(mpl, code->arg.arg.x);
235.4890 + break;
235.4891 + case O_ADD:
235.4892 + case O_SUB:
235.4893 + case O_LESS:
235.4894 + case O_MUL:
235.4895 + case O_DIV:
235.4896 + case O_IDIV:
235.4897 + case O_MOD:
235.4898 + case O_POWER:
235.4899 + case O_ATAN2:
235.4900 + case O_ROUND2:
235.4901 + case O_TRUNC2:
235.4902 + case O_UNIFORM:
235.4903 + case O_NORMAL:
235.4904 + case O_CONCAT:
235.4905 + case O_LT:
235.4906 + case O_LE:
235.4907 + case O_EQ:
235.4908 + case O_GE:
235.4909 + case O_GT:
235.4910 + case O_NE:
235.4911 + case O_AND:
235.4912 + case O_OR:
235.4913 + case O_UNION:
235.4914 + case O_DIFF:
235.4915 + case O_SYMDIFF:
235.4916 + case O_INTER:
235.4917 + case O_CROSS:
235.4918 + case O_IN:
235.4919 + case O_NOTIN:
235.4920 + case O_WITHIN:
235.4921 + case O_NOTWITHIN:
235.4922 + case O_SUBSTR:
235.4923 + case O_STR2TIME:
235.4924 + case O_TIME2STR:
235.4925 + /* binary operation */
235.4926 + clean_code(mpl, code->arg.arg.x);
235.4927 + clean_code(mpl, code->arg.arg.y);
235.4928 + break;
235.4929 + case O_DOTS:
235.4930 + case O_FORK:
235.4931 + case O_SUBSTR3:
235.4932 + /* ternary operation */
235.4933 + clean_code(mpl, code->arg.arg.x);
235.4934 + clean_code(mpl, code->arg.arg.y);
235.4935 + clean_code(mpl, code->arg.arg.z);
235.4936 + break;
235.4937 + case O_MIN:
235.4938 + case O_MAX:
235.4939 + /* n-ary operation */
235.4940 + for (e = code->arg.list; e != NULL; e = e->next)
235.4941 + clean_code(mpl, e->x);
235.4942 + break;
235.4943 + case O_SUM:
235.4944 + case O_PROD:
235.4945 + case O_MINIMUM:
235.4946 + case O_MAXIMUM:
235.4947 + case O_FORALL:
235.4948 + case O_EXISTS:
235.4949 + case O_SETOF:
235.4950 + case O_BUILD:
235.4951 + /* iterated operation */
235.4952 + clean_domain(mpl, code->arg.loop.domain);
235.4953 + clean_code(mpl, code->arg.loop.x);
235.4954 + break;
235.4955 + default:
235.4956 + xassert(code->op != code->op);
235.4957 + }
235.4958 +done: return;
235.4959 +}
235.4960 +
235.4961 +#if 1 /* 11/II-2008 */
235.4962 +/**********************************************************************/
235.4963 +/* * * DATA TABLES * * */
235.4964 +/**********************************************************************/
235.4965 +
235.4966 +int mpl_tab_num_args(TABDCA *dca)
235.4967 +{ /* returns the number of arguments */
235.4968 + return dca->na;
235.4969 +}
235.4970 +
235.4971 +const char *mpl_tab_get_arg(TABDCA *dca, int k)
235.4972 +{ /* returns pointer to k-th argument */
235.4973 + xassert(1 <= k && k <= dca->na);
235.4974 + return dca->arg[k];
235.4975 +}
235.4976 +
235.4977 +int mpl_tab_num_flds(TABDCA *dca)
235.4978 +{ /* returns the number of fields */
235.4979 + return dca->nf;
235.4980 +}
235.4981 +
235.4982 +const char *mpl_tab_get_name(TABDCA *dca, int k)
235.4983 +{ /* returns pointer to name of k-th field */
235.4984 + xassert(1 <= k && k <= dca->nf);
235.4985 + return dca->name[k];
235.4986 +}
235.4987 +
235.4988 +int mpl_tab_get_type(TABDCA *dca, int k)
235.4989 +{ /* returns type of k-th field */
235.4990 + xassert(1 <= k && k <= dca->nf);
235.4991 + return dca->type[k];
235.4992 +}
235.4993 +
235.4994 +double mpl_tab_get_num(TABDCA *dca, int k)
235.4995 +{ /* returns numeric value of k-th field */
235.4996 + xassert(1 <= k && k <= dca->nf);
235.4997 + xassert(dca->type[k] == 'N');
235.4998 + return dca->num[k];
235.4999 +}
235.5000 +
235.5001 +const char *mpl_tab_get_str(TABDCA *dca, int k)
235.5002 +{ /* returns pointer to string value of k-th field */
235.5003 + xassert(1 <= k && k <= dca->nf);
235.5004 + xassert(dca->type[k] == 'S');
235.5005 + xassert(dca->str[k] != NULL);
235.5006 + return dca->str[k];
235.5007 +}
235.5008 +
235.5009 +void mpl_tab_set_num(TABDCA *dca, int k, double num)
235.5010 +{ /* assign numeric value to k-th field */
235.5011 + xassert(1 <= k && k <= dca->nf);
235.5012 + xassert(dca->type[k] == '?');
235.5013 + dca->type[k] = 'N';
235.5014 + dca->num[k] = num;
235.5015 + return;
235.5016 +}
235.5017 +
235.5018 +void mpl_tab_set_str(TABDCA *dca, int k, const char *str)
235.5019 +{ /* assign string value to k-th field */
235.5020 + xassert(1 <= k && k <= dca->nf);
235.5021 + xassert(dca->type[k] == '?');
235.5022 + xassert(strlen(str) <= MAX_LENGTH);
235.5023 + xassert(dca->str[k] != NULL);
235.5024 + dca->type[k] = 'S';
235.5025 + strcpy(dca->str[k], str);
235.5026 + return;
235.5027 +}
235.5028 +
235.5029 +static int write_func(MPL *mpl, void *info)
235.5030 +{ /* this is auxiliary routine to work within domain scope */
235.5031 + TABLE *tab = info;
235.5032 + TABDCA *dca = mpl->dca;
235.5033 + TABOUT *out;
235.5034 + SYMBOL *sym;
235.5035 + int k;
235.5036 + char buf[MAX_LENGTH+1];
235.5037 + /* evaluate field values */
235.5038 + k = 0;
235.5039 + for (out = tab->u.out.list; out != NULL; out = out->next)
235.5040 + { k++;
235.5041 + switch (out->code->type)
235.5042 + { case A_NUMERIC:
235.5043 + dca->type[k] = 'N';
235.5044 + dca->num[k] = eval_numeric(mpl, out->code);
235.5045 + dca->str[k][0] = '\0';
235.5046 + break;
235.5047 + case A_SYMBOLIC:
235.5048 + sym = eval_symbolic(mpl, out->code);
235.5049 + if (sym->str == NULL)
235.5050 + { dca->type[k] = 'N';
235.5051 + dca->num[k] = sym->num;
235.5052 + dca->str[k][0] = '\0';
235.5053 + }
235.5054 + else
235.5055 + { dca->type[k] = 'S';
235.5056 + dca->num[k] = 0.0;
235.5057 + fetch_string(mpl, sym->str, buf);
235.5058 + strcpy(dca->str[k], buf);
235.5059 + }
235.5060 + delete_symbol(mpl, sym);
235.5061 + break;
235.5062 + default:
235.5063 + xassert(out != out);
235.5064 + }
235.5065 + }
235.5066 + /* write record to output table */
235.5067 + mpl_tab_drv_write(mpl);
235.5068 + return 0;
235.5069 +}
235.5070 +
235.5071 +void execute_table(MPL *mpl, TABLE *tab)
235.5072 +{ /* execute table statement */
235.5073 + TABARG *arg;
235.5074 + TABFLD *fld;
235.5075 + TABIN *in;
235.5076 + TABOUT *out;
235.5077 + TABDCA *dca;
235.5078 + SET *set;
235.5079 + int k;
235.5080 + char buf[MAX_LENGTH+1];
235.5081 + /* allocate table driver communication area */
235.5082 + xassert(mpl->dca == NULL);
235.5083 + mpl->dca = dca = xmalloc(sizeof(TABDCA));
235.5084 + dca->id = 0;
235.5085 + dca->link = NULL;
235.5086 + dca->na = 0;
235.5087 + dca->arg = NULL;
235.5088 + dca->nf = 0;
235.5089 + dca->name = NULL;
235.5090 + dca->type = NULL;
235.5091 + dca->num = NULL;
235.5092 + dca->str = NULL;
235.5093 + /* allocate arguments */
235.5094 + xassert(dca->na == 0);
235.5095 + for (arg = tab->arg; arg != NULL; arg = arg->next)
235.5096 + dca->na++;
235.5097 + dca->arg = xcalloc(1+dca->na, sizeof(char *));
235.5098 +#if 1 /* 28/IX-2008 */
235.5099 + for (k = 1; k <= dca->na; k++) dca->arg[k] = NULL;
235.5100 +#endif
235.5101 + /* evaluate argument values */
235.5102 + k = 0;
235.5103 + for (arg = tab->arg; arg != NULL; arg = arg->next)
235.5104 + { SYMBOL *sym;
235.5105 + k++;
235.5106 + xassert(arg->code->type == A_SYMBOLIC);
235.5107 + sym = eval_symbolic(mpl, arg->code);
235.5108 + if (sym->str == NULL)
235.5109 + sprintf(buf, "%.*g", DBL_DIG, sym->num);
235.5110 + else
235.5111 + fetch_string(mpl, sym->str, buf);
235.5112 + delete_symbol(mpl, sym);
235.5113 + dca->arg[k] = xmalloc(strlen(buf)+1);
235.5114 + strcpy(dca->arg[k], buf);
235.5115 + }
235.5116 + /* perform table input/output */
235.5117 + switch (tab->type)
235.5118 + { case A_INPUT: goto read_table;
235.5119 + case A_OUTPUT: goto write_table;
235.5120 + default: xassert(tab != tab);
235.5121 + }
235.5122 +read_table:
235.5123 + /* read data from input table */
235.5124 + /* add the only member to the control set and assign it empty
235.5125 + elemental set */
235.5126 + set = tab->u.in.set;
235.5127 + if (set != NULL)
235.5128 + { if (set->data)
235.5129 + error(mpl, "%s already provided with data", set->name);
235.5130 + xassert(set->array->head == NULL);
235.5131 + add_member(mpl, set->array, NULL)->value.set =
235.5132 + create_elemset(mpl, set->dimen);
235.5133 + set->data = 1;
235.5134 + }
235.5135 + /* check parameters specified in the input list */
235.5136 + for (in = tab->u.in.list; in != NULL; in = in->next)
235.5137 + { if (in->par->data)
235.5138 + error(mpl, "%s already provided with data", in->par->name);
235.5139 + in->par->data = 1;
235.5140 + }
235.5141 + /* allocate and initialize fields */
235.5142 + xassert(dca->nf == 0);
235.5143 + for (fld = tab->u.in.fld; fld != NULL; fld = fld->next)
235.5144 + dca->nf++;
235.5145 + for (in = tab->u.in.list; in != NULL; in = in->next)
235.5146 + dca->nf++;
235.5147 + dca->name = xcalloc(1+dca->nf, sizeof(char *));
235.5148 + dca->type = xcalloc(1+dca->nf, sizeof(int));
235.5149 + dca->num = xcalloc(1+dca->nf, sizeof(double));
235.5150 + dca->str = xcalloc(1+dca->nf, sizeof(char *));
235.5151 + k = 0;
235.5152 + for (fld = tab->u.in.fld; fld != NULL; fld = fld->next)
235.5153 + { k++;
235.5154 + dca->name[k] = fld->name;
235.5155 + dca->type[k] = '?';
235.5156 + dca->num[k] = 0.0;
235.5157 + dca->str[k] = xmalloc(MAX_LENGTH+1);
235.5158 + dca->str[k][0] = '\0';
235.5159 + }
235.5160 + for (in = tab->u.in.list; in != NULL; in = in->next)
235.5161 + { k++;
235.5162 + dca->name[k] = in->name;
235.5163 + dca->type[k] = '?';
235.5164 + dca->num[k] = 0.0;
235.5165 + dca->str[k] = xmalloc(MAX_LENGTH+1);
235.5166 + dca->str[k][0] = '\0';
235.5167 + }
235.5168 + /* open input table */
235.5169 + mpl_tab_drv_open(mpl, 'R');
235.5170 + /* read and process records */
235.5171 + for (;;)
235.5172 + { TUPLE *tup;
235.5173 + /* reset field types */
235.5174 + for (k = 1; k <= dca->nf; k++)
235.5175 + dca->type[k] = '?';
235.5176 + /* read next record */
235.5177 + if (mpl_tab_drv_read(mpl)) break;
235.5178 + /* all fields must be set by the driver */
235.5179 + for (k = 1; k <= dca->nf; k++)
235.5180 + { if (dca->type[k] == '?')
235.5181 + error(mpl, "field %s missing in input table",
235.5182 + dca->name[k]);
235.5183 + }
235.5184 + /* construct n-tuple */
235.5185 + tup = create_tuple(mpl);
235.5186 + k = 0;
235.5187 + for (fld = tab->u.in.fld; fld != NULL; fld = fld->next)
235.5188 + { k++;
235.5189 + xassert(k <= dca->nf);
235.5190 + switch (dca->type[k])
235.5191 + { case 'N':
235.5192 + tup = expand_tuple(mpl, tup, create_symbol_num(mpl,
235.5193 + dca->num[k]));
235.5194 + break;
235.5195 + case 'S':
235.5196 + xassert(strlen(dca->str[k]) <= MAX_LENGTH);
235.5197 + tup = expand_tuple(mpl, tup, create_symbol_str(mpl,
235.5198 + create_string(mpl, dca->str[k])));
235.5199 + break;
235.5200 + default:
235.5201 + xassert(dca != dca);
235.5202 + }
235.5203 + }
235.5204 + /* add n-tuple just read to the control set */
235.5205 + if (tab->u.in.set != NULL)
235.5206 + check_then_add(mpl, tab->u.in.set->array->head->value.set,
235.5207 + copy_tuple(mpl, tup));
235.5208 + /* assign values to the parameters in the input list */
235.5209 + for (in = tab->u.in.list; in != NULL; in = in->next)
235.5210 + { MEMBER *memb;
235.5211 + k++;
235.5212 + xassert(k <= dca->nf);
235.5213 + /* there must be no member with the same n-tuple */
235.5214 + if (find_member(mpl, in->par->array, tup) != NULL)
235.5215 + error(mpl, "%s%s already defined", in->par->name,
235.5216 + format_tuple(mpl, '[', tup));
235.5217 + /* create new parameter member with given n-tuple */
235.5218 + memb = add_member(mpl, in->par->array, copy_tuple(mpl, tup))
235.5219 + ;
235.5220 + /* assign value to the parameter member */
235.5221 + switch (in->par->type)
235.5222 + { case A_NUMERIC:
235.5223 + case A_INTEGER:
235.5224 + case A_BINARY:
235.5225 + if (dca->type[k] != 'N')
235.5226 + error(mpl, "%s requires numeric data",
235.5227 + in->par->name);
235.5228 + memb->value.num = dca->num[k];
235.5229 + break;
235.5230 + case A_SYMBOLIC:
235.5231 + switch (dca->type[k])
235.5232 + { case 'N':
235.5233 + memb->value.sym = create_symbol_num(mpl,
235.5234 + dca->num[k]);
235.5235 + break;
235.5236 + case 'S':
235.5237 + xassert(strlen(dca->str[k]) <= MAX_LENGTH);
235.5238 + memb->value.sym = create_symbol_str(mpl,
235.5239 + create_string(mpl,dca->str[k]));
235.5240 + break;
235.5241 + default:
235.5242 + xassert(dca != dca);
235.5243 + }
235.5244 + break;
235.5245 + default:
235.5246 + xassert(in != in);
235.5247 + }
235.5248 + }
235.5249 + /* n-tuple is no more needed */
235.5250 + delete_tuple(mpl, tup);
235.5251 + }
235.5252 + /* close input table */
235.5253 + mpl_tab_drv_close(mpl);
235.5254 + goto done;
235.5255 +write_table:
235.5256 + /* write data to output table */
235.5257 + /* allocate and initialize fields */
235.5258 + xassert(dca->nf == 0);
235.5259 + for (out = tab->u.out.list; out != NULL; out = out->next)
235.5260 + dca->nf++;
235.5261 + dca->name = xcalloc(1+dca->nf, sizeof(char *));
235.5262 + dca->type = xcalloc(1+dca->nf, sizeof(int));
235.5263 + dca->num = xcalloc(1+dca->nf, sizeof(double));
235.5264 + dca->str = xcalloc(1+dca->nf, sizeof(char *));
235.5265 + k = 0;
235.5266 + for (out = tab->u.out.list; out != NULL; out = out->next)
235.5267 + { k++;
235.5268 + dca->name[k] = out->name;
235.5269 + dca->type[k] = '?';
235.5270 + dca->num[k] = 0.0;
235.5271 + dca->str[k] = xmalloc(MAX_LENGTH+1);
235.5272 + dca->str[k][0] = '\0';
235.5273 + }
235.5274 + /* open output table */
235.5275 + mpl_tab_drv_open(mpl, 'W');
235.5276 + /* evaluate fields and write records */
235.5277 + loop_within_domain(mpl, tab->u.out.domain, tab, write_func);
235.5278 + /* close output table */
235.5279 + mpl_tab_drv_close(mpl);
235.5280 +done: /* free table driver communication area */
235.5281 + free_dca(mpl);
235.5282 + return;
235.5283 +}
235.5284 +
235.5285 +void free_dca(MPL *mpl)
235.5286 +{ /* free table driver communucation area */
235.5287 + TABDCA *dca = mpl->dca;
235.5288 + int k;
235.5289 + if (dca != NULL)
235.5290 + { if (dca->link != NULL)
235.5291 + mpl_tab_drv_close(mpl);
235.5292 + if (dca->arg != NULL)
235.5293 + { for (k = 1; k <= dca->na; k++)
235.5294 +#if 1 /* 28/IX-2008 */
235.5295 + if (dca->arg[k] != NULL)
235.5296 +#endif
235.5297 + xfree(dca->arg[k]);
235.5298 + xfree(dca->arg);
235.5299 + }
235.5300 + if (dca->name != NULL) xfree(dca->name);
235.5301 + if (dca->type != NULL) xfree(dca->type);
235.5302 + if (dca->num != NULL) xfree(dca->num);
235.5303 + if (dca->str != NULL)
235.5304 + { for (k = 1; k <= dca->nf; k++)
235.5305 + xfree(dca->str[k]);
235.5306 + xfree(dca->str);
235.5307 + }
235.5308 + xfree(dca), mpl->dca = NULL;
235.5309 + }
235.5310 + return;
235.5311 +}
235.5312 +
235.5313 +void clean_table(MPL *mpl, TABLE *tab)
235.5314 +{ /* clean table statement */
235.5315 + TABARG *arg;
235.5316 + TABOUT *out;
235.5317 + /* clean string list */
235.5318 + for (arg = tab->arg; arg != NULL; arg = arg->next)
235.5319 + clean_code(mpl, arg->code);
235.5320 + switch (tab->type)
235.5321 + { case A_INPUT:
235.5322 + break;
235.5323 + case A_OUTPUT:
235.5324 + /* clean subscript domain */
235.5325 + clean_domain(mpl, tab->u.out.domain);
235.5326 + /* clean output list */
235.5327 + for (out = tab->u.out.list; out != NULL; out = out->next)
235.5328 + clean_code(mpl, out->code);
235.5329 + break;
235.5330 + default:
235.5331 + xassert(tab != tab);
235.5332 + }
235.5333 + return;
235.5334 +}
235.5335 +#endif
235.5336 +
235.5337 +/**********************************************************************/
235.5338 +/* * * MODEL STATEMENTS * * */
235.5339 +/**********************************************************************/
235.5340 +
235.5341 +/*----------------------------------------------------------------------
235.5342 +-- execute_check - execute check statement.
235.5343 +--
235.5344 +-- This routine executes specified check statement. */
235.5345 +
235.5346 +static int check_func(MPL *mpl, void *info)
235.5347 +{ /* this is auxiliary routine to work within domain scope */
235.5348 + CHECK *chk = (CHECK *)info;
235.5349 + if (!eval_logical(mpl, chk->code))
235.5350 + error(mpl, "check%s failed", format_tuple(mpl, '[',
235.5351 + get_domain_tuple(mpl, chk->domain)));
235.5352 + return 0;
235.5353 +}
235.5354 +
235.5355 +void execute_check(MPL *mpl, CHECK *chk)
235.5356 +{ loop_within_domain(mpl, chk->domain, chk, check_func);
235.5357 + return;
235.5358 +}
235.5359 +
235.5360 +/*----------------------------------------------------------------------
235.5361 +-- clean_check - clean check statement.
235.5362 +--
235.5363 +-- This routine cleans specified check statement that assumes deleting
235.5364 +-- all stuff dynamically allocated on generating/postsolving phase. */
235.5365 +
235.5366 +void clean_check(MPL *mpl, CHECK *chk)
235.5367 +{ /* clean subscript domain */
235.5368 + clean_domain(mpl, chk->domain);
235.5369 + /* clean pseudo-code for computing predicate */
235.5370 + clean_code(mpl, chk->code);
235.5371 + return;
235.5372 +}
235.5373 +
235.5374 +/*----------------------------------------------------------------------
235.5375 +-- execute_display - execute display statement.
235.5376 +--
235.5377 +-- This routine executes specified display statement. */
235.5378 +
235.5379 +static void display_set(MPL *mpl, SET *set, MEMBER *memb)
235.5380 +{ /* display member of model set */
235.5381 + ELEMSET *s = memb->value.set;
235.5382 + MEMBER *m;
235.5383 + write_text(mpl, "%s%s%s\n", set->name,
235.5384 + format_tuple(mpl, '[', memb->tuple),
235.5385 + s->head == NULL ? " is empty" : ":");
235.5386 + for (m = s->head; m != NULL; m = m->next)
235.5387 + write_text(mpl, " %s\n", format_tuple(mpl, '(', m->tuple));
235.5388 + return;
235.5389 +}
235.5390 +
235.5391 +static void display_par(MPL *mpl, PARAMETER *par, MEMBER *memb)
235.5392 +{ /* display member of model parameter */
235.5393 + switch (par->type)
235.5394 + { case A_NUMERIC:
235.5395 + case A_INTEGER:
235.5396 + case A_BINARY:
235.5397 + write_text(mpl, "%s%s = %.*g\n", par->name,
235.5398 + format_tuple(mpl, '[', memb->tuple),
235.5399 + DBL_DIG, memb->value.num);
235.5400 + break;
235.5401 + case A_SYMBOLIC:
235.5402 + write_text(mpl, "%s%s = %s\n", par->name,
235.5403 + format_tuple(mpl, '[', memb->tuple),
235.5404 + format_symbol(mpl, memb->value.sym));
235.5405 + break;
235.5406 + default:
235.5407 + xassert(par != par);
235.5408 + }
235.5409 + return;
235.5410 +}
235.5411 +
235.5412 +#if 1 /* 15/V-2010 */
235.5413 +static void display_var(MPL *mpl, VARIABLE *var, MEMBER *memb,
235.5414 + int suff)
235.5415 +{ /* display member of model variable */
235.5416 + if (suff == DOT_NONE || suff == DOT_VAL)
235.5417 + write_text(mpl, "%s%s.val = %.*g\n", var->name,
235.5418 + format_tuple(mpl, '[', memb->tuple), DBL_DIG,
235.5419 + memb->value.var->prim);
235.5420 + else if (suff == DOT_LB)
235.5421 + write_text(mpl, "%s%s.lb = %.*g\n", var->name,
235.5422 + format_tuple(mpl, '[', memb->tuple), DBL_DIG,
235.5423 + memb->value.var->var->lbnd == NULL ? -DBL_MAX :
235.5424 + memb->value.var->lbnd);
235.5425 + else if (suff == DOT_UB)
235.5426 + write_text(mpl, "%s%s.ub = %.*g\n", var->name,
235.5427 + format_tuple(mpl, '[', memb->tuple), DBL_DIG,
235.5428 + memb->value.var->var->ubnd == NULL ? +DBL_MAX :
235.5429 + memb->value.var->ubnd);
235.5430 + else if (suff == DOT_STATUS)
235.5431 + write_text(mpl, "%s%s.status = %d\n", var->name, format_tuple
235.5432 + (mpl, '[', memb->tuple), memb->value.var->stat);
235.5433 + else if (suff == DOT_DUAL)
235.5434 + write_text(mpl, "%s%s.dual = %.*g\n", var->name,
235.5435 + format_tuple(mpl, '[', memb->tuple), DBL_DIG,
235.5436 + memb->value.var->dual);
235.5437 + else
235.5438 + xassert(suff != suff);
235.5439 + return;
235.5440 +}
235.5441 +#endif
235.5442 +
235.5443 +#if 1 /* 15/V-2010 */
235.5444 +static void display_con(MPL *mpl, CONSTRAINT *con, MEMBER *memb,
235.5445 + int suff)
235.5446 +{ /* display member of model constraint */
235.5447 + if (suff == DOT_NONE || suff == DOT_VAL)
235.5448 + write_text(mpl, "%s%s.val = %.*g\n", con->name,
235.5449 + format_tuple(mpl, '[', memb->tuple), DBL_DIG,
235.5450 + memb->value.con->prim);
235.5451 + else if (suff == DOT_LB)
235.5452 + write_text(mpl, "%s%s.lb = %.*g\n", con->name,
235.5453 + format_tuple(mpl, '[', memb->tuple), DBL_DIG,
235.5454 + memb->value.con->con->lbnd == NULL ? -DBL_MAX :
235.5455 + memb->value.con->lbnd);
235.5456 + else if (suff == DOT_UB)
235.5457 + write_text(mpl, "%s%s.ub = %.*g\n", con->name,
235.5458 + format_tuple(mpl, '[', memb->tuple), DBL_DIG,
235.5459 + memb->value.con->con->ubnd == NULL ? +DBL_MAX :
235.5460 + memb->value.con->ubnd);
235.5461 + else if (suff == DOT_STATUS)
235.5462 + write_text(mpl, "%s%s.status = %d\n", con->name, format_tuple
235.5463 + (mpl, '[', memb->tuple), memb->value.con->stat);
235.5464 + else if (suff == DOT_DUAL)
235.5465 + write_text(mpl, "%s%s.dual = %.*g\n", con->name,
235.5466 + format_tuple(mpl, '[', memb->tuple), DBL_DIG,
235.5467 + memb->value.con->dual);
235.5468 + else
235.5469 + xassert(suff != suff);
235.5470 + return;
235.5471 +}
235.5472 +#endif
235.5473 +
235.5474 +static void display_memb(MPL *mpl, CODE *code)
235.5475 +{ /* display member specified by pseudo-code */
235.5476 + MEMBER memb;
235.5477 + ARG_LIST *e;
235.5478 + xassert(code->op == O_MEMNUM || code->op == O_MEMSYM
235.5479 + || code->op == O_MEMSET || code->op == O_MEMVAR
235.5480 + || code->op == O_MEMCON);
235.5481 + memb.tuple = create_tuple(mpl);
235.5482 + for (e = code->arg.par.list; e != NULL; e = e->next)
235.5483 + memb.tuple = expand_tuple(mpl, memb.tuple, eval_symbolic(mpl,
235.5484 + e->x));
235.5485 + switch (code->op)
235.5486 + { case O_MEMNUM:
235.5487 + memb.value.num = eval_member_num(mpl, code->arg.par.par,
235.5488 + memb.tuple);
235.5489 + display_par(mpl, code->arg.par.par, &memb);
235.5490 + break;
235.5491 + case O_MEMSYM:
235.5492 + memb.value.sym = eval_member_sym(mpl, code->arg.par.par,
235.5493 + memb.tuple);
235.5494 + display_par(mpl, code->arg.par.par, &memb);
235.5495 + delete_symbol(mpl, memb.value.sym);
235.5496 + break;
235.5497 + case O_MEMSET:
235.5498 + memb.value.set = eval_member_set(mpl, code->arg.set.set,
235.5499 + memb.tuple);
235.5500 + display_set(mpl, code->arg.set.set, &memb);
235.5501 + break;
235.5502 + case O_MEMVAR:
235.5503 + memb.value.var = eval_member_var(mpl, code->arg.var.var,
235.5504 + memb.tuple);
235.5505 + display_var
235.5506 + (mpl, code->arg.var.var, &memb, code->arg.var.suff);
235.5507 + break;
235.5508 + case O_MEMCON:
235.5509 + memb.value.con = eval_member_con(mpl, code->arg.con.con,
235.5510 + memb.tuple);
235.5511 + display_con
235.5512 + (mpl, code->arg.con.con, &memb, code->arg.con.suff);
235.5513 + break;
235.5514 + default:
235.5515 + xassert(code != code);
235.5516 + }
235.5517 + delete_tuple(mpl, memb.tuple);
235.5518 + return;
235.5519 +}
235.5520 +
235.5521 +static void display_code(MPL *mpl, CODE *code)
235.5522 +{ /* display value of expression */
235.5523 + switch (code->type)
235.5524 + { case A_NUMERIC:
235.5525 + /* numeric value */
235.5526 + { double num;
235.5527 + num = eval_numeric(mpl, code);
235.5528 + write_text(mpl, "%.*g\n", DBL_DIG, num);
235.5529 + }
235.5530 + break;
235.5531 + case A_SYMBOLIC:
235.5532 + /* symbolic value */
235.5533 + { SYMBOL *sym;
235.5534 + sym = eval_symbolic(mpl, code);
235.5535 + write_text(mpl, "%s\n", format_symbol(mpl, sym));
235.5536 + delete_symbol(mpl, sym);
235.5537 + }
235.5538 + break;
235.5539 + case A_LOGICAL:
235.5540 + /* logical value */
235.5541 + { int bit;
235.5542 + bit = eval_logical(mpl, code);
235.5543 + write_text(mpl, "%s\n", bit ? "true" : "false");
235.5544 + }
235.5545 + break;
235.5546 + case A_TUPLE:
235.5547 + /* n-tuple */
235.5548 + { TUPLE *tuple;
235.5549 + tuple = eval_tuple(mpl, code);
235.5550 + write_text(mpl, "%s\n", format_tuple(mpl, '(', tuple));
235.5551 + delete_tuple(mpl, tuple);
235.5552 + }
235.5553 + break;
235.5554 + case A_ELEMSET:
235.5555 + /* elemental set */
235.5556 + { ELEMSET *set;
235.5557 + MEMBER *memb;
235.5558 + set = eval_elemset(mpl, code);
235.5559 + if (set->head == 0)
235.5560 + write_text(mpl, "set is empty\n");
235.5561 + for (memb = set->head; memb != NULL; memb = memb->next)
235.5562 + write_text(mpl, " %s\n", format_tuple(mpl, '(',
235.5563 + memb->tuple));
235.5564 + delete_elemset(mpl, set);
235.5565 + }
235.5566 + break;
235.5567 + case A_FORMULA:
235.5568 + /* linear form */
235.5569 + { FORMULA *form, *term;
235.5570 + form = eval_formula(mpl, code);
235.5571 + if (form == NULL)
235.5572 + write_text(mpl, "linear form is empty\n");
235.5573 + for (term = form; term != NULL; term = term->next)
235.5574 + { if (term->var == NULL)
235.5575 + write_text(mpl, " %.*g\n", term->coef);
235.5576 + else
235.5577 + write_text(mpl, " %.*g %s%s\n", DBL_DIG,
235.5578 + term->coef, term->var->var->name,
235.5579 + format_tuple(mpl, '[', term->var->memb->tuple));
235.5580 + }
235.5581 + delete_formula(mpl, form);
235.5582 + }
235.5583 + break;
235.5584 + default:
235.5585 + xassert(code != code);
235.5586 + }
235.5587 + return;
235.5588 +}
235.5589 +
235.5590 +static int display_func(MPL *mpl, void *info)
235.5591 +{ /* this is auxiliary routine to work within domain scope */
235.5592 + DISPLAY *dpy = (DISPLAY *)info;
235.5593 + DISPLAY1 *entry;
235.5594 + for (entry = dpy->list; entry != NULL; entry = entry->next)
235.5595 + { if (entry->type == A_INDEX)
235.5596 + { /* dummy index */
235.5597 + DOMAIN_SLOT *slot = entry->u.slot;
235.5598 + write_text(mpl, "%s = %s\n", slot->name,
235.5599 + format_symbol(mpl, slot->value));
235.5600 + }
235.5601 + else if (entry->type == A_SET)
235.5602 + { /* model set */
235.5603 + SET *set = entry->u.set;
235.5604 + MEMBER *memb;
235.5605 + if (set->assign != NULL)
235.5606 + { /* the set has assignment expression; evaluate all its
235.5607 + members over entire domain */
235.5608 + eval_whole_set(mpl, set);
235.5609 + }
235.5610 + else
235.5611 + { /* the set has no assignment expression; refer to its
235.5612 + any existing member ignoring resultant value to check
235.5613 + the data provided the data section */
235.5614 +#if 1 /* 12/XII-2008 */
235.5615 + if (set->gadget != NULL && set->data == 0)
235.5616 + { /* initialize the set with data from a plain set */
235.5617 + saturate_set(mpl, set);
235.5618 + }
235.5619 +#endif
235.5620 + if (set->array->head != NULL)
235.5621 + eval_member_set(mpl, set, set->array->head->tuple);
235.5622 + }
235.5623 + /* display all members of the set array */
235.5624 + if (set->array->head == NULL)
235.5625 + write_text(mpl, "%s has empty content\n", set->name);
235.5626 + for (memb = set->array->head; memb != NULL; memb =
235.5627 + memb->next) display_set(mpl, set, memb);
235.5628 + }
235.5629 + else if (entry->type == A_PARAMETER)
235.5630 + { /* model parameter */
235.5631 + PARAMETER *par = entry->u.par;
235.5632 + MEMBER *memb;
235.5633 + if (par->assign != NULL)
235.5634 + { /* the parameter has an assignment expression; evaluate
235.5635 + all its member over entire domain */
235.5636 + eval_whole_par(mpl, par);
235.5637 + }
235.5638 + else
235.5639 + { /* the parameter has no assignment expression; refer to
235.5640 + its any existing member ignoring resultant value to
235.5641 + check the data provided in the data section */
235.5642 + if (par->array->head != NULL)
235.5643 + { if (par->type != A_SYMBOLIC)
235.5644 + eval_member_num(mpl, par, par->array->head->tuple);
235.5645 + else
235.5646 + delete_symbol(mpl, eval_member_sym(mpl, par,
235.5647 + par->array->head->tuple));
235.5648 + }
235.5649 + }
235.5650 + /* display all members of the parameter array */
235.5651 + if (par->array->head == NULL)
235.5652 + write_text(mpl, "%s has empty content\n", par->name);
235.5653 + for (memb = par->array->head; memb != NULL; memb =
235.5654 + memb->next) display_par(mpl, par, memb);
235.5655 + }
235.5656 + else if (entry->type == A_VARIABLE)
235.5657 + { /* model variable */
235.5658 + VARIABLE *var = entry->u.var;
235.5659 + MEMBER *memb;
235.5660 + xassert(mpl->flag_p);
235.5661 + /* display all members of the variable array */
235.5662 + if (var->array->head == NULL)
235.5663 + write_text(mpl, "%s has empty content\n", var->name);
235.5664 + for (memb = var->array->head; memb != NULL; memb =
235.5665 + memb->next) display_var(mpl, var, memb, DOT_NONE);
235.5666 + }
235.5667 + else if (entry->type == A_CONSTRAINT)
235.5668 + { /* model constraint */
235.5669 + CONSTRAINT *con = entry->u.con;
235.5670 + MEMBER *memb;
235.5671 + xassert(mpl->flag_p);
235.5672 + /* display all members of the constraint array */
235.5673 + if (con->array->head == NULL)
235.5674 + write_text(mpl, "%s has empty content\n", con->name);
235.5675 + for (memb = con->array->head; memb != NULL; memb =
235.5676 + memb->next) display_con(mpl, con, memb, DOT_NONE);
235.5677 + }
235.5678 + else if (entry->type == A_EXPRESSION)
235.5679 + { /* expression */
235.5680 + CODE *code = entry->u.code;
235.5681 + if (code->op == O_MEMNUM || code->op == O_MEMSYM ||
235.5682 + code->op == O_MEMSET || code->op == O_MEMVAR ||
235.5683 + code->op == O_MEMCON)
235.5684 + display_memb(mpl, code);
235.5685 + else
235.5686 + display_code(mpl, code);
235.5687 + }
235.5688 + else
235.5689 + xassert(entry != entry);
235.5690 + }
235.5691 + return 0;
235.5692 +}
235.5693 +
235.5694 +void execute_display(MPL *mpl, DISPLAY *dpy)
235.5695 +{ loop_within_domain(mpl, dpy->domain, dpy, display_func);
235.5696 + return;
235.5697 +}
235.5698 +
235.5699 +/*----------------------------------------------------------------------
235.5700 +-- clean_display - clean display statement.
235.5701 +--
235.5702 +-- This routine cleans specified display statement that assumes deleting
235.5703 +-- all stuff dynamically allocated on generating/postsolving phase. */
235.5704 +
235.5705 +void clean_display(MPL *mpl, DISPLAY *dpy)
235.5706 +{ DISPLAY1 *d;
235.5707 +#if 0 /* 15/V-2010 */
235.5708 + ARG_LIST *e;
235.5709 +#endif
235.5710 + /* clean subscript domain */
235.5711 + clean_domain(mpl, dpy->domain);
235.5712 + /* clean display list */
235.5713 + for (d = dpy->list; d != NULL; d = d->next)
235.5714 + { /* clean pseudo-code for computing expression */
235.5715 + if (d->type == A_EXPRESSION)
235.5716 + clean_code(mpl, d->u.code);
235.5717 +#if 0 /* 15/V-2010 */
235.5718 + /* clean pseudo-code for computing subscripts */
235.5719 + for (e = d->list; e != NULL; e = e->next)
235.5720 + clean_code(mpl, e->x);
235.5721 +#endif
235.5722 + }
235.5723 + return;
235.5724 +}
235.5725 +
235.5726 +/*----------------------------------------------------------------------
235.5727 +-- execute_printf - execute printf statement.
235.5728 +--
235.5729 +-- This routine executes specified printf statement. */
235.5730 +
235.5731 +#if 1 /* 14/VII-2006 */
235.5732 +static void print_char(MPL *mpl, int c)
235.5733 +{ if (mpl->prt_fp == NULL)
235.5734 + write_char(mpl, c);
235.5735 + else
235.5736 + xfputc(c, mpl->prt_fp);
235.5737 + return;
235.5738 +}
235.5739 +
235.5740 +static void print_text(MPL *mpl, char *fmt, ...)
235.5741 +{ va_list arg;
235.5742 + char buf[OUTBUF_SIZE], *c;
235.5743 + va_start(arg, fmt);
235.5744 + vsprintf(buf, fmt, arg);
235.5745 + xassert(strlen(buf) < sizeof(buf));
235.5746 + va_end(arg);
235.5747 + for (c = buf; *c != '\0'; c++) print_char(mpl, *c);
235.5748 + return;
235.5749 +}
235.5750 +#endif
235.5751 +
235.5752 +static int printf_func(MPL *mpl, void *info)
235.5753 +{ /* this is auxiliary routine to work within domain scope */
235.5754 + PRINTF *prt = (PRINTF *)info;
235.5755 + PRINTF1 *entry;
235.5756 + SYMBOL *sym;
235.5757 + char fmt[MAX_LENGTH+1], *c, *from, save;
235.5758 + /* evaluate format control string */
235.5759 + sym = eval_symbolic(mpl, prt->fmt);
235.5760 + if (sym->str == NULL)
235.5761 + sprintf(fmt, "%.*g", DBL_DIG, sym->num);
235.5762 + else
235.5763 + fetch_string(mpl, sym->str, fmt);
235.5764 + delete_symbol(mpl, sym);
235.5765 + /* scan format control string and perform formatting output */
235.5766 + entry = prt->list;
235.5767 + for (c = fmt; *c != '\0'; c++)
235.5768 + { if (*c == '%')
235.5769 + { /* scan format specifier */
235.5770 + from = c++;
235.5771 + if (*c == '%')
235.5772 + { print_char(mpl, '%');
235.5773 + continue;
235.5774 + }
235.5775 + if (entry == NULL) break;
235.5776 + /* scan optional flags */
235.5777 + while (*c == '-' || *c == '+' || *c == ' ' || *c == '#' ||
235.5778 + *c == '0') c++;
235.5779 + /* scan optional minimum field width */
235.5780 + while (isdigit((unsigned char)*c)) c++;
235.5781 + /* scan optional precision */
235.5782 + if (*c == '.')
235.5783 + { c++;
235.5784 + while (isdigit((unsigned char)*c)) c++;
235.5785 + }
235.5786 + /* scan conversion specifier and perform formatting */
235.5787 + save = *(c+1), *(c+1) = '\0';
235.5788 + if (*c == 'd' || *c == 'i' || *c == 'e' || *c == 'E' ||
235.5789 + *c == 'f' || *c == 'F' || *c == 'g' || *c == 'G')
235.5790 + { /* the specifier requires numeric value */
235.5791 + double value;
235.5792 + xassert(entry != NULL);
235.5793 + switch (entry->code->type)
235.5794 + { case A_NUMERIC:
235.5795 + value = eval_numeric(mpl, entry->code);
235.5796 + break;
235.5797 + case A_SYMBOLIC:
235.5798 + sym = eval_symbolic(mpl, entry->code);
235.5799 + if (sym->str != NULL)
235.5800 + error(mpl, "cannot convert %s to floating-point"
235.5801 + " number", format_symbol(mpl, sym));
235.5802 + value = sym->num;
235.5803 + delete_symbol(mpl, sym);
235.5804 + break;
235.5805 + case A_LOGICAL:
235.5806 + if (eval_logical(mpl, entry->code))
235.5807 + value = 1.0;
235.5808 + else
235.5809 + value = 0.0;
235.5810 + break;
235.5811 + default:
235.5812 + xassert(entry != entry);
235.5813 + }
235.5814 + if (*c == 'd' || *c == 'i')
235.5815 + { double int_max = (double)INT_MAX;
235.5816 + if (!(-int_max <= value && value <= +int_max))
235.5817 + error(mpl, "cannot convert %.*g to integer",
235.5818 + DBL_DIG, value);
235.5819 + print_text(mpl, from, (int)floor(value + 0.5));
235.5820 + }
235.5821 + else
235.5822 + print_text(mpl, from, value);
235.5823 + }
235.5824 + else if (*c == 's')
235.5825 + { /* the specifier requires symbolic value */
235.5826 + char value[MAX_LENGTH+1];
235.5827 + switch (entry->code->type)
235.5828 + { case A_NUMERIC:
235.5829 + sprintf(value, "%.*g", DBL_DIG, eval_numeric(mpl,
235.5830 + entry->code));
235.5831 + break;
235.5832 + case A_LOGICAL:
235.5833 + if (eval_logical(mpl, entry->code))
235.5834 + strcpy(value, "T");
235.5835 + else
235.5836 + strcpy(value, "F");
235.5837 + break;
235.5838 + case A_SYMBOLIC:
235.5839 + sym = eval_symbolic(mpl, entry->code);
235.5840 + if (sym->str == NULL)
235.5841 + sprintf(value, "%.*g", DBL_DIG, sym->num);
235.5842 + else
235.5843 + fetch_string(mpl, sym->str, value);
235.5844 + delete_symbol(mpl, sym);
235.5845 + break;
235.5846 + default:
235.5847 + xassert(entry != entry);
235.5848 + }
235.5849 + print_text(mpl, from, value);
235.5850 + }
235.5851 + else
235.5852 + error(mpl, "format specifier missing or invalid");
235.5853 + *(c+1) = save;
235.5854 + entry = entry->next;
235.5855 + }
235.5856 + else if (*c == '\\')
235.5857 + { /* write some control character */
235.5858 + c++;
235.5859 + if (*c == 't')
235.5860 + print_char(mpl, '\t');
235.5861 + else if (*c == 'n')
235.5862 + print_char(mpl, '\n');
235.5863 +#if 1 /* 28/X-2010 */
235.5864 + else if (*c == '\0')
235.5865 + { /* format string ends with backslash */
235.5866 + error(mpl, "invalid use of escape character \\ in format"
235.5867 + " control string");
235.5868 + }
235.5869 +#endif
235.5870 + else
235.5871 + print_char(mpl, *c);
235.5872 + }
235.5873 + else
235.5874 + { /* write character without formatting */
235.5875 + print_char(mpl, *c);
235.5876 + }
235.5877 + }
235.5878 + return 0;
235.5879 +}
235.5880 +
235.5881 +#if 0 /* 14/VII-2006 */
235.5882 +void execute_printf(MPL *mpl, PRINTF *prt)
235.5883 +{ loop_within_domain(mpl, prt->domain, prt, printf_func);
235.5884 + return;
235.5885 +}
235.5886 +#else
235.5887 +void execute_printf(MPL *mpl, PRINTF *prt)
235.5888 +{ if (prt->fname == NULL)
235.5889 + { /* switch to the standard output */
235.5890 + if (mpl->prt_fp != NULL)
235.5891 + { xfclose(mpl->prt_fp), mpl->prt_fp = NULL;
235.5892 + xfree(mpl->prt_file), mpl->prt_file = NULL;
235.5893 + }
235.5894 + }
235.5895 + else
235.5896 + { /* evaluate file name string */
235.5897 + SYMBOL *sym;
235.5898 + char fname[MAX_LENGTH+1];
235.5899 + sym = eval_symbolic(mpl, prt->fname);
235.5900 + if (sym->str == NULL)
235.5901 + sprintf(fname, "%.*g", DBL_DIG, sym->num);
235.5902 + else
235.5903 + fetch_string(mpl, sym->str, fname);
235.5904 + delete_symbol(mpl, sym);
235.5905 + /* close the current print file, if necessary */
235.5906 + if (mpl->prt_fp != NULL &&
235.5907 + (!prt->app || strcmp(mpl->prt_file, fname) != 0))
235.5908 + { xfclose(mpl->prt_fp), mpl->prt_fp = NULL;
235.5909 + xfree(mpl->prt_file), mpl->prt_file = NULL;
235.5910 + }
235.5911 + /* open the specified print file, if necessary */
235.5912 + if (mpl->prt_fp == NULL)
235.5913 + { mpl->prt_fp = xfopen(fname, prt->app ? "a" : "w");
235.5914 + if (mpl->prt_fp == NULL)
235.5915 + error(mpl, "unable to open `%s' for writing - %s",
235.5916 + fname, xerrmsg());
235.5917 + mpl->prt_file = xmalloc(strlen(fname)+1);
235.5918 + strcpy(mpl->prt_file, fname);
235.5919 + }
235.5920 + }
235.5921 + loop_within_domain(mpl, prt->domain, prt, printf_func);
235.5922 + if (mpl->prt_fp != NULL)
235.5923 + { xfflush(mpl->prt_fp);
235.5924 + if (xferror(mpl->prt_fp))
235.5925 + error(mpl, "writing error to `%s' - %s", mpl->prt_file,
235.5926 + xerrmsg());
235.5927 + }
235.5928 + return;
235.5929 +}
235.5930 +#endif
235.5931 +
235.5932 +/*----------------------------------------------------------------------
235.5933 +-- clean_printf - clean printf statement.
235.5934 +--
235.5935 +-- This routine cleans specified printf statement that assumes deleting
235.5936 +-- all stuff dynamically allocated on generating/postsolving phase. */
235.5937 +
235.5938 +void clean_printf(MPL *mpl, PRINTF *prt)
235.5939 +{ PRINTF1 *p;
235.5940 + /* clean subscript domain */
235.5941 + clean_domain(mpl, prt->domain);
235.5942 + /* clean pseudo-code for computing format string */
235.5943 + clean_code(mpl, prt->fmt);
235.5944 + /* clean printf list */
235.5945 + for (p = prt->list; p != NULL; p = p->next)
235.5946 + { /* clean pseudo-code for computing value to be printed */
235.5947 + clean_code(mpl, p->code);
235.5948 + }
235.5949 +#if 1 /* 14/VII-2006 */
235.5950 + /* clean pseudo-code for computing file name string */
235.5951 + clean_code(mpl, prt->fname);
235.5952 +#endif
235.5953 + return;
235.5954 +}
235.5955 +
235.5956 +/*----------------------------------------------------------------------
235.5957 +-- execute_for - execute for statement.
235.5958 +--
235.5959 +-- This routine executes specified for statement. */
235.5960 +
235.5961 +static int for_func(MPL *mpl, void *info)
235.5962 +{ /* this is auxiliary routine to work within domain scope */
235.5963 + FOR *fur = (FOR *)info;
235.5964 + STATEMENT *stmt, *save;
235.5965 + save = mpl->stmt;
235.5966 + for (stmt = fur->list; stmt != NULL; stmt = stmt->next)
235.5967 + execute_statement(mpl, stmt);
235.5968 + mpl->stmt = save;
235.5969 + return 0;
235.5970 +}
235.5971 +
235.5972 +void execute_for(MPL *mpl, FOR *fur)
235.5973 +{ loop_within_domain(mpl, fur->domain, fur, for_func);
235.5974 + return;
235.5975 +}
235.5976 +
235.5977 +/*----------------------------------------------------------------------
235.5978 +-- clean_for - clean for statement.
235.5979 +--
235.5980 +-- This routine cleans specified for statement that assumes deleting all
235.5981 +-- stuff dynamically allocated on generating/postsolving phase. */
235.5982 +
235.5983 +void clean_for(MPL *mpl, FOR *fur)
235.5984 +{ STATEMENT *stmt;
235.5985 + /* clean subscript domain */
235.5986 + clean_domain(mpl, fur->domain);
235.5987 + /* clean all sub-statements */
235.5988 + for (stmt = fur->list; stmt != NULL; stmt = stmt->next)
235.5989 + clean_statement(mpl, stmt);
235.5990 + return;
235.5991 +}
235.5992 +
235.5993 +/*----------------------------------------------------------------------
235.5994 +-- execute_statement - execute specified model statement.
235.5995 +--
235.5996 +-- This routine executes specified model statement. */
235.5997 +
235.5998 +void execute_statement(MPL *mpl, STATEMENT *stmt)
235.5999 +{ mpl->stmt = stmt;
235.6000 + switch (stmt->type)
235.6001 + { case A_SET:
235.6002 + case A_PARAMETER:
235.6003 + case A_VARIABLE:
235.6004 + break;
235.6005 + case A_CONSTRAINT:
235.6006 + xprintf("Generating %s...\n", stmt->u.con->name);
235.6007 + eval_whole_con(mpl, stmt->u.con);
235.6008 + break;
235.6009 + case A_TABLE:
235.6010 + switch (stmt->u.tab->type)
235.6011 + { case A_INPUT:
235.6012 + xprintf("Reading %s...\n", stmt->u.tab->name);
235.6013 + break;
235.6014 + case A_OUTPUT:
235.6015 + xprintf("Writing %s...\n", stmt->u.tab->name);
235.6016 + break;
235.6017 + default:
235.6018 + xassert(stmt != stmt);
235.6019 + }
235.6020 + execute_table(mpl, stmt->u.tab);
235.6021 + break;
235.6022 + case A_SOLVE:
235.6023 + break;
235.6024 + case A_CHECK:
235.6025 + xprintf("Checking (line %d)...\n", stmt->line);
235.6026 + execute_check(mpl, stmt->u.chk);
235.6027 + break;
235.6028 + case A_DISPLAY:
235.6029 + write_text(mpl, "Display statement at line %d\n",
235.6030 + stmt->line);
235.6031 + execute_display(mpl, stmt->u.dpy);
235.6032 + break;
235.6033 + case A_PRINTF:
235.6034 + execute_printf(mpl, stmt->u.prt);
235.6035 + break;
235.6036 + case A_FOR:
235.6037 + execute_for(mpl, stmt->u.fur);
235.6038 + break;
235.6039 + default:
235.6040 + xassert(stmt != stmt);
235.6041 + }
235.6042 + return;
235.6043 +}
235.6044 +
235.6045 +/*----------------------------------------------------------------------
235.6046 +-- clean_statement - clean specified model statement.
235.6047 +--
235.6048 +-- This routine cleans specified model statement that assumes deleting
235.6049 +-- all stuff dynamically allocated on generating/postsolving phase. */
235.6050 +
235.6051 +void clean_statement(MPL *mpl, STATEMENT *stmt)
235.6052 +{ switch(stmt->type)
235.6053 + { case A_SET:
235.6054 + clean_set(mpl, stmt->u.set); break;
235.6055 + case A_PARAMETER:
235.6056 + clean_parameter(mpl, stmt->u.par); break;
235.6057 + case A_VARIABLE:
235.6058 + clean_variable(mpl, stmt->u.var); break;
235.6059 + case A_CONSTRAINT:
235.6060 + clean_constraint(mpl, stmt->u.con); break;
235.6061 +#if 1 /* 11/II-2008 */
235.6062 + case A_TABLE:
235.6063 + clean_table(mpl, stmt->u.tab); break;
235.6064 +#endif
235.6065 + case A_SOLVE:
235.6066 + break;
235.6067 + case A_CHECK:
235.6068 + clean_check(mpl, stmt->u.chk); break;
235.6069 + case A_DISPLAY:
235.6070 + clean_display(mpl, stmt->u.dpy); break;
235.6071 + case A_PRINTF:
235.6072 + clean_printf(mpl, stmt->u.prt); break;
235.6073 + case A_FOR:
235.6074 + clean_for(mpl, stmt->u.fur); break;
235.6075 + default:
235.6076 + xassert(stmt != stmt);
235.6077 + }
235.6078 + return;
235.6079 +}
235.6080 +
235.6081 +/* eof */
236.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
236.2 +++ b/src/glpmpl04.c Mon Dec 06 13:09:21 2010 +0100
236.3 @@ -0,0 +1,1424 @@
236.4 +/* glpmpl04.c */
236.5 +
236.6 +/***********************************************************************
236.7 +* This code is part of GLPK (GNU Linear Programming Kit).
236.8 +*
236.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
236.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
236.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
236.12 +* E-mail: <mao@gnu.org>.
236.13 +*
236.14 +* GLPK is free software: you can redistribute it and/or modify it
236.15 +* under the terms of the GNU General Public License as published by
236.16 +* the Free Software Foundation, either version 3 of the License, or
236.17 +* (at your option) any later version.
236.18 +*
236.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
236.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
236.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
236.22 +* License for more details.
236.23 +*
236.24 +* You should have received a copy of the GNU General Public License
236.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
236.26 +***********************************************************************/
236.27 +
236.28 +#define _GLPSTD_ERRNO
236.29 +#define _GLPSTD_STDIO
236.30 +#include "glpmpl.h"
236.31 +#define xfault xerror
236.32 +#define dmp_create_poolx(size) dmp_create_pool()
236.33 +
236.34 +/**********************************************************************/
236.35 +/* * * GENERATING AND POSTSOLVING MODEL * * */
236.36 +/**********************************************************************/
236.37 +
236.38 +/*----------------------------------------------------------------------
236.39 +-- alloc_content - allocate content arrays for all model objects.
236.40 +--
236.41 +-- This routine allocates content arrays for all existing model objects
236.42 +-- and thereby finalizes creating model.
236.43 +--
236.44 +-- This routine must be called immediately after reading model section,
236.45 +-- i.e. before reading data section or generating model. */
236.46 +
236.47 +void alloc_content(MPL *mpl)
236.48 +{ STATEMENT *stmt;
236.49 + /* walk through all model statements */
236.50 + for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
236.51 + { switch (stmt->type)
236.52 + { case A_SET:
236.53 + /* model set */
236.54 + xassert(stmt->u.set->array == NULL);
236.55 + stmt->u.set->array = create_array(mpl, A_ELEMSET,
236.56 + stmt->u.set->dim);
236.57 + break;
236.58 + case A_PARAMETER:
236.59 + /* model parameter */
236.60 + xassert(stmt->u.par->array == NULL);
236.61 + switch (stmt->u.par->type)
236.62 + { case A_NUMERIC:
236.63 + case A_INTEGER:
236.64 + case A_BINARY:
236.65 + stmt->u.par->array = create_array(mpl, A_NUMERIC,
236.66 + stmt->u.par->dim);
236.67 + break;
236.68 + case A_SYMBOLIC:
236.69 + stmt->u.par->array = create_array(mpl, A_SYMBOLIC,
236.70 + stmt->u.par->dim);
236.71 + break;
236.72 + default:
236.73 + xassert(stmt != stmt);
236.74 + }
236.75 + break;
236.76 + case A_VARIABLE:
236.77 + /* model variable */
236.78 + xassert(stmt->u.var->array == NULL);
236.79 + stmt->u.var->array = create_array(mpl, A_ELEMVAR,
236.80 + stmt->u.var->dim);
236.81 + break;
236.82 + case A_CONSTRAINT:
236.83 + /* model constraint/objective */
236.84 + xassert(stmt->u.con->array == NULL);
236.85 + stmt->u.con->array = create_array(mpl, A_ELEMCON,
236.86 + stmt->u.con->dim);
236.87 + break;
236.88 +#if 1 /* 11/II-2008 */
236.89 + case A_TABLE:
236.90 +#endif
236.91 + case A_SOLVE:
236.92 + case A_CHECK:
236.93 + case A_DISPLAY:
236.94 + case A_PRINTF:
236.95 + case A_FOR:
236.96 + /* functional statements have no content array */
236.97 + break;
236.98 + default:
236.99 + xassert(stmt != stmt);
236.100 + }
236.101 + }
236.102 + return;
236.103 +}
236.104 +
236.105 +/*----------------------------------------------------------------------
236.106 +-- generate_model - generate model.
236.107 +--
236.108 +-- This routine executes the model statements which precede the solve
236.109 +-- statement. */
236.110 +
236.111 +void generate_model(MPL *mpl)
236.112 +{ STATEMENT *stmt;
236.113 + xassert(!mpl->flag_p);
236.114 + for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
236.115 + { execute_statement(mpl, stmt);
236.116 + if (mpl->stmt->type == A_SOLVE) break;
236.117 + }
236.118 + mpl->stmt = stmt;
236.119 + return;
236.120 +}
236.121 +
236.122 +/*----------------------------------------------------------------------
236.123 +-- build_problem - build problem instance.
236.124 +--
236.125 +-- This routine builds lists of rows and columns for problem instance,
236.126 +-- which corresponds to the generated model. */
236.127 +
236.128 +void build_problem(MPL *mpl)
236.129 +{ STATEMENT *stmt;
236.130 + MEMBER *memb;
236.131 + VARIABLE *v;
236.132 + CONSTRAINT *c;
236.133 + FORMULA *t;
236.134 + int i, j;
236.135 + xassert(mpl->m == 0);
236.136 + xassert(mpl->n == 0);
236.137 + xassert(mpl->row == NULL);
236.138 + xassert(mpl->col == NULL);
236.139 + /* check that all elemental variables has zero column numbers */
236.140 + for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
236.141 + { if (stmt->type == A_VARIABLE)
236.142 + { v = stmt->u.var;
236.143 + for (memb = v->array->head; memb != NULL; memb = memb->next)
236.144 + xassert(memb->value.var->j == 0);
236.145 + }
236.146 + }
236.147 + /* assign row numbers to elemental constraints and objectives */
236.148 + for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
236.149 + { if (stmt->type == A_CONSTRAINT)
236.150 + { c = stmt->u.con;
236.151 + for (memb = c->array->head; memb != NULL; memb = memb->next)
236.152 + { xassert(memb->value.con->i == 0);
236.153 + memb->value.con->i = ++mpl->m;
236.154 + /* walk through linear form and mark elemental variables,
236.155 + which are referenced at least once */
236.156 + for (t = memb->value.con->form; t != NULL; t = t->next)
236.157 + { xassert(t->var != NULL);
236.158 + t->var->memb->value.var->j = -1;
236.159 + }
236.160 + }
236.161 + }
236.162 + }
236.163 + /* assign column numbers to marked elemental variables */
236.164 + for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
236.165 + { if (stmt->type == A_VARIABLE)
236.166 + { v = stmt->u.var;
236.167 + for (memb = v->array->head; memb != NULL; memb = memb->next)
236.168 + if (memb->value.var->j != 0) memb->value.var->j =
236.169 + ++mpl->n;
236.170 + }
236.171 + }
236.172 + /* build list of rows */
236.173 + mpl->row = xcalloc(1+mpl->m, sizeof(ELEMCON *));
236.174 + for (i = 1; i <= mpl->m; i++) mpl->row[i] = NULL;
236.175 + for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
236.176 + { if (stmt->type == A_CONSTRAINT)
236.177 + { c = stmt->u.con;
236.178 + for (memb = c->array->head; memb != NULL; memb = memb->next)
236.179 + { i = memb->value.con->i;
236.180 + xassert(1 <= i && i <= mpl->m);
236.181 + xassert(mpl->row[i] == NULL);
236.182 + mpl->row[i] = memb->value.con;
236.183 + }
236.184 + }
236.185 + }
236.186 + for (i = 1; i <= mpl->m; i++) xassert(mpl->row[i] != NULL);
236.187 + /* build list of columns */
236.188 + mpl->col = xcalloc(1+mpl->n, sizeof(ELEMVAR *));
236.189 + for (j = 1; j <= mpl->n; j++) mpl->col[j] = NULL;
236.190 + for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
236.191 + { if (stmt->type == A_VARIABLE)
236.192 + { v = stmt->u.var;
236.193 + for (memb = v->array->head; memb != NULL; memb = memb->next)
236.194 + { j = memb->value.var->j;
236.195 + if (j == 0) continue;
236.196 + xassert(1 <= j && j <= mpl->n);
236.197 + xassert(mpl->col[j] == NULL);
236.198 + mpl->col[j] = memb->value.var;
236.199 + }
236.200 + }
236.201 + }
236.202 + for (j = 1; j <= mpl->n; j++) xassert(mpl->col[j] != NULL);
236.203 + return;
236.204 +}
236.205 +
236.206 +/*----------------------------------------------------------------------
236.207 +-- postsolve_model - postsolve model.
236.208 +--
236.209 +-- This routine executes the model statements which follow the solve
236.210 +-- statement. */
236.211 +
236.212 +void postsolve_model(MPL *mpl)
236.213 +{ STATEMENT *stmt;
236.214 + xassert(!mpl->flag_p);
236.215 + mpl->flag_p = 1;
236.216 + for (stmt = mpl->stmt; stmt != NULL; stmt = stmt->next)
236.217 + execute_statement(mpl, stmt);
236.218 + mpl->stmt = NULL;
236.219 + return;
236.220 +}
236.221 +
236.222 +/*----------------------------------------------------------------------
236.223 +-- clean_model - clean model content.
236.224 +--
236.225 +-- This routine cleans the model content that assumes deleting all stuff
236.226 +-- dynamically allocated on generating/postsolving phase.
236.227 +--
236.228 +-- Actually cleaning model content is not needed. This function is used
236.229 +-- mainly to be sure that there were no logical errors on using dynamic
236.230 +-- memory pools during the generation phase.
236.231 +--
236.232 +-- NOTE: This routine must not be called if any errors were detected on
236.233 +-- the generation phase. */
236.234 +
236.235 +void clean_model(MPL *mpl)
236.236 +{ STATEMENT *stmt;
236.237 + for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
236.238 + clean_statement(mpl, stmt);
236.239 + /* check that all atoms have been returned to their pools */
236.240 + if (dmp_in_use(mpl->strings).lo != 0)
236.241 + error(mpl, "internal logic error: %d string segment(s) were lo"
236.242 + "st", dmp_in_use(mpl->strings).lo);
236.243 + if (dmp_in_use(mpl->symbols).lo != 0)
236.244 + error(mpl, "internal logic error: %d symbol(s) were lost",
236.245 + dmp_in_use(mpl->symbols).lo);
236.246 + if (dmp_in_use(mpl->tuples).lo != 0)
236.247 + error(mpl, "internal logic error: %d n-tuple component(s) were"
236.248 + " lost", dmp_in_use(mpl->tuples).lo);
236.249 + if (dmp_in_use(mpl->arrays).lo != 0)
236.250 + error(mpl, "internal logic error: %d array(s) were lost",
236.251 + dmp_in_use(mpl->arrays).lo);
236.252 + if (dmp_in_use(mpl->members).lo != 0)
236.253 + error(mpl, "internal logic error: %d array member(s) were lost"
236.254 + , dmp_in_use(mpl->members).lo);
236.255 + if (dmp_in_use(mpl->elemvars).lo != 0)
236.256 + error(mpl, "internal logic error: %d elemental variable(s) wer"
236.257 + "e lost", dmp_in_use(mpl->elemvars).lo);
236.258 + if (dmp_in_use(mpl->formulae).lo != 0)
236.259 + error(mpl, "internal logic error: %d linear term(s) were lost",
236.260 + dmp_in_use(mpl->formulae).lo);
236.261 + if (dmp_in_use(mpl->elemcons).lo != 0)
236.262 + error(mpl, "internal logic error: %d elemental constraint(s) w"
236.263 + "ere lost", dmp_in_use(mpl->elemcons).lo);
236.264 + return;
236.265 +}
236.266 +
236.267 +/**********************************************************************/
236.268 +/* * * INPUT/OUTPUT * * */
236.269 +/**********************************************************************/
236.270 +
236.271 +/*----------------------------------------------------------------------
236.272 +-- open_input - open input text file.
236.273 +--
236.274 +-- This routine opens the input text file for scanning. */
236.275 +
236.276 +void open_input(MPL *mpl, char *file)
236.277 +{ mpl->line = 0;
236.278 + mpl->c = '\n';
236.279 + mpl->token = 0;
236.280 + mpl->imlen = 0;
236.281 + mpl->image[0] = '\0';
236.282 + mpl->value = 0.0;
236.283 + mpl->b_token = T_EOF;
236.284 + mpl->b_imlen = 0;
236.285 + mpl->b_image[0] = '\0';
236.286 + mpl->b_value = 0.0;
236.287 + mpl->f_dots = 0;
236.288 + mpl->f_scan = 0;
236.289 + mpl->f_token = 0;
236.290 + mpl->f_imlen = 0;
236.291 + mpl->f_image[0] = '\0';
236.292 + mpl->f_value = 0.0;
236.293 + memset(mpl->context, ' ', CONTEXT_SIZE);
236.294 + mpl->c_ptr = 0;
236.295 + xassert(mpl->in_fp == NULL);
236.296 + mpl->in_fp = xfopen(file, "r");
236.297 + if (mpl->in_fp == NULL)
236.298 + error(mpl, "unable to open %s - %s", file, xerrmsg());
236.299 + mpl->in_file = file;
236.300 + /* scan the very first character */
236.301 + get_char(mpl);
236.302 + /* scan the very first token */
236.303 + get_token(mpl);
236.304 + return;
236.305 +}
236.306 +
236.307 +/*----------------------------------------------------------------------
236.308 +-- read_char - read next character from input text file.
236.309 +--
236.310 +-- This routine returns a next ASCII character read from the input text
236.311 +-- file. If the end of file has been reached, EOF is returned. */
236.312 +
236.313 +int read_char(MPL *mpl)
236.314 +{ int c;
236.315 + xassert(mpl->in_fp != NULL);
236.316 + c = xfgetc(mpl->in_fp);
236.317 + if (c < 0)
236.318 + { if (xferror(mpl->in_fp))
236.319 + error(mpl, "read error on %s - %s", mpl->in_file,
236.320 + xerrmsg());
236.321 + c = EOF;
236.322 + }
236.323 + return c;
236.324 +}
236.325 +
236.326 +/*----------------------------------------------------------------------
236.327 +-- close_input - close input text file.
236.328 +--
236.329 +-- This routine closes the input text file. */
236.330 +
236.331 +void close_input(MPL *mpl)
236.332 +{ xassert(mpl->in_fp != NULL);
236.333 + xfclose(mpl->in_fp);
236.334 + mpl->in_fp = NULL;
236.335 + mpl->in_file = NULL;
236.336 + return;
236.337 +}
236.338 +
236.339 +/*----------------------------------------------------------------------
236.340 +-- open_output - open output text file.
236.341 +--
236.342 +-- This routine opens the output text file for writing data produced by
236.343 +-- display and printf statements. */
236.344 +
236.345 +void open_output(MPL *mpl, char *file)
236.346 +{ xassert(mpl->out_fp == NULL);
236.347 + if (file == NULL)
236.348 + { file = "<stdout>";
236.349 + mpl->out_fp = (void *)stdout;
236.350 + }
236.351 + else
236.352 + { mpl->out_fp = xfopen(file, "w");
236.353 + if (mpl->out_fp == NULL)
236.354 + error(mpl, "unable to create %s - %s", file, xerrmsg());
236.355 + }
236.356 + mpl->out_file = xmalloc(strlen(file)+1);
236.357 + strcpy(mpl->out_file, file);
236.358 + return;
236.359 +}
236.360 +
236.361 +/*----------------------------------------------------------------------
236.362 +-- write_char - write next character to output text file.
236.363 +--
236.364 +-- This routine writes an ASCII character to the output text file. */
236.365 +
236.366 +void write_char(MPL *mpl, int c)
236.367 +{ xassert(mpl->out_fp != NULL);
236.368 + if (mpl->out_fp == (void *)stdout)
236.369 + xprintf("%c", c);
236.370 + else
236.371 + xfprintf(mpl->out_fp, "%c", c);
236.372 + return;
236.373 +}
236.374 +
236.375 +/*----------------------------------------------------------------------
236.376 +-- write_text - format and write text to output text file.
236.377 +--
236.378 +-- This routine formats a text using the format control string and then
236.379 +-- writes this text to the output text file. */
236.380 +
236.381 +void write_text(MPL *mpl, char *fmt, ...)
236.382 +{ va_list arg;
236.383 + char buf[OUTBUF_SIZE], *c;
236.384 + va_start(arg, fmt);
236.385 + vsprintf(buf, fmt, arg);
236.386 + xassert(strlen(buf) < sizeof(buf));
236.387 + va_end(arg);
236.388 + for (c = buf; *c != '\0'; c++) write_char(mpl, *c);
236.389 + return;
236.390 +}
236.391 +
236.392 +/*----------------------------------------------------------------------
236.393 +-- flush_output - finalize writing data to output text file.
236.394 +--
236.395 +-- This routine finalizes writing data to the output text file. */
236.396 +
236.397 +void flush_output(MPL *mpl)
236.398 +{ xassert(mpl->out_fp != NULL);
236.399 + if (mpl->out_fp != (void *)stdout)
236.400 + { xfflush(mpl->out_fp);
236.401 + if (xferror(mpl->out_fp))
236.402 + error(mpl, "write error on %s - %s", mpl->out_file,
236.403 + xerrmsg());
236.404 + }
236.405 + return;
236.406 +}
236.407 +
236.408 +/**********************************************************************/
236.409 +/* * * SOLVER INTERFACE * * */
236.410 +/**********************************************************************/
236.411 +
236.412 +/*----------------------------------------------------------------------
236.413 +-- error - print error message and terminate model processing.
236.414 +--
236.415 +-- This routine formats and prints an error message and then terminates
236.416 +-- model processing. */
236.417 +
236.418 +void error(MPL *mpl, char *fmt, ...)
236.419 +{ va_list arg;
236.420 + char msg[4095+1];
236.421 + va_start(arg, fmt);
236.422 + vsprintf(msg, fmt, arg);
236.423 + xassert(strlen(msg) < sizeof(msg));
236.424 + va_end(arg);
236.425 + switch (mpl->phase)
236.426 + { case 1:
236.427 + case 2:
236.428 + /* translation phase */
236.429 + xprintf("%s:%d: %s\n",
236.430 + mpl->in_file == NULL ? "(unknown)" : mpl->in_file,
236.431 + mpl->line, msg);
236.432 + print_context(mpl);
236.433 + break;
236.434 + case 3:
236.435 + /* generation/postsolve phase */
236.436 + xprintf("%s:%d: %s\n",
236.437 + mpl->mod_file == NULL ? "(unknown)" : mpl->mod_file,
236.438 + mpl->stmt == NULL ? 0 : mpl->stmt->line, msg);
236.439 + break;
236.440 + default:
236.441 + xassert(mpl != mpl);
236.442 + }
236.443 + mpl->phase = 4;
236.444 + longjmp(mpl->jump, 1);
236.445 + /* no return */
236.446 +}
236.447 +
236.448 +/*----------------------------------------------------------------------
236.449 +-- warning - print warning message and continue model processing.
236.450 +--
236.451 +-- This routine formats and prints a warning message and returns to the
236.452 +-- calling program. */
236.453 +
236.454 +void warning(MPL *mpl, char *fmt, ...)
236.455 +{ va_list arg;
236.456 + char msg[4095+1];
236.457 + va_start(arg, fmt);
236.458 + vsprintf(msg, fmt, arg);
236.459 + xassert(strlen(msg) < sizeof(msg));
236.460 + va_end(arg);
236.461 + switch (mpl->phase)
236.462 + { case 1:
236.463 + case 2:
236.464 + /* translation phase */
236.465 + xprintf("%s:%d: warning: %s\n",
236.466 + mpl->in_file == NULL ? "(unknown)" : mpl->in_file,
236.467 + mpl->line, msg);
236.468 + break;
236.469 + case 3:
236.470 + /* generation/postsolve phase */
236.471 + xprintf("%s:%d: warning: %s\n",
236.472 + mpl->mod_file == NULL ? "(unknown)" : mpl->mod_file,
236.473 + mpl->stmt == NULL ? 0 : mpl->stmt->line, msg);
236.474 + break;
236.475 + default:
236.476 + xassert(mpl != mpl);
236.477 + }
236.478 + return;
236.479 +}
236.480 +
236.481 +/*----------------------------------------------------------------------
236.482 +-- mpl_initialize - create and initialize translator database.
236.483 +--
236.484 +-- *Synopsis*
236.485 +--
236.486 +-- #include "glpmpl.h"
236.487 +-- MPL *mpl_initialize(void);
236.488 +--
236.489 +-- *Description*
236.490 +--
236.491 +-- The routine mpl_initialize creates and initializes the database used
236.492 +-- by the GNU MathProg translator.
236.493 +--
236.494 +-- *Returns*
236.495 +--
236.496 +-- The routine returns a pointer to the database created. */
236.497 +
236.498 +MPL *mpl_initialize(void)
236.499 +{ MPL *mpl;
236.500 + mpl = xmalloc(sizeof(MPL));
236.501 + /* scanning segment */
236.502 + mpl->line = 0;
236.503 + mpl->c = 0;
236.504 + mpl->token = 0;
236.505 + mpl->imlen = 0;
236.506 + mpl->image = xcalloc(MAX_LENGTH+1, sizeof(char));
236.507 + mpl->image[0] = '\0';
236.508 + mpl->value = 0.0;
236.509 + mpl->b_token = 0;
236.510 + mpl->b_imlen = 0;
236.511 + mpl->b_image = xcalloc(MAX_LENGTH+1, sizeof(char));
236.512 + mpl->b_image[0] = '\0';
236.513 + mpl->b_value = 0.0;
236.514 + mpl->f_dots = 0;
236.515 + mpl->f_scan = 0;
236.516 + mpl->f_token = 0;
236.517 + mpl->f_imlen = 0;
236.518 + mpl->f_image = xcalloc(MAX_LENGTH+1, sizeof(char));
236.519 + mpl->f_image[0] = '\0';
236.520 + mpl->f_value = 0.0;
236.521 + mpl->context = xcalloc(CONTEXT_SIZE, sizeof(char));
236.522 + memset(mpl->context, ' ', CONTEXT_SIZE);
236.523 + mpl->c_ptr = 0;
236.524 + mpl->flag_d = 0;
236.525 + /* translating segment */
236.526 + mpl->pool = dmp_create_poolx(0);
236.527 + mpl->tree = avl_create_tree(avl_strcmp, NULL);
236.528 + mpl->model = NULL;
236.529 + mpl->flag_x = 0;
236.530 + mpl->as_within = 0;
236.531 + mpl->as_in = 0;
236.532 + mpl->as_binary = 0;
236.533 + mpl->flag_s = 0;
236.534 + /* common segment */
236.535 + mpl->strings = dmp_create_poolx(sizeof(STRING));
236.536 + mpl->symbols = dmp_create_poolx(sizeof(SYMBOL));
236.537 + mpl->tuples = dmp_create_poolx(sizeof(TUPLE));
236.538 + mpl->arrays = dmp_create_poolx(sizeof(ARRAY));
236.539 + mpl->members = dmp_create_poolx(sizeof(MEMBER));
236.540 + mpl->elemvars = dmp_create_poolx(sizeof(ELEMVAR));
236.541 + mpl->formulae = dmp_create_poolx(sizeof(FORMULA));
236.542 + mpl->elemcons = dmp_create_poolx(sizeof(ELEMCON));
236.543 + mpl->a_list = NULL;
236.544 + mpl->sym_buf = xcalloc(255+1, sizeof(char));
236.545 + mpl->sym_buf[0] = '\0';
236.546 + mpl->tup_buf = xcalloc(255+1, sizeof(char));
236.547 + mpl->tup_buf[0] = '\0';
236.548 + /* generating/postsolving segment */
236.549 + mpl->rand = rng_create_rand();
236.550 + mpl->flag_p = 0;
236.551 + mpl->stmt = NULL;
236.552 +#if 1 /* 11/II-2008 */
236.553 + mpl->dca = NULL;
236.554 +#endif
236.555 + mpl->m = 0;
236.556 + mpl->n = 0;
236.557 + mpl->row = NULL;
236.558 + mpl->col = NULL;
236.559 + /* input/output segment */
236.560 + mpl->in_fp = NULL;
236.561 + mpl->in_file = NULL;
236.562 + mpl->out_fp = NULL;
236.563 + mpl->out_file = NULL;
236.564 + mpl->prt_fp = NULL;
236.565 + mpl->prt_file = NULL;
236.566 + /* solver interface segment */
236.567 + if (setjmp(mpl->jump)) xassert(mpl != mpl);
236.568 + mpl->phase = 0;
236.569 + mpl->mod_file = NULL;
236.570 + mpl->mpl_buf = xcalloc(255+1, sizeof(char));
236.571 + mpl->mpl_buf[0] = '\0';
236.572 + return mpl;
236.573 +}
236.574 +
236.575 +/*----------------------------------------------------------------------
236.576 +-- mpl_read_model - read model section and optional data section.
236.577 +--
236.578 +-- *Synopsis*
236.579 +--
236.580 +-- #include "glpmpl.h"
236.581 +-- int mpl_read_model(MPL *mpl, char *file, int skip_data);
236.582 +--
236.583 +-- *Description*
236.584 +--
236.585 +-- The routine mpl_read_model reads model section and optionally data
236.586 +-- section, which may follow the model section, from the text file,
236.587 +-- whose name is the character string file, performs translating model
236.588 +-- statements and data blocks, and stores all the information in the
236.589 +-- translator database.
236.590 +--
236.591 +-- The parameter skip_data is a flag. If the input file contains the
236.592 +-- data section and this flag is set, the data section is not read as
236.593 +-- if there were no data section and a warning message is issued. This
236.594 +-- allows reading the data section from another input file.
236.595 +--
236.596 +-- This routine should be called once after the routine mpl_initialize
236.597 +-- and before other API routines.
236.598 +--
236.599 +-- *Returns*
236.600 +--
236.601 +-- The routine mpl_read_model returns one the following codes:
236.602 +--
236.603 +-- 1 - translation successful. The input text file contains only model
236.604 +-- section. In this case the calling program may call the routine
236.605 +-- mpl_read_data to read data section from another file.
236.606 +-- 2 - translation successful. The input text file contains both model
236.607 +-- and data section.
236.608 +-- 4 - processing failed due to some errors. In this case the calling
236.609 +-- program should call the routine mpl_terminate to terminate model
236.610 +-- processing. */
236.611 +
236.612 +int mpl_read_model(MPL *mpl, char *file, int skip_data)
236.613 +{ if (mpl->phase != 0)
236.614 + xfault("mpl_read_model: invalid call sequence\n");
236.615 + if (file == NULL)
236.616 + xfault("mpl_read_model: no input filename specified\n");
236.617 + /* set up error handler */
236.618 + if (setjmp(mpl->jump)) goto done;
236.619 + /* translate model section */
236.620 + mpl->phase = 1;
236.621 + xprintf("Reading model section from %s...\n", file);
236.622 + open_input(mpl, file);
236.623 + model_section(mpl);
236.624 + if (mpl->model == NULL)
236.625 + error(mpl, "empty model section not allowed");
236.626 + /* save name of the input text file containing model section for
236.627 + error diagnostics during the generation phase */
236.628 + mpl->mod_file = xcalloc(strlen(file)+1, sizeof(char));
236.629 + strcpy(mpl->mod_file, mpl->in_file);
236.630 + /* allocate content arrays for all model objects */
236.631 + alloc_content(mpl);
236.632 + /* optional data section may begin with the keyword 'data' */
236.633 + if (is_keyword(mpl, "data"))
236.634 + { if (skip_data)
236.635 + { warning(mpl, "data section ignored");
236.636 + goto skip;
236.637 + }
236.638 + mpl->flag_d = 1;
236.639 + get_token(mpl /* data */);
236.640 + if (mpl->token != T_SEMICOLON)
236.641 + error(mpl, "semicolon missing where expected");
236.642 + get_token(mpl /* ; */);
236.643 + /* translate data section */
236.644 + mpl->phase = 2;
236.645 + xprintf("Reading data section from %s...\n", file);
236.646 + data_section(mpl);
236.647 + }
236.648 + /* process end statement */
236.649 + end_statement(mpl);
236.650 +skip: xprintf("%d line%s were read\n",
236.651 + mpl->line, mpl->line == 1 ? "" : "s");
236.652 + close_input(mpl);
236.653 +done: /* return to the calling program */
236.654 + return mpl->phase;
236.655 +}
236.656 +
236.657 +/*----------------------------------------------------------------------
236.658 +-- mpl_read_data - read data section.
236.659 +--
236.660 +-- *Synopsis*
236.661 +--
236.662 +-- #include "glpmpl.h"
236.663 +-- int mpl_read_data(MPL *mpl, char *file);
236.664 +--
236.665 +-- *Description*
236.666 +--
236.667 +-- The routine mpl_read_data reads data section from the text file,
236.668 +-- whose name is the character string file, performs translating data
236.669 +-- blocks, and stores the data read in the translator database.
236.670 +--
236.671 +-- If this routine is used, it should be called once after the routine
236.672 +-- mpl_read_model and if the latter returned the code 1.
236.673 +--
236.674 +-- *Returns*
236.675 +--
236.676 +-- The routine mpl_read_data returns one of the following codes:
236.677 +--
236.678 +-- 2 - data section has been successfully processed.
236.679 +-- 4 - processing failed due to some errors. In this case the calling
236.680 +-- program should call the routine mpl_terminate to terminate model
236.681 +-- processing. */
236.682 +
236.683 +int mpl_read_data(MPL *mpl, char *file)
236.684 +#if 0 /* 02/X-2008 */
236.685 +{ if (mpl->phase != 1)
236.686 +#else
236.687 +{ if (!(mpl->phase == 1 || mpl->phase == 2))
236.688 +#endif
236.689 + xfault("mpl_read_data: invalid call sequence\n");
236.690 + if (file == NULL)
236.691 + xfault("mpl_read_data: no input filename specified\n");
236.692 + /* set up error handler */
236.693 + if (setjmp(mpl->jump)) goto done;
236.694 + /* process data section */
236.695 + mpl->phase = 2;
236.696 + xprintf("Reading data section from %s...\n", file);
236.697 + mpl->flag_d = 1;
236.698 + open_input(mpl, file);
236.699 + /* in this case the keyword 'data' is optional */
236.700 + if (is_literal(mpl, "data"))
236.701 + { get_token(mpl /* data */);
236.702 + if (mpl->token != T_SEMICOLON)
236.703 + error(mpl, "semicolon missing where expected");
236.704 + get_token(mpl /* ; */);
236.705 + }
236.706 + data_section(mpl);
236.707 + /* process end statement */
236.708 + end_statement(mpl);
236.709 + xprintf("%d line%s were read\n",
236.710 + mpl->line, mpl->line == 1 ? "" : "s");
236.711 + close_input(mpl);
236.712 +done: /* return to the calling program */
236.713 + return mpl->phase;
236.714 +}
236.715 +
236.716 +/*----------------------------------------------------------------------
236.717 +-- mpl_generate - generate model.
236.718 +--
236.719 +-- *Synopsis*
236.720 +--
236.721 +-- #include "glpmpl.h"
236.722 +-- int mpl_generate(MPL *mpl, char *file);
236.723 +--
236.724 +-- *Description*
236.725 +--
236.726 +-- The routine mpl_generate generates the model using its description
236.727 +-- stored in the translator database. This phase means generating all
236.728 +-- variables, constraints, and objectives, executing check and display
236.729 +-- statements, which precede the solve statement (if it is presented),
236.730 +-- and building the problem instance.
236.731 +--
236.732 +-- The character string file specifies the name of output text file, to
236.733 +-- which output produced by display statements should be written. It is
236.734 +-- allowed to specify NULL, in which case the output goes to stdout via
236.735 +-- the routine print.
236.736 +--
236.737 +-- This routine should be called once after the routine mpl_read_model
236.738 +-- or mpl_read_data and if one of the latters returned the code 2.
236.739 +--
236.740 +-- *Returns*
236.741 +--
236.742 +-- The routine mpl_generate returns one of the following codes:
236.743 +--
236.744 +-- 3 - model has been successfully generated. In this case the calling
236.745 +-- program may call other api routines to obtain components of the
236.746 +-- problem instance from the translator database.
236.747 +-- 4 - processing failed due to some errors. In this case the calling
236.748 +-- program should call the routine mpl_terminate to terminate model
236.749 +-- processing. */
236.750 +
236.751 +int mpl_generate(MPL *mpl, char *file)
236.752 +{ if (!(mpl->phase == 1 || mpl->phase == 2))
236.753 + xfault("mpl_generate: invalid call sequence\n");
236.754 + /* set up error handler */
236.755 + if (setjmp(mpl->jump)) goto done;
236.756 + /* generate model */
236.757 + mpl->phase = 3;
236.758 + open_output(mpl, file);
236.759 + generate_model(mpl);
236.760 + flush_output(mpl);
236.761 + /* build problem instance */
236.762 + build_problem(mpl);
236.763 + /* generation phase has been finished */
236.764 + xprintf("Model has been successfully generated\n");
236.765 +done: /* return to the calling program */
236.766 + return mpl->phase;
236.767 +}
236.768 +
236.769 +/*----------------------------------------------------------------------
236.770 +-- mpl_get_prob_name - obtain problem (model) name.
236.771 +--
236.772 +-- *Synopsis*
236.773 +--
236.774 +-- #include "glpmpl.h"
236.775 +-- char *mpl_get_prob_name(MPL *mpl);
236.776 +--
236.777 +-- *Returns*
236.778 +--
236.779 +-- The routine mpl_get_prob_name returns a pointer to internal buffer,
236.780 +-- which contains symbolic name of the problem (model).
236.781 +--
236.782 +-- *Note*
236.783 +--
236.784 +-- Currently MathProg has no feature to assign a symbolic name to the
236.785 +-- model. Therefore the routine mpl_get_prob_name tries to construct
236.786 +-- such name using the name of input text file containing model section,
236.787 +-- although this is not a good idea (due to portability problems). */
236.788 +
236.789 +char *mpl_get_prob_name(MPL *mpl)
236.790 +{ char *name = mpl->mpl_buf;
236.791 + char *file = mpl->mod_file;
236.792 + int k;
236.793 + if (mpl->phase != 3)
236.794 + xfault("mpl_get_prob_name: invalid call sequence\n");
236.795 + for (;;)
236.796 + { if (strchr(file, '/') != NULL)
236.797 + file = strchr(file, '/') + 1;
236.798 + else if (strchr(file, '\\') != NULL)
236.799 + file = strchr(file, '\\') + 1;
236.800 + else if (strchr(file, ':') != NULL)
236.801 + file = strchr(file, ':') + 1;
236.802 + else
236.803 + break;
236.804 + }
236.805 + for (k = 0; ; k++)
236.806 + { if (k == 255) break;
236.807 + if (!(isalnum((unsigned char)*file) || *file == '_')) break;
236.808 + name[k] = *file++;
236.809 + }
236.810 + if (k == 0)
236.811 + strcpy(name, "Unknown");
236.812 + else
236.813 + name[k] = '\0';
236.814 + xassert(strlen(name) <= 255);
236.815 + return name;
236.816 +}
236.817 +
236.818 +/*----------------------------------------------------------------------
236.819 +-- mpl_get_num_rows - determine number of rows.
236.820 +--
236.821 +-- *Synopsis*
236.822 +--
236.823 +-- #include "glpmpl.h"
236.824 +-- int mpl_get_num_rows(MPL *mpl);
236.825 +--
236.826 +-- *Returns*
236.827 +--
236.828 +-- The routine mpl_get_num_rows returns total number of rows in the
236.829 +-- problem, where each row is an individual constraint or objective. */
236.830 +
236.831 +int mpl_get_num_rows(MPL *mpl)
236.832 +{ if (mpl->phase != 3)
236.833 + xfault("mpl_get_num_rows: invalid call sequence\n");
236.834 + return mpl->m;
236.835 +}
236.836 +
236.837 +/*----------------------------------------------------------------------
236.838 +-- mpl_get_num_cols - determine number of columns.
236.839 +--
236.840 +-- *Synopsis*
236.841 +--
236.842 +-- #include "glpmpl.h"
236.843 +-- int mpl_get_num_cols(MPL *mpl);
236.844 +--
236.845 +-- *Returns*
236.846 +--
236.847 +-- The routine mpl_get_num_cols returns total number of columns in the
236.848 +-- problem, where each column is an individual variable. */
236.849 +
236.850 +int mpl_get_num_cols(MPL *mpl)
236.851 +{ if (mpl->phase != 3)
236.852 + xfault("mpl_get_num_cols: invalid call sequence\n");
236.853 + return mpl->n;
236.854 +}
236.855 +
236.856 +/*----------------------------------------------------------------------
236.857 +-- mpl_get_row_name - obtain row name.
236.858 +--
236.859 +-- *Synopsis*
236.860 +--
236.861 +-- #include "glpmpl.h"
236.862 +-- char *mpl_get_row_name(MPL *mpl, int i);
236.863 +--
236.864 +-- *Returns*
236.865 +--
236.866 +-- The routine mpl_get_row_name returns a pointer to internal buffer,
236.867 +-- which contains symbolic name of i-th row of the problem. */
236.868 +
236.869 +char *mpl_get_row_name(MPL *mpl, int i)
236.870 +{ char *name = mpl->mpl_buf, *t;
236.871 + int len;
236.872 + if (mpl->phase != 3)
236.873 + xfault("mpl_get_row_name: invalid call sequence\n");
236.874 + if (!(1 <= i && i <= mpl->m))
236.875 + xfault("mpl_get_row_name: i = %d; row number out of range\n",
236.876 + i);
236.877 + strcpy(name, mpl->row[i]->con->name);
236.878 + len = strlen(name);
236.879 + xassert(len <= 255);
236.880 + t = format_tuple(mpl, '[', mpl->row[i]->memb->tuple);
236.881 + while (*t)
236.882 + { if (len == 255) break;
236.883 + name[len++] = *t++;
236.884 + }
236.885 + name[len] = '\0';
236.886 + if (len == 255) strcpy(name+252, "...");
236.887 + xassert(strlen(name) <= 255);
236.888 + return name;
236.889 +}
236.890 +
236.891 +/*----------------------------------------------------------------------
236.892 +-- mpl_get_row_kind - determine row kind.
236.893 +--
236.894 +-- *Synopsis*
236.895 +--
236.896 +-- #include "glpmpl.h"
236.897 +-- int mpl_get_row_kind(MPL *mpl, int i);
236.898 +--
236.899 +-- *Returns*
236.900 +--
236.901 +-- The routine mpl_get_row_kind returns the kind of i-th row, which can
236.902 +-- be one of the following:
236.903 +--
236.904 +-- MPL_ST - non-free (constraint) row;
236.905 +-- MPL_MIN - free (objective) row to be minimized;
236.906 +-- MPL_MAX - free (objective) row to be maximized. */
236.907 +
236.908 +int mpl_get_row_kind(MPL *mpl, int i)
236.909 +{ int kind;
236.910 + if (mpl->phase != 3)
236.911 + xfault("mpl_get_row_kind: invalid call sequence\n");
236.912 + if (!(1 <= i && i <= mpl->m))
236.913 + xfault("mpl_get_row_kind: i = %d; row number out of range\n",
236.914 + i);
236.915 + switch (mpl->row[i]->con->type)
236.916 + { case A_CONSTRAINT:
236.917 + kind = MPL_ST; break;
236.918 + case A_MINIMIZE:
236.919 + kind = MPL_MIN; break;
236.920 + case A_MAXIMIZE:
236.921 + kind = MPL_MAX; break;
236.922 + default:
236.923 + xassert(mpl != mpl);
236.924 + }
236.925 + return kind;
236.926 +}
236.927 +
236.928 +/*----------------------------------------------------------------------
236.929 +-- mpl_get_row_bnds - obtain row bounds.
236.930 +--
236.931 +-- *Synopsis*
236.932 +--
236.933 +-- #include "glpmpl.h"
236.934 +-- int mpl_get_row_bnds(MPL *mpl, int i, double *lb, double *ub);
236.935 +--
236.936 +-- *Description*
236.937 +--
236.938 +-- The routine mpl_get_row_bnds stores lower and upper bounds of i-th
236.939 +-- row of the problem to the locations, which the parameters lb and ub
236.940 +-- point to, respectively. Besides the routine returns the type of the
236.941 +-- i-th row.
236.942 +--
236.943 +-- If some of the parameters lb and ub is NULL, the corresponding bound
236.944 +-- value is not stored.
236.945 +--
236.946 +-- Types and bounds have the following meaning:
236.947 +--
236.948 +-- Type Bounds Note
236.949 +-- -----------------------------------------------------------
236.950 +-- MPL_FR -inf < f(x) < +inf Free linear form
236.951 +-- MPL_LO lb <= f(x) < +inf Inequality f(x) >= lb
236.952 +-- MPL_UP -inf < f(x) <= ub Inequality f(x) <= ub
236.953 +-- MPL_DB lb <= f(x) <= ub Inequality lb <= f(x) <= ub
236.954 +-- MPL_FX f(x) = lb Equality f(x) = lb
236.955 +--
236.956 +-- where f(x) is the corresponding linear form of the i-th row.
236.957 +--
236.958 +-- If the row has no lower bound, *lb is set to zero; if the row has
236.959 +-- no upper bound, *ub is set to zero; and if the row is of fixed type,
236.960 +-- both *lb and *ub are set to the same value.
236.961 +--
236.962 +-- *Returns*
236.963 +--
236.964 +-- The routine returns the type of the i-th row as it is stated in the
236.965 +-- table above. */
236.966 +
236.967 +int mpl_get_row_bnds(MPL *mpl, int i, double *_lb, double *_ub)
236.968 +{ ELEMCON *con;
236.969 + int type;
236.970 + double lb, ub;
236.971 + if (mpl->phase != 3)
236.972 + xfault("mpl_get_row_bnds: invalid call sequence\n");
236.973 + if (!(1 <= i && i <= mpl->m))
236.974 + xfault("mpl_get_row_bnds: i = %d; row number out of range\n",
236.975 + i);
236.976 + con = mpl->row[i];
236.977 +#if 0 /* 21/VII-2006 */
236.978 + if (con->con->lbnd == NULL && con->con->ubnd == NULL)
236.979 + type = MPL_FR, lb = ub = 0.0;
236.980 + else if (con->con->ubnd == NULL)
236.981 + type = MPL_LO, lb = con->lbnd, ub = 0.0;
236.982 + else if (con->con->lbnd == NULL)
236.983 + type = MPL_UP, lb = 0.0, ub = con->ubnd;
236.984 + else if (con->con->lbnd != con->con->ubnd)
236.985 + type = MPL_DB, lb = con->lbnd, ub = con->ubnd;
236.986 + else
236.987 + type = MPL_FX, lb = ub = con->lbnd;
236.988 +#else
236.989 + lb = (con->con->lbnd == NULL ? -DBL_MAX : con->lbnd);
236.990 + ub = (con->con->ubnd == NULL ? +DBL_MAX : con->ubnd);
236.991 + if (lb == -DBL_MAX && ub == +DBL_MAX)
236.992 + type = MPL_FR, lb = ub = 0.0;
236.993 + else if (ub == +DBL_MAX)
236.994 + type = MPL_LO, ub = 0.0;
236.995 + else if (lb == -DBL_MAX)
236.996 + type = MPL_UP, lb = 0.0;
236.997 + else if (con->con->lbnd != con->con->ubnd)
236.998 + type = MPL_DB;
236.999 + else
236.1000 + type = MPL_FX;
236.1001 +#endif
236.1002 + if (_lb != NULL) *_lb = lb;
236.1003 + if (_ub != NULL) *_ub = ub;
236.1004 + return type;
236.1005 +}
236.1006 +
236.1007 +/*----------------------------------------------------------------------
236.1008 +-- mpl_get_mat_row - obtain row of the constraint matrix.
236.1009 +--
236.1010 +-- *Synopsis*
236.1011 +--
236.1012 +-- #include "glpmpl.h"
236.1013 +-- int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[]);
236.1014 +--
236.1015 +-- *Description*
236.1016 +--
236.1017 +-- The routine mpl_get_mat_row stores column indices and numeric values
236.1018 +-- of constraint coefficients for the i-th row to locations ndx[1], ...,
236.1019 +-- ndx[len] and val[1], ..., val[len], respectively, where 0 <= len <= n
236.1020 +-- is number of (structural) non-zero constraint coefficients, and n is
236.1021 +-- number of columns in the problem.
236.1022 +--
236.1023 +-- If the parameter ndx is NULL, column indices are not stored. If the
236.1024 +-- parameter val is NULL, numeric values are not stored.
236.1025 +--
236.1026 +-- Note that free rows may have constant terms, which are not part of
236.1027 +-- the constraint matrix and therefore not reported by this routine. The
236.1028 +-- constant term of a particular row can be obtained, if necessary, via
236.1029 +-- the routine mpl_get_row_c0.
236.1030 +--
236.1031 +-- *Returns*
236.1032 +--
236.1033 +-- The routine mpl_get_mat_row returns len, which is length of i-th row
236.1034 +-- of the constraint matrix (i.e. number of non-zero coefficients). */
236.1035 +
236.1036 +int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[])
236.1037 +{ FORMULA *term;
236.1038 + int len = 0;
236.1039 + if (mpl->phase != 3)
236.1040 + xfault("mpl_get_mat_row: invalid call sequence\n");
236.1041 + if (!(1 <= i && i <= mpl->m))
236.1042 + xfault("mpl_get_mat_row: i = %d; row number out of range\n",
236.1043 + i);
236.1044 + for (term = mpl->row[i]->form; term != NULL; term = term->next)
236.1045 + { xassert(term->var != NULL);
236.1046 + len++;
236.1047 + xassert(len <= mpl->n);
236.1048 + if (ndx != NULL) ndx[len] = term->var->j;
236.1049 + if (val != NULL) val[len] = term->coef;
236.1050 + }
236.1051 + return len;
236.1052 +}
236.1053 +
236.1054 +/*----------------------------------------------------------------------
236.1055 +-- mpl_get_row_c0 - obtain constant term of free row.
236.1056 +--
236.1057 +-- *Synopsis*
236.1058 +--
236.1059 +-- #include "glpmpl.h"
236.1060 +-- double mpl_get_row_c0(MPL *mpl, int i);
236.1061 +--
236.1062 +-- *Returns*
236.1063 +--
236.1064 +-- The routine mpl_get_row_c0 returns numeric value of constant term of
236.1065 +-- i-th row.
236.1066 +--
236.1067 +-- Note that only free rows may have non-zero constant terms. Therefore
236.1068 +-- if i-th row is not free, the routine returns zero. */
236.1069 +
236.1070 +double mpl_get_row_c0(MPL *mpl, int i)
236.1071 +{ ELEMCON *con;
236.1072 + double c0;
236.1073 + if (mpl->phase != 3)
236.1074 + xfault("mpl_get_row_c0: invalid call sequence\n");
236.1075 + if (!(1 <= i && i <= mpl->m))
236.1076 + xfault("mpl_get_row_c0: i = %d; row number out of range\n",
236.1077 + i);
236.1078 + con = mpl->row[i];
236.1079 + if (con->con->lbnd == NULL && con->con->ubnd == NULL)
236.1080 + c0 = - con->lbnd;
236.1081 + else
236.1082 + c0 = 0.0;
236.1083 + return c0;
236.1084 +}
236.1085 +
236.1086 +/*----------------------------------------------------------------------
236.1087 +-- mpl_get_col_name - obtain column name.
236.1088 +--
236.1089 +-- *Synopsis*
236.1090 +--
236.1091 +-- #include "glpmpl.h"
236.1092 +-- char *mpl_get_col_name(MPL *mpl, int j);
236.1093 +--
236.1094 +-- *Returns*
236.1095 +--
236.1096 +-- The routine mpl_get_col_name returns a pointer to internal buffer,
236.1097 +-- which contains symbolic name of j-th column of the problem. */
236.1098 +
236.1099 +char *mpl_get_col_name(MPL *mpl, int j)
236.1100 +{ char *name = mpl->mpl_buf, *t;
236.1101 + int len;
236.1102 + if (mpl->phase != 3)
236.1103 + xfault("mpl_get_col_name: invalid call sequence\n");
236.1104 + if (!(1 <= j && j <= mpl->n))
236.1105 + xfault("mpl_get_col_name: j = %d; column number out of range\n"
236.1106 + , j);
236.1107 + strcpy(name, mpl->col[j]->var->name);
236.1108 + len = strlen(name);
236.1109 + xassert(len <= 255);
236.1110 + t = format_tuple(mpl, '[', mpl->col[j]->memb->tuple);
236.1111 + while (*t)
236.1112 + { if (len == 255) break;
236.1113 + name[len++] = *t++;
236.1114 + }
236.1115 + name[len] = '\0';
236.1116 + if (len == 255) strcpy(name+252, "...");
236.1117 + xassert(strlen(name) <= 255);
236.1118 + return name;
236.1119 +}
236.1120 +
236.1121 +/*----------------------------------------------------------------------
236.1122 +-- mpl_get_col_kind - determine column kind.
236.1123 +--
236.1124 +-- *Synopsis*
236.1125 +--
236.1126 +-- #include "glpmpl.h"
236.1127 +-- int mpl_get_col_kind(MPL *mpl, int j);
236.1128 +--
236.1129 +-- *Returns*
236.1130 +--
236.1131 +-- The routine mpl_get_col_kind returns the kind of j-th column, which
236.1132 +-- can be one of the following:
236.1133 +--
236.1134 +-- MPL_NUM - continuous variable;
236.1135 +-- MPL_INT - integer variable;
236.1136 +-- MPL_BIN - binary variable.
236.1137 +--
236.1138 +-- Note that column kinds are defined independently on type and bounds
236.1139 +-- (reported by the routine mpl_get_col_bnds) of corresponding columns.
236.1140 +-- This means, in particular, that bounds of an integer column may be
236.1141 +-- fractional, or a binary column may have lower and upper bounds that
236.1142 +-- are not 0 and 1 (or it may have no lower/upper bound at all). */
236.1143 +
236.1144 +int mpl_get_col_kind(MPL *mpl, int j)
236.1145 +{ int kind;
236.1146 + if (mpl->phase != 3)
236.1147 + xfault("mpl_get_col_kind: invalid call sequence\n");
236.1148 + if (!(1 <= j && j <= mpl->n))
236.1149 + xfault("mpl_get_col_kind: j = %d; column number out of range\n"
236.1150 + , j);
236.1151 + switch (mpl->col[j]->var->type)
236.1152 + { case A_NUMERIC:
236.1153 + kind = MPL_NUM; break;
236.1154 + case A_INTEGER:
236.1155 + kind = MPL_INT; break;
236.1156 + case A_BINARY:
236.1157 + kind = MPL_BIN; break;
236.1158 + default:
236.1159 + xassert(mpl != mpl);
236.1160 + }
236.1161 + return kind;
236.1162 +}
236.1163 +
236.1164 +/*----------------------------------------------------------------------
236.1165 +-- mpl_get_col_bnds - obtain column bounds.
236.1166 +--
236.1167 +-- *Synopsis*
236.1168 +--
236.1169 +-- #include "glpmpl.h"
236.1170 +-- int mpl_get_col_bnds(MPL *mpl, int j, double *lb, double *ub);
236.1171 +--
236.1172 +-- *Description*
236.1173 +--
236.1174 +-- The routine mpl_get_col_bnds stores lower and upper bound of j-th
236.1175 +-- column of the problem to the locations, which the parameters lb and
236.1176 +-- ub point to, respectively. Besides the routine returns the type of
236.1177 +-- the j-th column.
236.1178 +--
236.1179 +-- If some of the parameters lb and ub is NULL, the corresponding bound
236.1180 +-- value is not stored.
236.1181 +--
236.1182 +-- Types and bounds have the following meaning:
236.1183 +--
236.1184 +-- Type Bounds Note
236.1185 +-- ------------------------------------------------------
236.1186 +-- MPL_FR -inf < x < +inf Free (unbounded) variable
236.1187 +-- MPL_LO lb <= x < +inf Variable with lower bound
236.1188 +-- MPL_UP -inf < x <= ub Variable with upper bound
236.1189 +-- MPL_DB lb <= x <= ub Double-bounded variable
236.1190 +-- MPL_FX x = lb Fixed variable
236.1191 +--
236.1192 +-- where x is individual variable corresponding to the j-th column.
236.1193 +--
236.1194 +-- If the column has no lower bound, *lb is set to zero; if the column
236.1195 +-- has no upper bound, *ub is set to zero; and if the column is of fixed
236.1196 +-- type, both *lb and *ub are set to the same value.
236.1197 +--
236.1198 +-- *Returns*
236.1199 +--
236.1200 +-- The routine returns the type of the j-th column as it is stated in
236.1201 +-- the table above. */
236.1202 +
236.1203 +int mpl_get_col_bnds(MPL *mpl, int j, double *_lb, double *_ub)
236.1204 +{ ELEMVAR *var;
236.1205 + int type;
236.1206 + double lb, ub;
236.1207 + if (mpl->phase != 3)
236.1208 + xfault("mpl_get_col_bnds: invalid call sequence\n");
236.1209 + if (!(1 <= j && j <= mpl->n))
236.1210 + xfault("mpl_get_col_bnds: j = %d; column number out of range\n"
236.1211 + , j);
236.1212 + var = mpl->col[j];
236.1213 +#if 0 /* 21/VII-2006 */
236.1214 + if (var->var->lbnd == NULL && var->var->ubnd == NULL)
236.1215 + type = MPL_FR, lb = ub = 0.0;
236.1216 + else if (var->var->ubnd == NULL)
236.1217 + type = MPL_LO, lb = var->lbnd, ub = 0.0;
236.1218 + else if (var->var->lbnd == NULL)
236.1219 + type = MPL_UP, lb = 0.0, ub = var->ubnd;
236.1220 + else if (var->var->lbnd != var->var->ubnd)
236.1221 + type = MPL_DB, lb = var->lbnd, ub = var->ubnd;
236.1222 + else
236.1223 + type = MPL_FX, lb = ub = var->lbnd;
236.1224 +#else
236.1225 + lb = (var->var->lbnd == NULL ? -DBL_MAX : var->lbnd);
236.1226 + ub = (var->var->ubnd == NULL ? +DBL_MAX : var->ubnd);
236.1227 + if (lb == -DBL_MAX && ub == +DBL_MAX)
236.1228 + type = MPL_FR, lb = ub = 0.0;
236.1229 + else if (ub == +DBL_MAX)
236.1230 + type = MPL_LO, ub = 0.0;
236.1231 + else if (lb == -DBL_MAX)
236.1232 + type = MPL_UP, lb = 0.0;
236.1233 + else if (var->var->lbnd != var->var->ubnd)
236.1234 + type = MPL_DB;
236.1235 + else
236.1236 + type = MPL_FX;
236.1237 +#endif
236.1238 + if (_lb != NULL) *_lb = lb;
236.1239 + if (_ub != NULL) *_ub = ub;
236.1240 + return type;
236.1241 +}
236.1242 +
236.1243 +/*----------------------------------------------------------------------
236.1244 +-- mpl_has_solve_stmt - check if model has solve statement.
236.1245 +--
236.1246 +-- *Synopsis*
236.1247 +--
236.1248 +-- #include "glpmpl.h"
236.1249 +-- int mpl_has_solve_stmt(MPL *mpl);
236.1250 +--
236.1251 +-- *Returns*
236.1252 +--
236.1253 +-- If the model has the solve statement, the routine returns non-zero,
236.1254 +-- otherwise zero is returned. */
236.1255 +
236.1256 +int mpl_has_solve_stmt(MPL *mpl)
236.1257 +{ if (mpl->phase != 3)
236.1258 + xfault("mpl_has_solve_stmt: invalid call sequence\n");
236.1259 + return mpl->flag_s;
236.1260 +}
236.1261 +
236.1262 +#if 1 /* 15/V-2010 */
236.1263 +void mpl_put_row_soln(MPL *mpl, int i, int stat, double prim,
236.1264 + double dual)
236.1265 +{ /* store row (constraint/objective) solution components */
236.1266 + xassert(mpl->phase == 3);
236.1267 + xassert(1 <= i && i <= mpl->m);
236.1268 + mpl->row[i]->stat = stat;
236.1269 + mpl->row[i]->prim = prim;
236.1270 + mpl->row[i]->dual = dual;
236.1271 + return;
236.1272 +}
236.1273 +#endif
236.1274 +
236.1275 +#if 1 /* 15/V-2010 */
236.1276 +void mpl_put_col_soln(MPL *mpl, int j, int stat, double prim,
236.1277 + double dual)
236.1278 +{ /* store column (variable) solution components */
236.1279 + xassert(mpl->phase == 3);
236.1280 + xassert(1 <= j && j <= mpl->n);
236.1281 + mpl->col[j]->stat = stat;
236.1282 + mpl->col[j]->prim = prim;
236.1283 + mpl->col[j]->dual = dual;
236.1284 + return;
236.1285 +}
236.1286 +#endif
236.1287 +
236.1288 +#if 0 /* 15/V-2010 */
236.1289 +/*----------------------------------------------------------------------
236.1290 +-- mpl_put_col_value - store column value.
236.1291 +--
236.1292 +-- *Synopsis*
236.1293 +--
236.1294 +-- #include "glpmpl.h"
236.1295 +-- void mpl_put_col_value(MPL *mpl, int j, double val);
236.1296 +--
236.1297 +-- *Description*
236.1298 +--
236.1299 +-- The routine mpl_put_col_value stores numeric value of j-th column
236.1300 +-- into the translator database. It is assumed that the column value is
236.1301 +-- provided by the solver. */
236.1302 +
236.1303 +void mpl_put_col_value(MPL *mpl, int j, double val)
236.1304 +{ if (mpl->phase != 3)
236.1305 + xfault("mpl_put_col_value: invalid call sequence\n");
236.1306 + if (!(1 <= j && j <= mpl->n))
236.1307 + xfault(
236.1308 + "mpl_put_col_value: j = %d; column number out of range\n", j);
236.1309 + mpl->col[j]->prim = val;
236.1310 + return;
236.1311 +}
236.1312 +#endif
236.1313 +
236.1314 +/*----------------------------------------------------------------------
236.1315 +-- mpl_postsolve - postsolve model.
236.1316 +--
236.1317 +-- *Synopsis*
236.1318 +--
236.1319 +-- #include "glpmpl.h"
236.1320 +-- int mpl_postsolve(MPL *mpl);
236.1321 +--
236.1322 +-- *Description*
236.1323 +--
236.1324 +-- The routine mpl_postsolve performs postsolving of the model using
236.1325 +-- its description stored in the translator database. This phase means
236.1326 +-- executing statements, which follow the solve statement.
236.1327 +--
236.1328 +-- If this routine is used, it should be called once after the routine
236.1329 +-- mpl_generate and if the latter returned the code 3.
236.1330 +--
236.1331 +-- *Returns*
236.1332 +--
236.1333 +-- The routine mpl_postsolve returns one of the following codes:
236.1334 +--
236.1335 +-- 3 - model has been successfully postsolved.
236.1336 +-- 4 - processing failed due to some errors. In this case the calling
236.1337 +-- program should call the routine mpl_terminate to terminate model
236.1338 +-- processing. */
236.1339 +
236.1340 +int mpl_postsolve(MPL *mpl)
236.1341 +{ if (!(mpl->phase == 3 && !mpl->flag_p))
236.1342 + xfault("mpl_postsolve: invalid call sequence\n");
236.1343 + /* set up error handler */
236.1344 + if (setjmp(mpl->jump)) goto done;
236.1345 + /* perform postsolving */
236.1346 + postsolve_model(mpl);
236.1347 + flush_output(mpl);
236.1348 + /* postsolving phase has been finished */
236.1349 + xprintf("Model has been successfully processed\n");
236.1350 +done: /* return to the calling program */
236.1351 + return mpl->phase;
236.1352 +}
236.1353 +
236.1354 +/*----------------------------------------------------------------------
236.1355 +-- mpl_terminate - free all resources used by translator.
236.1356 +--
236.1357 +-- *Synopsis*
236.1358 +--
236.1359 +-- #include "glpmpl.h"
236.1360 +-- void mpl_terminate(MPL *mpl);
236.1361 +--
236.1362 +-- *Description*
236.1363 +--
236.1364 +-- The routine mpl_terminate frees all the resources used by the GNU
236.1365 +-- MathProg translator. */
236.1366 +
236.1367 +void mpl_terminate(MPL *mpl)
236.1368 +{ if (setjmp(mpl->jump)) xassert(mpl != mpl);
236.1369 + switch (mpl->phase)
236.1370 + { case 0:
236.1371 + case 1:
236.1372 + case 2:
236.1373 + case 3:
236.1374 + /* there were no errors; clean the model content */
236.1375 + clean_model(mpl);
236.1376 + xassert(mpl->a_list == NULL);
236.1377 +#if 1 /* 11/II-2008 */
236.1378 + xassert(mpl->dca == NULL);
236.1379 +#endif
236.1380 + break;
236.1381 + case 4:
236.1382 + /* model processing has been finished due to error; delete
236.1383 + search trees, which may be created for some arrays */
236.1384 + { ARRAY *a;
236.1385 + for (a = mpl->a_list; a != NULL; a = a->next)
236.1386 + if (a->tree != NULL) avl_delete_tree(a->tree);
236.1387 + }
236.1388 +#if 1 /* 11/II-2008 */
236.1389 + free_dca(mpl);
236.1390 +#endif
236.1391 + break;
236.1392 + default:
236.1393 + xassert(mpl != mpl);
236.1394 + }
236.1395 + /* delete the translator database */
236.1396 + xfree(mpl->image);
236.1397 + xfree(mpl->b_image);
236.1398 + xfree(mpl->f_image);
236.1399 + xfree(mpl->context);
236.1400 + dmp_delete_pool(mpl->pool);
236.1401 + avl_delete_tree(mpl->tree);
236.1402 + dmp_delete_pool(mpl->strings);
236.1403 + dmp_delete_pool(mpl->symbols);
236.1404 + dmp_delete_pool(mpl->tuples);
236.1405 + dmp_delete_pool(mpl->arrays);
236.1406 + dmp_delete_pool(mpl->members);
236.1407 + dmp_delete_pool(mpl->elemvars);
236.1408 + dmp_delete_pool(mpl->formulae);
236.1409 + dmp_delete_pool(mpl->elemcons);
236.1410 + xfree(mpl->sym_buf);
236.1411 + xfree(mpl->tup_buf);
236.1412 + rng_delete_rand(mpl->rand);
236.1413 + if (mpl->row != NULL) xfree(mpl->row);
236.1414 + if (mpl->col != NULL) xfree(mpl->col);
236.1415 + if (mpl->in_fp != NULL) xfclose(mpl->in_fp);
236.1416 + if (mpl->out_fp != NULL && mpl->out_fp != (void *)stdout)
236.1417 + xfclose(mpl->out_fp);
236.1418 + if (mpl->out_file != NULL) xfree(mpl->out_file);
236.1419 + if (mpl->prt_fp != NULL) xfclose(mpl->prt_fp);
236.1420 + if (mpl->prt_file != NULL) xfree(mpl->prt_file);
236.1421 + if (mpl->mod_file != NULL) xfree(mpl->mod_file);
236.1422 + xfree(mpl->mpl_buf);
236.1423 + xfree(mpl);
236.1424 + return;
236.1425 +}
236.1426 +
236.1427 +/* eof */
237.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
237.2 +++ b/src/glpmpl05.c Mon Dec 06 13:09:21 2010 +0100
237.3 @@ -0,0 +1,562 @@
237.4 +/* glpmpl05.c */
237.5 +
237.6 +/***********************************************************************
237.7 +* This code is part of GLPK (GNU Linear Programming Kit).
237.8 +*
237.9 +* Authors: Andrew Makhorin <mao@gnu.org>
237.10 +* Heinrich Schuchardt <xypron.glpk@gmx.de>
237.11 +*
237.12 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
237.13 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
237.14 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
237.15 +* E-mail: <mao@gnu.org>.
237.16 +*
237.17 +* GLPK is free software: you can redistribute it and/or modify it
237.18 +* under the terms of the GNU General Public License as published by
237.19 +* the Free Software Foundation, either version 3 of the License, or
237.20 +* (at your option) any later version.
237.21 +*
237.22 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
237.23 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
237.24 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
237.25 +* License for more details.
237.26 +*
237.27 +* You should have received a copy of the GNU General Public License
237.28 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
237.29 +***********************************************************************/
237.30 +
237.31 +#define _GLPSTD_STDIO
237.32 +#define _GLPSTD_TIME
237.33 +#include "glpmpl.h"
237.34 +
237.35 +double fn_gmtime(MPL *mpl)
237.36 +{ /* obtain the current calendar time (UTC) */
237.37 + time_t timer;
237.38 + struct tm *tm;
237.39 + int j;
237.40 + time(&timer);
237.41 + if (timer == (time_t)(-1))
237.42 +err: error(mpl, "gmtime(); unable to obtain current calendar time");
237.43 + tm = gmtime(&timer);
237.44 + if (tm == NULL) goto err;
237.45 + j = jday(tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
237.46 + if (j < 0) goto err;
237.47 + return (((double)(j - jday(1, 1, 1970)) * 24.0 +
237.48 + (double)tm->tm_hour) * 60.0 + (double)tm->tm_min) * 60.0 +
237.49 + (double)tm->tm_sec;
237.50 +}
237.51 +
237.52 +static char *week[] = { "Monday", "Tuesday", "Wednesday", "Thursday",
237.53 + "Friday", "Saturday", "Sunday" };
237.54 +
237.55 +static char *moon[] = { "January", "February", "March", "April", "May",
237.56 + "June", "July", "August", "September", "October", "November",
237.57 + "December" };
237.58 +
237.59 +static void error1(MPL *mpl, const char *str, const char *s,
237.60 + const char *fmt, const char *f, const char *msg)
237.61 +{ xprintf("Input string passed to str2time:\n");
237.62 + xprintf("%s\n", str);
237.63 + xprintf("%*s\n", (s - str) + 1, "^");
237.64 + xprintf("Format string passed to str2time:\n");
237.65 + xprintf("%s\n", fmt);
237.66 + xprintf("%*s\n", (f - fmt) + 1, "^");
237.67 + error(mpl, "%s", msg);
237.68 + /* no return */
237.69 +}
237.70 +
237.71 +double fn_str2time(MPL *mpl, const char *str, const char *fmt)
237.72 +{ /* convert character string to the calendar time */
237.73 + int j, year, month, day, hh, mm, ss, zone;
237.74 + const char *s, *f;
237.75 + year = month = day = hh = mm = ss = -1, zone = INT_MAX;
237.76 + s = str;
237.77 + for (f = fmt; *f != '\0'; f++)
237.78 + { if (*f == '%')
237.79 + { f++;
237.80 + if (*f == 'b' || *f == 'h')
237.81 + { /* the abbreviated month name */
237.82 + int k;
237.83 + char *name;
237.84 + if (month >= 0)
237.85 + error1(mpl, str, s, fmt, f, "month multiply specified"
237.86 + );
237.87 + while (*s == ' ') s++;
237.88 + for (month = 1; month <= 12; month++)
237.89 + { name = moon[month-1];
237.90 + for (k = 0; k <= 2; k++)
237.91 + { if (toupper((unsigned char)s[k]) !=
237.92 + toupper((unsigned char)name[k])) goto next;
237.93 + }
237.94 + s += 3;
237.95 + for (k = 3; name[k] != '\0'; k++)
237.96 + { if (toupper((unsigned char)*s) !=
237.97 + toupper((unsigned char)name[k])) break;
237.98 + s++;
237.99 + }
237.100 + break;
237.101 +next: ;
237.102 + }
237.103 + if (month > 12)
237.104 + error1(mpl, str, s, fmt, f, "abbreviated month name m"
237.105 + "issing or invalid");
237.106 + }
237.107 + else if (*f == 'd')
237.108 + { /* the day of the month as a decimal number (01..31) */
237.109 + if (day >= 0)
237.110 + error1(mpl, str, s, fmt, f, "day multiply specified");
237.111 + while (*s == ' ') s++;
237.112 + if (!('0' <= *s && *s <= '9'))
237.113 + error1(mpl, str, s, fmt, f, "day missing or invalid");
237.114 + day = (*s++) - '0';
237.115 + if ('0' <= *s && *s <= '9')
237.116 + day = 10 * day + ((*s++) - '0');
237.117 + if (!(1 <= day && day <= 31))
237.118 + error1(mpl, str, s, fmt, f, "day out of range");
237.119 + }
237.120 + else if (*f == 'H')
237.121 + { /* the hour as a decimal number, using a 24-hour clock
237.122 + (00..23) */
237.123 + if (hh >= 0)
237.124 + error1(mpl, str, s, fmt, f, "hour multiply specified")
237.125 + ;
237.126 + while (*s == ' ') s++;
237.127 + if (!('0' <= *s && *s <= '9'))
237.128 + error1(mpl, str, s, fmt, f, "hour missing or invalid")
237.129 + ;
237.130 + hh = (*s++) - '0';
237.131 + if ('0' <= *s && *s <= '9')
237.132 + hh = 10 * hh + ((*s++) - '0');
237.133 + if (!(0 <= hh && hh <= 23))
237.134 + error1(mpl, str, s, fmt, f, "hour out of range");
237.135 + }
237.136 + else if (*f == 'm')
237.137 + { /* the month as a decimal number (01..12) */
237.138 + if (month >= 0)
237.139 + error1(mpl, str, s, fmt, f, "month multiply specified"
237.140 + );
237.141 + while (*s == ' ') s++;
237.142 + if (!('0' <= *s && *s <= '9'))
237.143 + error1(mpl, str, s, fmt, f, "month missing or invalid"
237.144 + );
237.145 + month = (*s++) - '0';
237.146 + if ('0' <= *s && *s <= '9')
237.147 + month = 10 * month + ((*s++) - '0');
237.148 + if (!(1 <= month && month <= 12))
237.149 + error1(mpl, str, s, fmt, f, "month out of range");
237.150 + }
237.151 + else if (*f == 'M')
237.152 + { /* the minute as a decimal number (00..59) */
237.153 + if (mm >= 0)
237.154 + error1(mpl, str, s, fmt, f, "minute multiply specifie"
237.155 + "d");
237.156 + while (*s == ' ') s++;
237.157 + if (!('0' <= *s && *s <= '9'))
237.158 + error1(mpl, str, s, fmt, f, "minute missing or invali"
237.159 + "d");
237.160 + mm = (*s++) - '0';
237.161 + if ('0' <= *s && *s <= '9')
237.162 + mm = 10 * mm + ((*s++) - '0');
237.163 + if (!(0 <= mm && mm <= 59))
237.164 + error1(mpl, str, s, fmt, f, "minute out of range");
237.165 + }
237.166 + else if (*f == 'S')
237.167 + { /* the second as a decimal number (00..60) */
237.168 + if (ss >= 0)
237.169 + error1(mpl, str, s, fmt, f, "second multiply specifie"
237.170 + "d");
237.171 + while (*s == ' ') s++;
237.172 + if (!('0' <= *s && *s <= '9'))
237.173 + error1(mpl, str, s, fmt, f, "second missing or invali"
237.174 + "d");
237.175 + ss = (*s++) - '0';
237.176 + if ('0' <= *s && *s <= '9')
237.177 + ss = 10 * ss + ((*s++) - '0');
237.178 + if (!(0 <= ss && ss <= 60))
237.179 + error1(mpl, str, s, fmt, f, "second out of range");
237.180 + }
237.181 + else if (*f == 'y')
237.182 + { /* the year without a century as a decimal number
237.183 + (00..99); the values 00 to 68 mean the years 2000 to
237.184 + 2068 while the values 69 to 99 mean the years 1969 to
237.185 + 1999 */
237.186 + if (year >= 0)
237.187 + error1(mpl, str, s, fmt, f, "year multiply specified")
237.188 + ;
237.189 + while (*s == ' ') s++;
237.190 + if (!('0' <= *s && *s <= '9'))
237.191 + error1(mpl, str, s, fmt, f, "year missing or invalid")
237.192 + ;
237.193 + year = (*s++) - '0';
237.194 + if ('0' <= *s && *s <= '9')
237.195 + year = 10 * year + ((*s++) - '0');
237.196 + year += (year >= 69 ? 1900 : 2000);
237.197 + }
237.198 + else if (*f == 'Y')
237.199 + { /* the year as a decimal number, using the Gregorian
237.200 + calendar */
237.201 + if (year >= 0)
237.202 + error1(mpl, str, s, fmt, f, "year multiply specified")
237.203 + ;
237.204 + while (*s == ' ') s++;
237.205 + if (!('0' <= *s && *s <= '9'))
237.206 + error1(mpl, str, s, fmt, f, "year missing or invalid")
237.207 + ;
237.208 + year = 0;
237.209 + for (j = 1; j <= 4; j++)
237.210 + { if (!('0' <= *s && *s <= '9')) break;
237.211 + year = 10 * year + ((*s++) - '0');
237.212 + }
237.213 + if (!(1 <= year && year <= 4000))
237.214 + error1(mpl, str, s, fmt, f, "year out of range");
237.215 + }
237.216 + else if (*f == 'z')
237.217 + { /* time zone offset in the form zhhmm */
237.218 + int z, hh, mm;
237.219 + if (zone != INT_MAX)
237.220 + error1(mpl, str, s, fmt, f, "time zone offset multipl"
237.221 + "y specified");
237.222 + while (*s == ' ') s++;
237.223 + if (*s == 'Z')
237.224 + { z = hh = mm = 0, s++;
237.225 + goto skip;
237.226 + }
237.227 + if (*s == '+')
237.228 + z = +1, s++;
237.229 + else if (*s == '-')
237.230 + z = -1, s++;
237.231 + else
237.232 + error1(mpl, str, s, fmt, f, "time zone offset sign mi"
237.233 + "ssing");
237.234 + hh = 0;
237.235 + for (j = 1; j <= 2; j++)
237.236 + { if (!('0' <= *s && *s <= '9'))
237.237 +err1: error1(mpl, str, s, fmt, f, "time zone offset valu"
237.238 + "e incomplete or invalid");
237.239 + hh = 10 * hh + ((*s++) - '0');
237.240 + }
237.241 + if (hh > 23)
237.242 +err2: error1(mpl, str, s, fmt, f, "time zone offset value o"
237.243 + "ut of range");
237.244 + if (*s == ':')
237.245 + { s++;
237.246 + if (!('0' <= *s && *s <= '9')) goto err1;
237.247 + }
237.248 + mm = 0;
237.249 + if (!('0' <= *s && *s <= '9')) goto skip;
237.250 + for (j = 1; j <= 2; j++)
237.251 + { if (!('0' <= *s && *s <= '9')) goto err1;
237.252 + mm = 10 * mm + ((*s++) - '0');
237.253 + }
237.254 + if (mm > 59) goto err2;
237.255 +skip: zone = z * (60 * hh + mm);
237.256 + }
237.257 + else if (*f == '%')
237.258 + { /* literal % character */
237.259 + goto test;
237.260 + }
237.261 + else
237.262 + error1(mpl, str, s, fmt, f, "invalid conversion specifie"
237.263 + "r");
237.264 + }
237.265 + else if (*f == ' ')
237.266 + ;
237.267 + else
237.268 +test: { /* check a matching character in the input string */
237.269 + if (*s != *f)
237.270 + error1(mpl, str, s, fmt, f, "character mismatch");
237.271 + s++;
237.272 + }
237.273 + }
237.274 + if (year < 0) year = 1970;
237.275 + if (month < 0) month = 1;
237.276 + if (day < 0) day = 1;
237.277 + if (hh < 0) hh = 0;
237.278 + if (mm < 0) mm = 0;
237.279 + if (ss < 0) ss = 0;
237.280 + if (zone == INT_MAX) zone = 0;
237.281 + j = jday(day, month, year);
237.282 + xassert(j >= 0);
237.283 + return (((double)(j - jday(1, 1, 1970)) * 24.0 + (double)hh) *
237.284 + 60.0 + (double)mm) * 60.0 + (double)ss - 60.0 * (double)zone;
237.285 +}
237.286 +
237.287 +static void error2(MPL *mpl, const char *fmt, const char *f,
237.288 + const char *msg)
237.289 +{ xprintf("Format string passed to time2str:\n");
237.290 + xprintf("%s\n", fmt);
237.291 + xprintf("%*s\n", (f - fmt) + 1, "^");
237.292 + error(mpl, "%s", msg);
237.293 + /* no return */
237.294 +}
237.295 +
237.296 +static int weekday(int j)
237.297 +{ /* determine weekday number (1 = Mon, ..., 7 = Sun) */
237.298 + return (j + jday(1, 1, 1970)) % 7 + 1;
237.299 +}
237.300 +
237.301 +static int firstday(int year)
237.302 +{ /* determine the first day of the first week for a specified year
237.303 + according to ISO 8601 */
237.304 + int j;
237.305 + /* if 1 January is Monday, Tuesday, Wednesday or Thursday, it is
237.306 + in week 01; if 1 January is Friday, Saturday or Sunday, it is
237.307 + in week 52 or 53 of the previous year */
237.308 + j = jday(1, 1, year) - jday(1, 1, 1970);
237.309 + switch (weekday(j))
237.310 + { case 1: /* 1 Jan is Mon */ j += 0; break;
237.311 + case 2: /* 1 Jan is Tue */ j -= 1; break;
237.312 + case 3: /* 1 Jan is Wed */ j -= 2; break;
237.313 + case 4: /* 1 Jan is Thu */ j -= 3; break;
237.314 + case 5: /* 1 Jan is Fri */ j += 3; break;
237.315 + case 6: /* 1 Jan is Sat */ j += 2; break;
237.316 + case 7: /* 1 Jan is Sun */ j += 1; break;
237.317 + default: xassert(j != j);
237.318 + }
237.319 + /* the first day of the week must be Monday */
237.320 + xassert(weekday(j) == 1);
237.321 + return j;
237.322 +}
237.323 +
237.324 +void fn_time2str(MPL *mpl, char *str, double t, const char *fmt)
237.325 +{ /* convert the calendar time to character string */
237.326 + int j, year, month, day, hh, mm, ss, len;
237.327 + double temp;
237.328 + const char *f;
237.329 + char buf[MAX_LENGTH+1];
237.330 + if (!(-62135596800.0 <= t && t <= 64092211199.0))
237.331 + error(mpl, "time2str(%.*g,...); argument out of range",
237.332 + DBL_DIG, t);
237.333 + t = floor(t + 0.5);
237.334 + temp = fabs(t) / 86400.0;
237.335 + j = (int)floor(temp);
237.336 + if (t < 0.0)
237.337 + { if (temp == floor(temp))
237.338 + j = - j;
237.339 + else
237.340 + j = - (j + 1);
237.341 + }
237.342 + xassert(jdate(j + jday(1, 1, 1970), &day, &month, &year) == 0);
237.343 + ss = (int)(t - 86400.0 * (double)j);
237.344 + xassert(0 <= ss && ss < 86400);
237.345 + mm = ss / 60, ss %= 60;
237.346 + hh = mm / 60, mm %= 60;
237.347 + len = 0;
237.348 + for (f = fmt; *f != '\0'; f++)
237.349 + { if (*f == '%')
237.350 + { f++;
237.351 + if (*f == 'a')
237.352 + { /* the abbreviated weekday name */
237.353 + memcpy(buf, week[weekday(j)-1], 3), buf[3] = '\0';
237.354 + }
237.355 + else if (*f == 'A')
237.356 + { /* the full weekday name */
237.357 + strcpy(buf, week[weekday(j)-1]);
237.358 + }
237.359 + else if (*f == 'b' || *f == 'h')
237.360 + { /* the abbreviated month name */
237.361 + memcpy(buf, moon[month-1], 3), buf[3] = '\0';
237.362 + }
237.363 + else if (*f == 'B')
237.364 + { /* the full month name */
237.365 + strcpy(buf, moon[month-1]);
237.366 + }
237.367 + else if (*f == 'C')
237.368 + { /* the century of the year */
237.369 + sprintf(buf, "%02d", year / 100);
237.370 + }
237.371 + else if (*f == 'd')
237.372 + { /* the day of the month as a decimal number (01..31) */
237.373 + sprintf(buf, "%02d", day);
237.374 + }
237.375 + else if (*f == 'D')
237.376 + { /* the date using the format %m/%d/%y */
237.377 + sprintf(buf, "%02d/%02d/%02d", month, day, year % 100);
237.378 + }
237.379 + else if (*f == 'e')
237.380 + { /* the day of the month like with %d, but padded with
237.381 + blank (1..31) */
237.382 + sprintf(buf, "%2d", day);
237.383 + }
237.384 + else if (*f == 'F')
237.385 + { /* the date using the format %Y-%m-%d */
237.386 + sprintf(buf, "%04d-%02d-%02d", year, month, day);
237.387 + }
237.388 + else if (*f == 'g')
237.389 + { /* the year corresponding to the ISO week number, but
237.390 + without the century (range 00 through 99); this has
237.391 + the same format and value as %y, except that if the
237.392 + ISO week number (see %V) belongs to the previous or
237.393 + next year, that year is used instead */
237.394 + int iso;
237.395 + if (j < firstday(year))
237.396 + iso = year - 1;
237.397 + else if (j < firstday(year + 1))
237.398 + iso = year;
237.399 + else
237.400 + iso = year + 1;
237.401 + sprintf(buf, "%02d", iso % 100);
237.402 + }
237.403 + else if (*f == 'G')
237.404 + { /* the year corresponding to the ISO week number; this
237.405 + has the same format and value as %Y, excepth that if
237.406 + the ISO week number (see %V) belongs to the previous
237.407 + or next year, that year is used instead */
237.408 + int iso;
237.409 + if (j < firstday(year))
237.410 + iso = year - 1;
237.411 + else if (j < firstday(year + 1))
237.412 + iso = year;
237.413 + else
237.414 + iso = year + 1;
237.415 + sprintf(buf, "%04d", iso);
237.416 + }
237.417 + else if (*f == 'H')
237.418 + { /* the hour as a decimal number, using a 24-hour clock
237.419 + (00..23) */
237.420 + sprintf(buf, "%02d", hh);
237.421 + }
237.422 + else if (*f == 'I')
237.423 + { /* the hour as a decimal number, using a 12-hour clock
237.424 + (01..12) */
237.425 + sprintf(buf, "%02d",
237.426 + hh == 0 ? 12 : hh <= 12 ? hh : hh - 12);
237.427 + }
237.428 + else if (*f == 'j')
237.429 + { /* the day of the year as a decimal number (001..366) */
237.430 + sprintf(buf, "%03d",
237.431 + jday(day, month, year) - jday(1, 1, year) + 1);
237.432 + }
237.433 + else if (*f == 'k')
237.434 + { /* the hour as a decimal number, using a 24-hour clock
237.435 + like %H, but padded with blank (0..23) */
237.436 + sprintf(buf, "%2d", hh);
237.437 + }
237.438 + else if (*f == 'l')
237.439 + { /* the hour as a decimal number, using a 12-hour clock
237.440 + like %I, but padded with blank (1..12) */
237.441 + sprintf(buf, "%2d",
237.442 + hh == 0 ? 12 : hh <= 12 ? hh : hh - 12);
237.443 + }
237.444 + else if (*f == 'm')
237.445 + { /* the month as a decimal number (01..12) */
237.446 + sprintf(buf, "%02d", month);
237.447 + }
237.448 + else if (*f == 'M')
237.449 + { /* the minute as a decimal number (00..59) */
237.450 + sprintf(buf, "%02d", mm);
237.451 + }
237.452 + else if (*f == 'p')
237.453 + { /* either AM or PM, according to the given time value;
237.454 + noon is treated as PM and midnight as AM */
237.455 + strcpy(buf, hh <= 11 ? "AM" : "PM");
237.456 + }
237.457 + else if (*f == 'P')
237.458 + { /* either am or pm, according to the given time value;
237.459 + noon is treated as pm and midnight as am */
237.460 + strcpy(buf, hh <= 11 ? "am" : "pm");
237.461 + }
237.462 + else if (*f == 'r')
237.463 + { /* the calendar time using the format %I:%M:%S %p */
237.464 + sprintf(buf, "%02d:%02d:%02d %s",
237.465 + hh == 0 ? 12 : hh <= 12 ? hh : hh - 12,
237.466 + mm, ss, hh <= 11 ? "AM" : "PM");
237.467 + }
237.468 + else if (*f == 'R')
237.469 + { /* the hour and minute using the format %H:%M */
237.470 + sprintf(buf, "%02d:%02d", hh, mm);
237.471 + }
237.472 + else if (*f == 'S')
237.473 + { /* the second as a decimal number (00..59) */
237.474 + sprintf(buf, "%02d", ss);
237.475 + }
237.476 + else if (*f == 'T')
237.477 + { /* the time of day using the format %H:%M:%S */
237.478 + sprintf(buf, "%02d:%02d:%02d", hh, mm, ss);
237.479 + }
237.480 + else if (*f == 'u')
237.481 + { /* the day of the week as a decimal number (1..7),
237.482 + Monday being 1 */
237.483 + sprintf(buf, "%d", weekday(j));
237.484 + }
237.485 + else if (*f == 'U')
237.486 + { /* the week number of the current year as a decimal
237.487 + number (range 00 through 53), starting with the first
237.488 + Sunday as the first day of the first week; days
237.489 + preceding the first Sunday in the year are considered
237.490 + to be in week 00 */
237.491 +#if 1 /* 09/I-2009 */
237.492 +#undef sun
237.493 +/* causes compilation error in SunOS */
237.494 +#endif
237.495 + int sun;
237.496 + /* sun = the first Sunday of the year */
237.497 + sun = jday(1, 1, year) - jday(1, 1, 1970);
237.498 + sun += (7 - weekday(sun));
237.499 + sprintf(buf, "%02d", (j + 7 - sun) / 7);
237.500 + }
237.501 + else if (*f == 'V')
237.502 + { /* the ISO week number as a decimal number (range 01
237.503 + through 53); ISO weeks start with Monday and end with
237.504 + Sunday; week 01 of a year is the first week which has
237.505 + the majority of its days in that year; week 01 of
237.506 + a year can contain days from the previous year; the
237.507 + week before week 01 of a year is the last week (52 or
237.508 + 53) of the previous year even if it contains days
237.509 + from the new year */
237.510 + int iso;
237.511 + if (j < firstday(year))
237.512 + iso = j - firstday(year - 1);
237.513 + else if (j < firstday(year + 1))
237.514 + iso = j - firstday(year);
237.515 + else
237.516 + iso = j - firstday(year + 1);
237.517 + sprintf(buf, "%02d", iso / 7 + 1);
237.518 + }
237.519 + else if (*f == 'w')
237.520 + { /* the day of the week as a decimal number (0..6),
237.521 + Sunday being 0 */
237.522 + sprintf(buf, "%d", weekday(j) % 7);
237.523 + }
237.524 + else if (*f == 'W')
237.525 + { /* the week number of the current year as a decimal
237.526 + number (range 00 through 53), starting with the first
237.527 + Monday as the first day of the first week; days
237.528 + preceding the first Monday in the year are considered
237.529 + to be in week 00 */
237.530 + int mon;
237.531 + /* mon = the first Monday of the year */
237.532 + mon = jday(1, 1, year) - jday(1, 1, 1970);
237.533 + mon += (8 - weekday(mon)) % 7;
237.534 + sprintf(buf, "%02d", (j + 7 - mon) / 7);
237.535 + }
237.536 + else if (*f == 'y')
237.537 + { /* the year without a century as a decimal number
237.538 + (00..99) */
237.539 + sprintf(buf, "%02d", year % 100);
237.540 + }
237.541 + else if (*f == 'Y')
237.542 + { /* the year as a decimal number, using the Gregorian
237.543 + calendar */
237.544 + sprintf(buf, "%04d", year);
237.545 + }
237.546 + else if (*f == '%')
237.547 + { /* a literal % character */
237.548 + buf[0] = '%', buf[1] = '\0';
237.549 + }
237.550 + else
237.551 + error2(mpl, fmt, f, "invalid conversion specifier");
237.552 + }
237.553 + else
237.554 + buf[0] = *f, buf[1] = '\0';
237.555 + if (len + strlen(buf) > MAX_LENGTH)
237.556 + error(mpl, "time2str; output string length exceeds %d chara"
237.557 + "cters", MAX_LENGTH);
237.558 + memcpy(str+len, buf, strlen(buf));
237.559 + len += strlen(buf);
237.560 + }
237.561 + str[len] = '\0';
237.562 + return;
237.563 +}
237.564 +
237.565 +/* eof */
238.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
238.2 +++ b/src/glpmpl06.c Mon Dec 06 13:09:21 2010 +0100
238.3 @@ -0,0 +1,1002 @@
238.4 +/* glpmpl06.c */
238.5 +
238.6 +/***********************************************************************
238.7 +* This code is part of GLPK (GNU Linear Programming Kit).
238.8 +*
238.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
238.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
238.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
238.12 +* E-mail: <mao@gnu.org>.
238.13 +*
238.14 +* GLPK is free software: you can redistribute it and/or modify it
238.15 +* under the terms of the GNU General Public License as published by
238.16 +* the Free Software Foundation, either version 3 of the License, or
238.17 +* (at your option) any later version.
238.18 +*
238.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
238.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
238.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
238.22 +* License for more details.
238.23 +*
238.24 +* You should have received a copy of the GNU General Public License
238.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
238.26 +***********************************************************************/
238.27 +
238.28 +#define _GLPSTD_ERRNO
238.29 +#define _GLPSTD_STDIO
238.30 +#include "glpmpl.h"
238.31 +#include "glpsql.h"
238.32 +
238.33 +/**********************************************************************/
238.34 +
238.35 +#define CSV_FIELD_MAX 50
238.36 +/* maximal number of fields in record */
238.37 +
238.38 +#define CSV_FDLEN_MAX 100
238.39 +/* maximal field length */
238.40 +
238.41 +struct csv
238.42 +{ /* comma-separated values file */
238.43 + int mode;
238.44 + /* 'R' = reading; 'W' = writing */
238.45 + char *fname;
238.46 + /* name of csv file */
238.47 + FILE *fp;
238.48 + /* stream assigned to csv file */
238.49 + jmp_buf jump;
238.50 + /* address for non-local go to in case of error */
238.51 + int count;
238.52 + /* record count */
238.53 + /*--------------------------------------------------------------*/
238.54 + /* used only for input csv file */
238.55 + int c;
238.56 + /* current character or EOF */
238.57 + int what;
238.58 + /* current marker: */
238.59 +#define CSV_EOF 0 /* end-of-file */
238.60 +#define CSV_EOR 1 /* end-of-record */
238.61 +#define CSV_NUM 2 /* floating-point number */
238.62 +#define CSV_STR 3 /* character string */
238.63 + char field[CSV_FDLEN_MAX+1];
238.64 + /* current field just read */
238.65 + int nf;
238.66 + /* number of fields in the csv file */
238.67 + int ref[1+CSV_FIELD_MAX];
238.68 + /* ref[k] = k', if k-th field of the csv file corresponds to
238.69 + k'-th field in the table statement; if ref[k] = 0, k-th field
238.70 + of the csv file is ignored */
238.71 +#if 1 /* 01/VI-2010 */
238.72 + int nskip;
238.73 + /* number of comment records preceding the header record */
238.74 +#endif
238.75 +};
238.76 +
238.77 +#undef read_char
238.78 +
238.79 +static void read_char(struct csv *csv)
238.80 +{ /* read character from csv data file */
238.81 + int c;
238.82 + xassert(csv->c != EOF);
238.83 + if (csv->c == '\n') csv->count++;
238.84 +loop: c = fgetc(csv->fp);
238.85 + if (ferror(csv->fp))
238.86 + { xprintf("%s:%d: read error - %s\n", csv->fname, csv->count,
238.87 + strerror(errno));
238.88 + longjmp(csv->jump, 0);
238.89 + }
238.90 + if (feof(csv->fp))
238.91 + { if (csv->c == '\n')
238.92 + { csv->count--;
238.93 + c = EOF;
238.94 + }
238.95 + else
238.96 + { xprintf("%s:%d: warning: missing final end-of-line\n",
238.97 + csv->fname, csv->count);
238.98 + c = '\n';
238.99 + }
238.100 + }
238.101 + else if (c == '\r')
238.102 + goto loop;
238.103 + else if (c == '\n')
238.104 + ;
238.105 + else if (iscntrl(c))
238.106 + { xprintf("%s:%d: invalid control character 0x%02X\n",
238.107 + csv->fname, csv->count, c);
238.108 + longjmp(csv->jump, 0);
238.109 + }
238.110 + csv->c = c;
238.111 + return;
238.112 +}
238.113 +
238.114 +static void read_field(struct csv *csv)
238.115 +{ /* read field from csv data file */
238.116 + /* check for end of file */
238.117 + if (csv->c == EOF)
238.118 + { csv->what = CSV_EOF;
238.119 + strcpy(csv->field, "EOF");
238.120 + goto done;
238.121 + }
238.122 + /* check for end of record */
238.123 + if (csv->c == '\n')
238.124 + { csv->what = CSV_EOR;
238.125 + strcpy(csv->field, "EOR");
238.126 + read_char(csv);
238.127 + if (csv->c == ',')
238.128 +err1: { xprintf("%s:%d: empty field not allowed\n", csv->fname,
238.129 + csv->count);
238.130 + longjmp(csv->jump, 0);
238.131 + }
238.132 + if (csv->c == '\n')
238.133 + { xprintf("%s:%d: empty record not allowed\n", csv->fname,
238.134 + csv->count);
238.135 + longjmp(csv->jump, 0);
238.136 + }
238.137 +#if 1 /* 01/VI-2010 */
238.138 + /* skip comment records; may appear only before the very first
238.139 + record containing field names */
238.140 + if (csv->c == '#' && csv->count == 1)
238.141 + { while (csv->c == '#')
238.142 + { while (csv->c != '\n')
238.143 + read_char(csv);
238.144 + read_char(csv);
238.145 + csv->nskip++;
238.146 + }
238.147 + }
238.148 +#endif
238.149 + goto done;
238.150 + }
238.151 + /* skip comma before next field */
238.152 + if (csv->c == ',')
238.153 + read_char(csv);
238.154 + /* read field */
238.155 + if (csv->c == '\'' || csv->c == '"')
238.156 + { /* read a field enclosed in quotes */
238.157 + int quote = csv->c, len = 0;
238.158 + csv->what = CSV_STR;
238.159 + /* skip opening quote */
238.160 + read_char(csv);
238.161 + /* read field characters within quotes */
238.162 + for (;;)
238.163 + { /* check for closing quote and read it */
238.164 + if (csv->c == quote)
238.165 + { read_char(csv);
238.166 + if (csv->c == quote)
238.167 + ;
238.168 + else if (csv->c == ',' || csv->c == '\n')
238.169 + break;
238.170 + else
238.171 + { xprintf("%s:%d: invalid field\n", csv->fname,
238.172 + csv->count);
238.173 + longjmp(csv->jump, 0);
238.174 + }
238.175 + }
238.176 + /* check the current field length */
238.177 + if (len == CSV_FDLEN_MAX)
238.178 +err2: { xprintf("%s:%d: field too long\n", csv->fname,
238.179 + csv->count);
238.180 + longjmp(csv->jump, 0);
238.181 + }
238.182 + /* add the current character to the field */
238.183 + csv->field[len++] = (char)csv->c;
238.184 + /* read the next character */
238.185 + read_char(csv);
238.186 + }
238.187 + /* the field has been read */
238.188 + if (len == 0) goto err1;
238.189 + csv->field[len] = '\0';
238.190 + }
238.191 + else
238.192 + { /* read a field not enclosed in quotes */
238.193 + int len = 0;
238.194 + double temp;
238.195 + csv->what = CSV_NUM;
238.196 + while (!(csv->c == ',' || csv->c == '\n'))
238.197 + { /* quotes within the field are not allowed */
238.198 + if (csv->c == '\'' || csv->c == '"')
238.199 + { xprintf("%s:%d: invalid use of single or double quote wi"
238.200 + "thin field\n", csv->fname, csv->count);
238.201 + longjmp(csv->jump, 0);
238.202 + }
238.203 + /* check the current field length */
238.204 + if (len == CSV_FDLEN_MAX) goto err2;
238.205 + /* add the current character to the field */
238.206 + csv->field[len++] = (char)csv->c;
238.207 + /* read the next character */
238.208 + read_char(csv);
238.209 + }
238.210 + /* the field has been read */
238.211 + if (len == 0) goto err1;
238.212 + csv->field[len] = '\0';
238.213 + /* check the field type */
238.214 + if (str2num(csv->field, &temp)) csv->what = CSV_STR;
238.215 + }
238.216 +done: return;
238.217 +}
238.218 +
238.219 +static struct csv *csv_open_file(TABDCA *dca, int mode)
238.220 +{ /* open csv data file */
238.221 + struct csv *csv;
238.222 + /* create control structure */
238.223 + csv = xmalloc(sizeof(struct csv));
238.224 + csv->mode = mode;
238.225 + csv->fname = NULL;
238.226 + csv->fp = NULL;
238.227 + if (setjmp(csv->jump)) goto fail;
238.228 + csv->count = 0;
238.229 + csv->c = '\n';
238.230 + csv->what = 0;
238.231 + csv->field[0] = '\0';
238.232 + csv->nf = 0;
238.233 + /* try to open the csv data file */
238.234 + if (mpl_tab_num_args(dca) < 2)
238.235 + { xprintf("csv_driver: file name not specified\n");
238.236 + longjmp(csv->jump, 0);
238.237 + }
238.238 + csv->fname = xmalloc(strlen(mpl_tab_get_arg(dca, 2))+1);
238.239 + strcpy(csv->fname, mpl_tab_get_arg(dca, 2));
238.240 + if (mode == 'R')
238.241 + { /* open the file for reading */
238.242 + int k;
238.243 + csv->fp = fopen(csv->fname, "r");
238.244 + if (csv->fp == NULL)
238.245 + { xprintf("csv_driver: unable to open %s - %s\n",
238.246 + csv->fname, strerror(errno));
238.247 + longjmp(csv->jump, 0);
238.248 + }
238.249 +#if 1 /* 01/VI-2010 */
238.250 + csv->nskip = 0;
238.251 +#endif
238.252 + /* skip fake new-line */
238.253 + read_field(csv);
238.254 + xassert(csv->what == CSV_EOR);
238.255 + /* read field names */
238.256 + xassert(csv->nf == 0);
238.257 + for (;;)
238.258 + { read_field(csv);
238.259 + if (csv->what == CSV_EOR)
238.260 + break;
238.261 + if (csv->what != CSV_STR)
238.262 + { xprintf("%s:%d: invalid field name\n", csv->fname,
238.263 + csv->count);
238.264 + longjmp(csv->jump, 0);
238.265 + }
238.266 + if (csv->nf == CSV_FIELD_MAX)
238.267 + { xprintf("%s:%d: too many fields\n", csv->fname,
238.268 + csv->count);
238.269 + longjmp(csv->jump, 0);
238.270 + }
238.271 + csv->nf++;
238.272 + /* find corresponding field in the table statement */
238.273 + for (k = mpl_tab_num_flds(dca); k >= 1; k--)
238.274 + { if (strcmp(mpl_tab_get_name(dca, k), csv->field) == 0)
238.275 + break;
238.276 + }
238.277 + csv->ref[csv->nf] = k;
238.278 + }
238.279 + /* find dummy RECNO field in the table statement */
238.280 + for (k = mpl_tab_num_flds(dca); k >= 1; k--)
238.281 + if (strcmp(mpl_tab_get_name(dca, k), "RECNO") == 0) break;
238.282 + csv->ref[0] = k;
238.283 + }
238.284 + else if (mode == 'W')
238.285 + { /* open the file for writing */
238.286 + int k, nf;
238.287 + csv->fp = fopen(csv->fname, "w");
238.288 + if (csv->fp == NULL)
238.289 + { xprintf("csv_driver: unable to create %s - %s\n",
238.290 + csv->fname, strerror(errno));
238.291 + longjmp(csv->jump, 0);
238.292 + }
238.293 + /* write field names */
238.294 + nf = mpl_tab_num_flds(dca);
238.295 + for (k = 1; k <= nf; k++)
238.296 + fprintf(csv->fp, "%s%c", mpl_tab_get_name(dca, k),
238.297 + k < nf ? ',' : '\n');
238.298 + csv->count++;
238.299 + }
238.300 + else
238.301 + xassert(mode != mode);
238.302 + /* the file has been open */
238.303 + return csv;
238.304 +fail: /* the file cannot be open */
238.305 + if (csv->fname != NULL) xfree(csv->fname);
238.306 + if (csv->fp != NULL) fclose(csv->fp);
238.307 + xfree(csv);
238.308 + return NULL;
238.309 +}
238.310 +
238.311 +static int csv_read_record(TABDCA *dca, struct csv *csv)
238.312 +{ /* read next record from csv data file */
238.313 + int k, ret = 0;
238.314 + xassert(csv->mode == 'R');
238.315 + if (setjmp(csv->jump))
238.316 + { ret = 1;
238.317 + goto done;
238.318 + }
238.319 + /* read dummy RECNO field */
238.320 + if (csv->ref[0] > 0)
238.321 +#if 0 /* 01/VI-2010 */
238.322 + mpl_tab_set_num(dca, csv->ref[0], csv->count-1);
238.323 +#else
238.324 + mpl_tab_set_num(dca, csv->ref[0], csv->count-csv->nskip-1);
238.325 +#endif
238.326 + /* read fields */
238.327 + for (k = 1; k <= csv->nf; k++)
238.328 + { read_field(csv);
238.329 + if (csv->what == CSV_EOF)
238.330 + { /* end-of-file reached */
238.331 + xassert(k == 1);
238.332 + ret = -1;
238.333 + goto done;
238.334 + }
238.335 + else if (csv->what == CSV_EOR)
238.336 + { /* end-of-record reached */
238.337 + int lack = csv->nf - k + 1;
238.338 + if (lack == 1)
238.339 + xprintf("%s:%d: one field missing\n", csv->fname,
238.340 + csv->count);
238.341 + else
238.342 + xprintf("%s:%d: %d fields missing\n", csv->fname,
238.343 + csv->count, lack);
238.344 + longjmp(csv->jump, 0);
238.345 + }
238.346 + else if (csv->what == CSV_NUM)
238.347 + { /* floating-point number */
238.348 + if (csv->ref[k] > 0)
238.349 + { double num;
238.350 + xassert(str2num(csv->field, &num) == 0);
238.351 + mpl_tab_set_num(dca, csv->ref[k], num);
238.352 + }
238.353 + }
238.354 + else if (csv->what == CSV_STR)
238.355 + { /* character string */
238.356 + if (csv->ref[k] > 0)
238.357 + mpl_tab_set_str(dca, csv->ref[k], csv->field);
238.358 + }
238.359 + else
238.360 + xassert(csv != csv);
238.361 + }
238.362 + /* now there must be NL */
238.363 + read_field(csv);
238.364 + xassert(csv->what != CSV_EOF);
238.365 + if (csv->what != CSV_EOR)
238.366 + { xprintf("%s:%d: too many fields\n", csv->fname, csv->count);
238.367 + longjmp(csv->jump, 0);
238.368 + }
238.369 +done: return ret;
238.370 +}
238.371 +
238.372 +static int csv_write_record(TABDCA *dca, struct csv *csv)
238.373 +{ /* write next record to csv data file */
238.374 + int k, nf, ret = 0;
238.375 + const char *c;
238.376 + xassert(csv->mode == 'W');
238.377 + nf = mpl_tab_num_flds(dca);
238.378 + for (k = 1; k <= nf; k++)
238.379 + { switch (mpl_tab_get_type(dca, k))
238.380 + { case 'N':
238.381 + fprintf(csv->fp, "%.*g", DBL_DIG,
238.382 + mpl_tab_get_num(dca, k));
238.383 + break;
238.384 + case 'S':
238.385 + fputc('"', csv->fp);
238.386 + for (c = mpl_tab_get_str(dca, k); *c != '\0'; c++)
238.387 + { if (*c == '"')
238.388 + fputc('"', csv->fp), fputc('"', csv->fp);
238.389 + else
238.390 + fputc(*c, csv->fp);
238.391 + }
238.392 + fputc('"', csv->fp);
238.393 + break;
238.394 + default:
238.395 + xassert(dca != dca);
238.396 + }
238.397 + fputc(k < nf ? ',' : '\n', csv->fp);
238.398 + }
238.399 + csv->count++;
238.400 + if (ferror(csv->fp))
238.401 + { xprintf("%s:%d: write error - %s\n", csv->fname, csv->count,
238.402 + strerror(errno));
238.403 + ret = 1;
238.404 + }
238.405 + return ret;
238.406 +}
238.407 +
238.408 +static int csv_close_file(TABDCA *dca, struct csv *csv)
238.409 +{ /* close csv data file */
238.410 + int ret = 0;
238.411 + xassert(dca == dca);
238.412 + if (csv->mode == 'W')
238.413 + { fflush(csv->fp);
238.414 + if (ferror(csv->fp))
238.415 + { xprintf("%s:%d: write error - %s\n", csv->fname,
238.416 + csv->count, strerror(errno));
238.417 + ret = 1;
238.418 + }
238.419 + }
238.420 + xfree(csv->fname);
238.421 + fclose(csv->fp);
238.422 + xfree(csv);
238.423 + return ret;
238.424 +}
238.425 +
238.426 +/**********************************************************************/
238.427 +
238.428 +#define DBF_FIELD_MAX 50
238.429 +/* maximal number of fields in record */
238.430 +
238.431 +#define DBF_FDLEN_MAX 100
238.432 +/* maximal field length */
238.433 +
238.434 +struct dbf
238.435 +{ /* xBASE data file */
238.436 + int mode;
238.437 + /* 'R' = reading; 'W' = writing */
238.438 + char *fname;
238.439 + /* name of xBASE file */
238.440 + FILE *fp;
238.441 + /* stream assigned to xBASE file */
238.442 + jmp_buf jump;
238.443 + /* address for non-local go to in case of error */
238.444 + int offset;
238.445 + /* offset of a byte to be read next */
238.446 + int count;
238.447 + /* record count */
238.448 + int nf;
238.449 + /* number of fields */
238.450 + int ref[1+DBF_FIELD_MAX];
238.451 + /* ref[k] = k', if k-th field of the csv file corresponds to
238.452 + k'-th field in the table statement; if ref[k] = 0, k-th field
238.453 + of the csv file is ignored */
238.454 + int type[1+DBF_FIELD_MAX];
238.455 + /* type[k] is type of k-th field */
238.456 + int len[1+DBF_FIELD_MAX];
238.457 + /* len[k] is length of k-th field */
238.458 + int prec[1+DBF_FIELD_MAX];
238.459 + /* prec[k] is precision of k-th field */
238.460 +};
238.461 +
238.462 +static int read_byte(struct dbf *dbf)
238.463 +{ /* read byte from xBASE data file */
238.464 + int b;
238.465 + b = fgetc(dbf->fp);
238.466 + if (ferror(dbf->fp))
238.467 + { xprintf("%s:0x%X: read error - %s\n", dbf->fname,
238.468 + dbf->offset, strerror(errno));
238.469 + longjmp(dbf->jump, 0);
238.470 + }
238.471 + if (feof(dbf->fp))
238.472 + { xprintf("%s:0x%X: unexpected end of file\n", dbf->fname,
238.473 + dbf->offset);
238.474 + longjmp(dbf->jump, 0);
238.475 + }
238.476 + xassert(0x00 <= b && b <= 0xFF);
238.477 + dbf->offset++;
238.478 + return b;
238.479 +}
238.480 +
238.481 +static void read_header(TABDCA *dca, struct dbf *dbf)
238.482 +{ /* read xBASE data file header */
238.483 + int b, j, k, recl;
238.484 + char name[10+1];
238.485 + /* (ignored) */
238.486 + for (j = 1; j <= 10; j++)
238.487 + read_byte(dbf);
238.488 + /* length of each record, in bytes */
238.489 + recl = read_byte(dbf);
238.490 + recl += read_byte(dbf) << 8;
238.491 + /* (ignored) */
238.492 + for (j = 1; j <= 20; j++)
238.493 + read_byte(dbf);
238.494 + /* field descriptor array */
238.495 + xassert(dbf->nf == 0);
238.496 + for (;;)
238.497 + { /* check for end of array */
238.498 + b = read_byte(dbf);
238.499 + if (b == 0x0D) break;
238.500 + if (dbf->nf == DBF_FIELD_MAX)
238.501 + { xprintf("%s:0x%X: too many fields\n", dbf->fname,
238.502 + dbf->offset);
238.503 + longjmp(dbf->jump, 0);
238.504 + }
238.505 + dbf->nf++;
238.506 + /* field name */
238.507 + name[0] = (char)b;
238.508 + for (j = 1; j < 10; j++)
238.509 + { b = read_byte(dbf);
238.510 + name[j] = (char)b;
238.511 + }
238.512 + name[10] = '\0';
238.513 + b = read_byte(dbf);
238.514 + if (b != 0x00)
238.515 + { xprintf("%s:0x%X: invalid field name\n", dbf->fname,
238.516 + dbf->offset);
238.517 + longjmp(dbf->jump, 0);
238.518 + }
238.519 + /* find corresponding field in the table statement */
238.520 + for (k = mpl_tab_num_flds(dca); k >= 1; k--)
238.521 + if (strcmp(mpl_tab_get_name(dca, k), name) == 0) break;
238.522 + dbf->ref[dbf->nf] = k;
238.523 + /* field type */
238.524 + b = read_byte(dbf);
238.525 + if (!(b == 'C' || b == 'N'))
238.526 + { xprintf("%s:0x%X: invalid field type\n", dbf->fname,
238.527 + dbf->offset);
238.528 + longjmp(dbf->jump, 0);
238.529 + }
238.530 + dbf->type[dbf->nf] = b;
238.531 + /* (ignored) */
238.532 + for (j = 1; j <= 4; j++)
238.533 + read_byte(dbf);
238.534 + /* field length */
238.535 + b = read_byte(dbf);
238.536 + if (b == 0)
238.537 + { xprintf("%s:0x%X: invalid field length\n", dbf->fname,
238.538 + dbf->offset);
238.539 + longjmp(dbf->jump, 0);
238.540 + }
238.541 + if (b > DBF_FDLEN_MAX)
238.542 + { xprintf("%s:0x%X: field too long\n", dbf->fname,
238.543 + dbf->offset);
238.544 + longjmp(dbf->jump, 0);
238.545 + }
238.546 + dbf->len[dbf->nf] = b;
238.547 + recl -= b;
238.548 + /* (ignored) */
238.549 + for (j = 1; j <= 15; j++)
238.550 + read_byte(dbf);
238.551 + }
238.552 + if (recl != 1)
238.553 + { xprintf("%s:0x%X: invalid file header\n", dbf->fname,
238.554 + dbf->offset);
238.555 + longjmp(dbf->jump, 0);
238.556 + }
238.557 + /* find dummy RECNO field in the table statement */
238.558 + for (k = mpl_tab_num_flds(dca); k >= 1; k--)
238.559 + if (strcmp(mpl_tab_get_name(dca, k), "RECNO") == 0) break;
238.560 + dbf->ref[0] = k;
238.561 + return;
238.562 +}
238.563 +
238.564 +static void parse_third_arg(TABDCA *dca, struct dbf *dbf)
238.565 +{ /* parse xBASE file format (third argument) */
238.566 + int j, k, temp;
238.567 + const char *arg;
238.568 + dbf->nf = mpl_tab_num_flds(dca);
238.569 + arg = mpl_tab_get_arg(dca, 3), j = 0;
238.570 + for (k = 1; k <= dbf->nf; k++)
238.571 + { /* parse specification of k-th field */
238.572 + if (arg[j] == '\0')
238.573 + { xprintf("xBASE driver: field %s: specification missing\n",
238.574 + mpl_tab_get_name(dca, k));
238.575 + longjmp(dbf->jump, 0);
238.576 + }
238.577 + /* parse field type */
238.578 + if (arg[j] == 'C' || arg[j] == 'N')
238.579 + dbf->type[k] = arg[j], j++;
238.580 + else
238.581 + { xprintf("xBASE driver: field %s: invalid field type\n",
238.582 + mpl_tab_get_name(dca, k));
238.583 + longjmp(dbf->jump, 0);
238.584 + }
238.585 + /* check for left parenthesis */
238.586 + if (arg[j] == '(')
238.587 + j++;
238.588 + else
238.589 +err: { xprintf("xBASE driver: field %s: invalid field format\n",
238.590 + mpl_tab_get_name(dca, k));
238.591 + longjmp(dbf->jump, 0);
238.592 + }
238.593 + /* parse field length */
238.594 + temp = 0;
238.595 + while (isdigit(arg[j]))
238.596 + { if (temp > DBF_FDLEN_MAX) break;
238.597 + temp = 10 * temp + (arg[j] - '0'), j++;
238.598 + }
238.599 + if (!(1 <= temp && temp <= DBF_FDLEN_MAX))
238.600 + { xprintf("xBASE driver: field %s: invalid field length\n",
238.601 + mpl_tab_get_name(dca, k));
238.602 + longjmp(dbf->jump, 0);
238.603 + }
238.604 + dbf->len[k] = temp;
238.605 + /* parse optional field precision */
238.606 + if (dbf->type[k] == 'N' && arg[j] == ',')
238.607 + { j++;
238.608 + temp = 0;
238.609 + while (isdigit(arg[j]))
238.610 + { if (temp > dbf->len[k]) break;
238.611 + temp = 10 * temp + (arg[j] - '0'), j++;
238.612 + }
238.613 + if (temp > dbf->len[k])
238.614 + { xprintf("xBASE driver: field %s: invalid field precision"
238.615 + "\n", mpl_tab_get_name(dca, k));
238.616 + longjmp(dbf->jump, 0);
238.617 + }
238.618 + dbf->prec[k] = temp;
238.619 + }
238.620 + else
238.621 + dbf->prec[k] = 0;
238.622 + /* check for right parenthesis */
238.623 + if (arg[j] == ')')
238.624 + j++;
238.625 + else
238.626 + goto err;
238.627 + }
238.628 + /* ignore other specifications */
238.629 + return;
238.630 +}
238.631 +
238.632 +static void write_byte(struct dbf *dbf, int b)
238.633 +{ /* write byte to xBASE data file */
238.634 + fputc(b, dbf->fp);
238.635 + dbf->offset++;
238.636 + return;
238.637 +}
238.638 +
238.639 +static void write_header(TABDCA *dca, struct dbf *dbf)
238.640 +{ /* write xBASE data file header */
238.641 + int j, k, temp;
238.642 + const char *name;
238.643 + /* version number */
238.644 + write_byte(dbf, 0x03 /* file without DBT */);
238.645 + /* date of last update (YYMMDD) */
238.646 + write_byte(dbf, 70 /* 1970 */);
238.647 + write_byte(dbf, 1 /* January */);
238.648 + write_byte(dbf, 1 /* 1st */);
238.649 + /* number of records (unknown so far) */
238.650 + for (j = 1; j <= 4; j++)
238.651 + write_byte(dbf, 0xFF);
238.652 + /* length of the header, in bytes */
238.653 + temp = 32 + dbf->nf * 32 + 1;
238.654 + write_byte(dbf, temp);
238.655 + write_byte(dbf, temp >> 8);
238.656 + /* length of each record, in bytes */
238.657 + temp = 1;
238.658 + for (k = 1; k <= dbf->nf; k++)
238.659 + temp += dbf->len[k];
238.660 + write_byte(dbf, temp);
238.661 + write_byte(dbf, temp >> 8);
238.662 + /* (reserved) */
238.663 + for (j = 1; j <= 20; j++)
238.664 + write_byte(dbf, 0x00);
238.665 + /* field descriptor array */
238.666 + for (k = 1; k <= dbf->nf; k++)
238.667 + { /* field name (terminated by 0x00) */
238.668 + name = mpl_tab_get_name(dca, k);
238.669 + for (j = 0; j < 10 && name[j] != '\0'; j++)
238.670 + write_byte(dbf, name[j]);
238.671 + for (j = j; j < 11; j++)
238.672 + write_byte(dbf, 0x00);
238.673 + /* field type */
238.674 + write_byte(dbf, dbf->type[k]);
238.675 + /* (reserved) */
238.676 + for (j = 1; j <= 4; j++)
238.677 + write_byte(dbf, 0x00);
238.678 + /* field length */
238.679 + write_byte(dbf, dbf->len[k]);
238.680 + /* field precision */
238.681 + write_byte(dbf, dbf->prec[k]);
238.682 + /* (reserved) */
238.683 + for (j = 1; j <= 14; j++)
238.684 + write_byte(dbf, 0x00);
238.685 + }
238.686 + /* end of header */
238.687 + write_byte(dbf, 0x0D);
238.688 + return;
238.689 +}
238.690 +
238.691 +static struct dbf *dbf_open_file(TABDCA *dca, int mode)
238.692 +{ /* open xBASE data file */
238.693 + struct dbf *dbf;
238.694 + /* create control structure */
238.695 + dbf = xmalloc(sizeof(struct dbf));
238.696 + dbf->mode = mode;
238.697 + dbf->fname = NULL;
238.698 + dbf->fp = NULL;
238.699 + if (setjmp(dbf->jump)) goto fail;
238.700 + dbf->offset = 0;
238.701 + dbf->count = 0;
238.702 + dbf->nf = 0;
238.703 + /* try to open the xBASE data file */
238.704 + if (mpl_tab_num_args(dca) < 2)
238.705 + { xprintf("xBASE driver: file name not specified\n");
238.706 + longjmp(dbf->jump, 0);
238.707 + }
238.708 + dbf->fname = xmalloc(strlen(mpl_tab_get_arg(dca, 2))+1);
238.709 + strcpy(dbf->fname, mpl_tab_get_arg(dca, 2));
238.710 + if (mode == 'R')
238.711 + { /* open the file for reading */
238.712 + dbf->fp = fopen(dbf->fname, "rb");
238.713 + if (dbf->fp == NULL)
238.714 + { xprintf("xBASE driver: unable to open %s - %s\n",
238.715 + dbf->fname, strerror(errno));
238.716 + longjmp(dbf->jump, 0);
238.717 + }
238.718 + read_header(dca, dbf);
238.719 + }
238.720 + else if (mode == 'W')
238.721 + { /* open the file for writing */
238.722 + if (mpl_tab_num_args(dca) < 3)
238.723 + { xprintf("xBASE driver: file format not specified\n");
238.724 + longjmp(dbf->jump, 0);
238.725 + }
238.726 + parse_third_arg(dca, dbf);
238.727 + dbf->fp = fopen(dbf->fname, "wb");
238.728 + if (dbf->fp == NULL)
238.729 + { xprintf("xBASE driver: unable to create %s - %s\n",
238.730 + dbf->fname, strerror(errno));
238.731 + longjmp(dbf->jump, 0);
238.732 + }
238.733 + write_header(dca, dbf);
238.734 + }
238.735 + else
238.736 + xassert(mode != mode);
238.737 + /* the file has been open */
238.738 + return dbf;
238.739 +fail: /* the file cannot be open */
238.740 + if (dbf->fname != NULL) xfree(dbf->fname);
238.741 + if (dbf->fp != NULL) fclose(dbf->fp);
238.742 + xfree(dbf);
238.743 + return NULL;
238.744 +}
238.745 +
238.746 +static int dbf_read_record(TABDCA *dca, struct dbf *dbf)
238.747 +{ /* read next record from xBASE data file */
238.748 + int b, j, k, ret = 0;
238.749 + char buf[DBF_FDLEN_MAX+1];
238.750 + xassert(dbf->mode == 'R');
238.751 + if (setjmp(dbf->jump))
238.752 + { ret = 1;
238.753 + goto done;
238.754 + }
238.755 + /* check record flag */
238.756 + b = read_byte(dbf);
238.757 + if (b == 0x1A)
238.758 + { /* end of data */
238.759 + ret = -1;
238.760 + goto done;
238.761 + }
238.762 + if (b != 0x20)
238.763 + { xprintf("%s:0x%X: invalid record flag\n", dbf->fname,
238.764 + dbf->offset);
238.765 + longjmp(dbf->jump, 0);
238.766 + }
238.767 + /* read dummy RECNO field */
238.768 + if (dbf->ref[0] > 0)
238.769 + mpl_tab_set_num(dca, dbf->ref[0], dbf->count+1);
238.770 + /* read fields */
238.771 + for (k = 1; k <= dbf->nf; k++)
238.772 + { /* read k-th field */
238.773 + for (j = 0; j < dbf->len[k]; j++)
238.774 + buf[j] = (char)read_byte(dbf);
238.775 + buf[dbf->len[k]] = '\0';
238.776 + /* set field value */
238.777 + if (dbf->type[k] == 'C')
238.778 + { /* character field */
238.779 + if (dbf->ref[k] > 0)
238.780 + mpl_tab_set_str(dca, dbf->ref[k], strtrim(buf));
238.781 + }
238.782 + else if (dbf->type[k] == 'N')
238.783 + { /* numeric field */
238.784 + if (dbf->ref[k] > 0)
238.785 + { double num;
238.786 + strspx(buf);
238.787 + xassert(str2num(buf, &num) == 0);
238.788 + mpl_tab_set_num(dca, dbf->ref[k], num);
238.789 + }
238.790 + }
238.791 + else
238.792 + xassert(dbf != dbf);
238.793 + }
238.794 + /* increase record count */
238.795 + dbf->count++;
238.796 +done: return ret;
238.797 +}
238.798 +
238.799 +static int dbf_write_record(TABDCA *dca, struct dbf *dbf)
238.800 +{ /* write next record to xBASE data file */
238.801 + int j, k, ret = 0;
238.802 + char buf[255+1];
238.803 + xassert(dbf->mode == 'W');
238.804 + if (setjmp(dbf->jump))
238.805 + { ret = 1;
238.806 + goto done;
238.807 + }
238.808 + /* record flag */
238.809 + write_byte(dbf, 0x20);
238.810 + xassert(dbf->nf == mpl_tab_num_flds(dca));
238.811 + for (k = 1; k <= dbf->nf; k++)
238.812 + { if (dbf->type[k] == 'C')
238.813 + { /* character field */
238.814 + const char *str;
238.815 + if (mpl_tab_get_type(dca, k) == 'N')
238.816 + { sprintf(buf, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k));
238.817 + str = buf;
238.818 + }
238.819 + else if (mpl_tab_get_type(dca, k) == 'S')
238.820 + str = mpl_tab_get_str(dca, k);
238.821 + else
238.822 + xassert(dca != dca);
238.823 + if ((int)strlen(str) > dbf->len[k])
238.824 + { xprintf("xBASE driver: field %s: cannot convert %.15s..."
238.825 + " to field format\n", mpl_tab_get_name(dca, k), str);
238.826 + longjmp(dbf->jump, 0);
238.827 + }
238.828 + for (j = 0; j < dbf->len[k] && str[j] != '\0'; j++)
238.829 + write_byte(dbf, str[j]);
238.830 + for (j = j; j < dbf->len[k]; j++)
238.831 + write_byte(dbf, ' ');
238.832 + }
238.833 + else if (dbf->type[k] == 'N')
238.834 + { /* numeric field */
238.835 + double num = mpl_tab_get_num(dca, k);
238.836 + if (fabs(num) > 1e20)
238.837 +err: { xprintf("xBASE driver: field %s: cannot convert %g to fi"
238.838 + "eld format\n", mpl_tab_get_name(dca, k), num);
238.839 + longjmp(dbf->jump, 0);
238.840 + }
238.841 + sprintf(buf, "%*.*f", dbf->len[k], dbf->prec[k], num);
238.842 + xassert(strlen(buf) < sizeof(buf));
238.843 + if ((int)strlen(buf) != dbf->len[k]) goto err;
238.844 + for (j = 0; j < dbf->len[k]; j++)
238.845 + write_byte(dbf, buf[j]);
238.846 + }
238.847 + else
238.848 + xassert(dbf != dbf);
238.849 + }
238.850 + /* increase record count */
238.851 + dbf->count++;
238.852 +done: return ret;
238.853 +}
238.854 +
238.855 +static int dbf_close_file(TABDCA *dca, struct dbf *dbf)
238.856 +{ /* close xBASE data file */
238.857 + int ret = 0;
238.858 + xassert(dca == dca);
238.859 + if (dbf->mode == 'W')
238.860 + { if (setjmp(dbf->jump))
238.861 + { ret = 1;
238.862 + goto skip;
238.863 + }
238.864 + /* end-of-file flag */
238.865 + write_byte(dbf, 0x1A);
238.866 + /* number of records */
238.867 + dbf->offset = 4;
238.868 + if (fseek(dbf->fp, dbf->offset, SEEK_SET))
238.869 + { xprintf("%s:0x%X: seek error - %s\n", dbf->fname,
238.870 + dbf->offset, strerror(errno));
238.871 + longjmp(dbf->jump, 0);
238.872 + }
238.873 + write_byte(dbf, dbf->count);
238.874 + write_byte(dbf, dbf->count >> 8);
238.875 + write_byte(dbf, dbf->count >> 16);
238.876 + write_byte(dbf, dbf->count >> 24);
238.877 + fflush(dbf->fp);
238.878 + if (ferror(dbf->fp))
238.879 + { xprintf("%s:0x%X: write error - %s\n", dbf->fname,
238.880 + dbf->offset, strerror(errno));
238.881 + longjmp(dbf->jump, 0);
238.882 + }
238.883 +skip: ;
238.884 + }
238.885 + xfree(dbf->fname);
238.886 + fclose(dbf->fp);
238.887 + xfree(dbf);
238.888 + return ret;
238.889 +}
238.890 +
238.891 +/**********************************************************************/
238.892 +
238.893 +#define TAB_CSV 1
238.894 +#define TAB_XBASE 2
238.895 +#define TAB_ODBC 3
238.896 +#define TAB_MYSQL 4
238.897 +
238.898 +void mpl_tab_drv_open(MPL *mpl, int mode)
238.899 +{ TABDCA *dca = mpl->dca;
238.900 + xassert(dca->id == 0);
238.901 + xassert(dca->link == NULL);
238.902 + xassert(dca->na >= 1);
238.903 + if (strcmp(dca->arg[1], "CSV") == 0)
238.904 + { dca->id = TAB_CSV;
238.905 + dca->link = csv_open_file(dca, mode);
238.906 + }
238.907 + else if (strcmp(dca->arg[1], "xBASE") == 0)
238.908 + { dca->id = TAB_XBASE;
238.909 + dca->link = dbf_open_file(dca, mode);
238.910 + }
238.911 + else if (strcmp(dca->arg[1], "ODBC") == 0 ||
238.912 + strcmp(dca->arg[1], "iODBC") == 0)
238.913 + { dca->id = TAB_ODBC;
238.914 + dca->link = db_iodbc_open(dca, mode);
238.915 + }
238.916 + else if (strcmp(dca->arg[1], "MySQL") == 0)
238.917 + { dca->id = TAB_MYSQL;
238.918 + dca->link = db_mysql_open(dca, mode);
238.919 + }
238.920 + else
238.921 + xprintf("Invalid table driver `%s'\n", dca->arg[1]);
238.922 + if (dca->link == NULL)
238.923 + error(mpl, "error on opening table %s",
238.924 + mpl->stmt->u.tab->name);
238.925 + return;
238.926 +}
238.927 +
238.928 +int mpl_tab_drv_read(MPL *mpl)
238.929 +{ TABDCA *dca = mpl->dca;
238.930 + int ret;
238.931 + switch (dca->id)
238.932 + { case TAB_CSV:
238.933 + ret = csv_read_record(dca, dca->link);
238.934 + break;
238.935 + case TAB_XBASE:
238.936 + ret = dbf_read_record(dca, dca->link);
238.937 + break;
238.938 + case TAB_ODBC:
238.939 + ret = db_iodbc_read(dca, dca->link);
238.940 + break;
238.941 + case TAB_MYSQL:
238.942 + ret = db_mysql_read(dca, dca->link);
238.943 + break;
238.944 + default:
238.945 + xassert(dca != dca);
238.946 + }
238.947 + if (ret > 0)
238.948 + error(mpl, "error on reading data from table %s",
238.949 + mpl->stmt->u.tab->name);
238.950 + return ret;
238.951 +}
238.952 +
238.953 +void mpl_tab_drv_write(MPL *mpl)
238.954 +{ TABDCA *dca = mpl->dca;
238.955 + int ret;
238.956 + switch (dca->id)
238.957 + { case TAB_CSV:
238.958 + ret = csv_write_record(dca, dca->link);
238.959 + break;
238.960 + case TAB_XBASE:
238.961 + ret = dbf_write_record(dca, dca->link);
238.962 + break;
238.963 + case TAB_ODBC:
238.964 + ret = db_iodbc_write(dca, dca->link);
238.965 + break;
238.966 + case TAB_MYSQL:
238.967 + ret = db_mysql_write(dca, dca->link);
238.968 + break;
238.969 + default:
238.970 + xassert(dca != dca);
238.971 + }
238.972 + if (ret)
238.973 + error(mpl, "error on writing data to table %s",
238.974 + mpl->stmt->u.tab->name);
238.975 + return;
238.976 +}
238.977 +
238.978 +void mpl_tab_drv_close(MPL *mpl)
238.979 +{ TABDCA *dca = mpl->dca;
238.980 + int ret;
238.981 + switch (dca->id)
238.982 + { case TAB_CSV:
238.983 + ret = csv_close_file(dca, dca->link);
238.984 + break;
238.985 + case TAB_XBASE:
238.986 + ret = dbf_close_file(dca, dca->link);
238.987 + break;
238.988 + case TAB_ODBC:
238.989 + ret = db_iodbc_close(dca, dca->link);
238.990 + break;
238.991 + case TAB_MYSQL:
238.992 + ret = db_mysql_close(dca, dca->link);
238.993 + break;
238.994 + default:
238.995 + xassert(dca != dca);
238.996 + }
238.997 + dca->id = 0;
238.998 + dca->link = NULL;
238.999 + if (ret)
238.1000 + error(mpl, "error on closing table %s",
238.1001 + mpl->stmt->u.tab->name);
238.1002 + return;
238.1003 +}
238.1004 +
238.1005 +/* eof */
239.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
239.2 +++ b/src/glpmps.c Mon Dec 06 13:09:21 2010 +0100
239.3 @@ -0,0 +1,1401 @@
239.4 +/* glpmps.c (MPS format routines) */
239.5 +
239.6 +/***********************************************************************
239.7 +* This code is part of GLPK (GNU Linear Programming Kit).
239.8 +*
239.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
239.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
239.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
239.12 +* E-mail: <mao@gnu.org>.
239.13 +*
239.14 +* GLPK is free software: you can redistribute it and/or modify it
239.15 +* under the terms of the GNU General Public License as published by
239.16 +* the Free Software Foundation, either version 3 of the License, or
239.17 +* (at your option) any later version.
239.18 +*
239.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
239.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
239.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
239.22 +* License for more details.
239.23 +*
239.24 +* You should have received a copy of the GNU General Public License
239.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
239.26 +***********************************************************************/
239.27 +
239.28 +#include "glpapi.h"
239.29 +
239.30 +/***********************************************************************
239.31 +* NAME
239.32 +*
239.33 +* glp_init_mpscp - initialize MPS format control parameters
239.34 +*
239.35 +* SYNOPSIS
239.36 +*
239.37 +* void glp_init_mpscp(glp_mpscp *parm);
239.38 +*
239.39 +* DESCRIPTION
239.40 +*
239.41 +* The routine glp_init_mpscp initializes control parameters, which are
239.42 +* used by the MPS input/output routines glp_read_mps and glp_write_mps,
239.43 +* with default values.
239.44 +*
239.45 +* Default values of the control parameters are stored in the glp_mpscp
239.46 +* structure, which the parameter parm points to. */
239.47 +
239.48 +void glp_init_mpscp(glp_mpscp *parm)
239.49 +{ parm->blank = '\0';
239.50 + parm->obj_name = NULL;
239.51 + parm->tol_mps = 1e-12;
239.52 + return;
239.53 +}
239.54 +
239.55 +static void check_parm(const char *func, const glp_mpscp *parm)
239.56 +{ /* check control parameters */
239.57 + if (!(0x00 <= parm->blank && parm->blank <= 0xFF) ||
239.58 + !(parm->blank == '\0' || isprint(parm->blank)))
239.59 + xerror("%s: blank = 0x%02X; invalid parameter\n",
239.60 + func, parm->blank);
239.61 + if (!(parm->obj_name == NULL || strlen(parm->obj_name) <= 255))
239.62 + xerror("%s: obj_name = \"%.12s...\"; parameter too long\n",
239.63 + func, parm->obj_name);
239.64 + if (!(0.0 <= parm->tol_mps && parm->tol_mps < 1.0))
239.65 + xerror("%s: tol_mps = %g; invalid parameter\n",
239.66 + func, parm->tol_mps);
239.67 + return;
239.68 +}
239.69 +
239.70 +/***********************************************************************
239.71 +* NAME
239.72 +*
239.73 +* glp_read_mps - read problem data in MPS format
239.74 +*
239.75 +* SYNOPSIS
239.76 +*
239.77 +* int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
239.78 +* const char *fname);
239.79 +*
239.80 +* DESCRIPTION
239.81 +*
239.82 +* The routine glp_read_mps reads problem data in MPS format from a
239.83 +* text file.
239.84 +*
239.85 +* The parameter fmt specifies the version of MPS format:
239.86 +*
239.87 +* GLP_MPS_DECK - fixed (ancient) MPS format;
239.88 +* GLP_MPS_FILE - free (modern) MPS format.
239.89 +*
239.90 +* The parameter parm is a pointer to the structure glp_mpscp, which
239.91 +* specifies control parameters used by the routine. If parm is NULL,
239.92 +* the routine uses default settings.
239.93 +*
239.94 +* The character string fname specifies a name of the text file to be
239.95 +* read.
239.96 +*
239.97 +* Note that before reading data the current content of the problem
239.98 +* object is completely erased with the routine glp_erase_prob.
239.99 +*
239.100 +* RETURNS
239.101 +*
239.102 +* If the operation was successful, the routine glp_read_mps returns
239.103 +* zero. Otherwise, it prints an error message and returns non-zero. */
239.104 +
239.105 +struct csa
239.106 +{ /* common storage area */
239.107 + glp_prob *P;
239.108 + /* pointer to problem object */
239.109 + int deck;
239.110 + /* MPS format (0 - free, 1 - fixed) */
239.111 + const glp_mpscp *parm;
239.112 + /* pointer to control parameters */
239.113 + const char *fname;
239.114 + /* name of input MPS file */
239.115 + XFILE *fp;
239.116 + /* stream assigned to input MPS file */
239.117 + jmp_buf jump;
239.118 + /* label for go to in case of error */
239.119 + int recno;
239.120 + /* current record (card) number */
239.121 + int recpos;
239.122 + /* current record (card) position */
239.123 + int c;
239.124 + /* current character */
239.125 + int fldno;
239.126 + /* current field number */
239.127 + char field[255+1];
239.128 + /* current field content */
239.129 + int w80;
239.130 + /* warning 'record must not be longer than 80 chars' issued */
239.131 + int wef;
239.132 + /* warning 'extra fields detected beyond field 6' issued */
239.133 + int obj_row;
239.134 + /* objective row number */
239.135 + void *work1, *work2, *work3;
239.136 + /* working arrays */
239.137 +};
239.138 +
239.139 +static void error(struct csa *csa, const char *fmt, ...)
239.140 +{ /* print error message and terminate processing */
239.141 + va_list arg;
239.142 + xprintf("%s:%d: ", csa->fname, csa->recno);
239.143 + va_start(arg, fmt);
239.144 + xvprintf(fmt, arg);
239.145 + va_end(arg);
239.146 + longjmp(csa->jump, 1);
239.147 + /* no return */
239.148 +}
239.149 +
239.150 +static void warning(struct csa *csa, const char *fmt, ...)
239.151 +{ /* print warning message and continue processing */
239.152 + va_list arg;
239.153 + xprintf("%s:%d: warning: ", csa->fname, csa->recno);
239.154 + va_start(arg, fmt);
239.155 + xvprintf(fmt, arg);
239.156 + va_end(arg);
239.157 + return;
239.158 +}
239.159 +
239.160 +static void read_char(struct csa *csa)
239.161 +{ /* read next character */
239.162 + int c;
239.163 + if (csa->c == '\n')
239.164 + csa->recno++, csa->recpos = 0;
239.165 + csa->recpos++;
239.166 +read: c = xfgetc(csa->fp);
239.167 + if (c < 0)
239.168 + { if (xferror(csa->fp))
239.169 + error(csa, "read error - %s\n", xerrmsg());
239.170 + else if (csa->c == '\n')
239.171 + error(csa, "unexpected end of file\n");
239.172 + else
239.173 + { warning(csa, "missing final end of line\n");
239.174 + c = '\n';
239.175 + }
239.176 + }
239.177 + else if (c == '\n')
239.178 + ;
239.179 + else if (csa->c == '\r')
239.180 + { c = '\r';
239.181 + goto badc;
239.182 + }
239.183 + else if (csa->deck && c == '\r')
239.184 + { csa->c = '\r';
239.185 + goto read;
239.186 + }
239.187 + else if (c == ' ')
239.188 + ;
239.189 + else if (isspace(c))
239.190 + { if (csa->deck)
239.191 +badc: error(csa, "in fixed MPS format white-space character 0x%02"
239.192 + "X is not allowed\n", c);
239.193 + c = ' ';
239.194 + }
239.195 + else if (iscntrl(c))
239.196 + error(csa, "invalid control character 0x%02X\n", c);
239.197 + if (csa->deck && csa->recpos == 81 && c != '\n' && csa->w80 < 1)
239.198 + { warning(csa, "in fixed MPS format record must not be longer th"
239.199 + "an 80 characters\n");
239.200 + csa->w80++;
239.201 + }
239.202 + csa->c = c;
239.203 + return;
239.204 +}
239.205 +
239.206 +static int indicator(struct csa *csa, int name)
239.207 +{ /* skip comment records and read possible indicator record */
239.208 + int ret;
239.209 + /* reset current field number */
239.210 + csa->fldno = 0;
239.211 +loop: /* read the very first character of the next record */
239.212 + xassert(csa->c == '\n');
239.213 + read_char(csa);
239.214 + if (csa->c == ' ' || csa->c == '\n')
239.215 + { /* data record */
239.216 + ret = 0;
239.217 + }
239.218 + else if (csa->c == '*')
239.219 + { /* comment record */
239.220 + while (csa->c != '\n')
239.221 + read_char(csa);
239.222 + goto loop;
239.223 + }
239.224 + else
239.225 + { /* indicator record */
239.226 + int len = 0;
239.227 + while (csa->c != ' ' && csa->c != '\n' && len < 12)
239.228 + { csa->field[len++] = (char)csa->c;
239.229 + read_char(csa);
239.230 + }
239.231 + csa->field[len] = '\0';
239.232 + if (!(strcmp(csa->field, "NAME") == 0 ||
239.233 + strcmp(csa->field, "ROWS") == 0 ||
239.234 + strcmp(csa->field, "COLUMNS") == 0 ||
239.235 + strcmp(csa->field, "RHS") == 0 ||
239.236 + strcmp(csa->field, "RANGES") == 0 ||
239.237 + strcmp(csa->field, "BOUNDS") == 0 ||
239.238 + strcmp(csa->field, "ENDATA") == 0))
239.239 + error(csa, "invalid indicator record\n");
239.240 + if (!name)
239.241 + { while (csa->c != '\n')
239.242 + read_char(csa);
239.243 + }
239.244 + ret = 1;
239.245 + }
239.246 + return ret;
239.247 +}
239.248 +
239.249 +static void read_field(struct csa *csa)
239.250 +{ /* read next field of the current data record */
239.251 + csa->fldno++;
239.252 + if (csa->deck)
239.253 + { /* fixed MPS format */
239.254 + int beg, end, pos;
239.255 + /* determine predefined field positions */
239.256 + if (csa->fldno == 1)
239.257 + beg = 2, end = 3;
239.258 + else if (csa->fldno == 2)
239.259 + beg = 5, end = 12;
239.260 + else if (csa->fldno == 3)
239.261 + beg = 15, end = 22;
239.262 + else if (csa->fldno == 4)
239.263 + beg = 25, end = 36;
239.264 + else if (csa->fldno == 5)
239.265 + beg = 40, end = 47;
239.266 + else if (csa->fldno == 6)
239.267 + beg = 50, end = 61;
239.268 + else
239.269 + xassert(csa != csa);
239.270 + /* skip blanks preceding the current field */
239.271 + if (csa->c != '\n')
239.272 + { pos = csa->recpos;
239.273 + while (csa->recpos < beg)
239.274 + { if (csa->c == ' ')
239.275 + ;
239.276 + else if (csa->c == '\n')
239.277 + break;
239.278 + else
239.279 + error(csa, "in fixed MPS format positions %d-%d must "
239.280 + "be blank\n", pos, beg-1);
239.281 + read_char(csa);
239.282 + }
239.283 + }
239.284 + /* skip possible comment beginning in the field 3 or 5 */
239.285 + if ((csa->fldno == 3 || csa->fldno == 5) && csa->c == '$')
239.286 + { while (csa->c != '\n')
239.287 + read_char(csa);
239.288 + }
239.289 + /* read the current field */
239.290 + for (pos = beg; pos <= end; pos++)
239.291 + { if (csa->c == '\n') break;
239.292 + csa->field[pos-beg] = (char)csa->c;
239.293 + read_char(csa);
239.294 + }
239.295 + csa->field[pos-beg] = '\0';
239.296 + strtrim(csa->field);
239.297 + /* skip blanks following the last field */
239.298 + if (csa->fldno == 6 && csa->c != '\n')
239.299 + { while (csa->recpos <= 72)
239.300 + { if (csa->c == ' ')
239.301 + ;
239.302 + else if (csa->c == '\n')
239.303 + break;
239.304 + else
239.305 + error(csa, "in fixed MPS format positions 62-72 must "
239.306 + "be blank\n");
239.307 + read_char(csa);
239.308 + }
239.309 + while (csa->c != '\n')
239.310 + read_char(csa);
239.311 + }
239.312 + }
239.313 + else
239.314 + { /* free MPS format */
239.315 + int len;
239.316 + /* skip blanks preceding the current field */
239.317 + while (csa->c == ' ')
239.318 + read_char(csa);
239.319 + /* skip possible comment */
239.320 + if (csa->c == '$')
239.321 + { while (csa->c != '\n')
239.322 + read_char(csa);
239.323 + }
239.324 + /* read the current field */
239.325 + len = 0;
239.326 + while (!(csa->c == ' ' || csa->c == '\n'))
239.327 + { if (len == 255)
239.328 + error(csa, "length of field %d exceeds 255 characters\n",
239.329 + csa->fldno++);
239.330 + csa->field[len++] = (char)csa->c;
239.331 + read_char(csa);
239.332 + }
239.333 + csa->field[len] = '\0';
239.334 + /* skip anything following the last field (any extra fields
239.335 + are considered to be comments) */
239.336 + if (csa->fldno == 6)
239.337 + { while (csa->c == ' ')
239.338 + read_char(csa);
239.339 + if (csa->c != '$' && csa->c != '\n' && csa->wef < 1)
239.340 + { warning(csa, "some extra field(s) detected beyond field "
239.341 + "6; field(s) ignored\n");
239.342 + csa->wef++;
239.343 + }
239.344 + while (csa->c != '\n')
239.345 + read_char(csa);
239.346 + }
239.347 + }
239.348 + return;
239.349 +}
239.350 +
239.351 +static void patch_name(struct csa *csa, char *name)
239.352 +{ /* process embedded blanks in symbolic name */
239.353 + int blank = csa->parm->blank;
239.354 + if (blank == '\0')
239.355 + { /* remove emedded blanks */
239.356 + strspx(name);
239.357 + }
239.358 + else
239.359 + { /* replace embedded blanks by specified character */
239.360 + for (; *name != '\0'; name++)
239.361 + if (*name == ' ') *name = (char)blank;
239.362 + }
239.363 + return;
239.364 +}
239.365 +
239.366 +static double read_number(struct csa *csa)
239.367 +{ /* read next field and convert it to floating-point number */
239.368 + double x;
239.369 + char *s;
239.370 + /* read next field */
239.371 + read_field(csa);
239.372 + xassert(csa->fldno == 4 || csa->fldno == 6);
239.373 + if (csa->field[0] == '\0')
239.374 + error(csa, "missing numeric value in field %d\n", csa->fldno);
239.375 + /* skip initial spaces of the field */
239.376 + for (s = csa->field; *s == ' '; s++);
239.377 + /* perform conversion */
239.378 + if (str2num(s, &x) != 0)
239.379 + error(csa, "cannot convert `%s' to floating-point number\n",
239.380 + s);
239.381 + return x;
239.382 +}
239.383 +
239.384 +static void skip_field(struct csa *csa)
239.385 +{ /* read and skip next field (assumed to be blank) */
239.386 + read_field(csa);
239.387 + if (csa->field[0] != '\0')
239.388 + error(csa, "field %d must be blank\n", csa->fldno);
239.389 + return;
239.390 +}
239.391 +
239.392 +static void read_name(struct csa *csa)
239.393 +{ /* read NAME indicator record */
239.394 + if (!(indicator(csa, 1) && strcmp(csa->field, "NAME") == 0))
239.395 + error(csa, "missing NAME indicator record\n");
239.396 + /* this indicator record looks like a data record; simulate that
239.397 + fields 1 and 2 were read */
239.398 + csa->fldno = 2;
239.399 + /* field 3: model name */
239.400 + read_field(csa), patch_name(csa, csa->field);
239.401 + if (csa->field[0] == '\0')
239.402 + warning(csa, "missing model name in field 3\n");
239.403 + else
239.404 + glp_set_prob_name(csa->P, csa->field);
239.405 + /* skip anything following field 3 */
239.406 + while (csa->c != '\n')
239.407 + read_char(csa);
239.408 + return;
239.409 +}
239.410 +
239.411 +static void read_rows(struct csa *csa)
239.412 +{ /* read ROWS section */
239.413 + int i, type;
239.414 +loop: if (indicator(csa, 0)) goto done;
239.415 + /* field 1: row type */
239.416 + read_field(csa), strspx(csa->field);
239.417 + if (strcmp(csa->field, "N") == 0)
239.418 + type = GLP_FR;
239.419 + else if (strcmp(csa->field, "G") == 0)
239.420 + type = GLP_LO;
239.421 + else if (strcmp(csa->field, "L") == 0)
239.422 + type = GLP_UP;
239.423 + else if (strcmp(csa->field, "E") == 0)
239.424 + type = GLP_FX;
239.425 + else if (csa->field[0] == '\0')
239.426 + error(csa, "missing row type in field 1\n");
239.427 + else
239.428 + error(csa, "invalid row type in field 1\n");
239.429 + /* field 2: row name */
239.430 + read_field(csa), patch_name(csa, csa->field);
239.431 + if (csa->field[0] == '\0')
239.432 + error(csa, "missing row name in field 2\n");
239.433 + if (glp_find_row(csa->P, csa->field) != 0)
239.434 + error(csa, "row `%s' multiply specified\n", csa->field);
239.435 + i = glp_add_rows(csa->P, 1);
239.436 + glp_set_row_name(csa->P, i, csa->field);
239.437 + glp_set_row_bnds(csa->P, i, type, 0.0, 0.0);
239.438 + /* fields 3, 4, 5, and 6 must be blank */
239.439 + skip_field(csa);
239.440 + skip_field(csa);
239.441 + skip_field(csa);
239.442 + skip_field(csa);
239.443 + goto loop;
239.444 +done: return;
239.445 +}
239.446 +
239.447 +static void read_columns(struct csa *csa)
239.448 +{ /* read COLUMNS section */
239.449 + int i, j, f, len, kind = GLP_CV, *ind;
239.450 + double aij, *val;
239.451 + char name[255+1], *flag;
239.452 + /* allocate working arrays */
239.453 + csa->work1 = ind = xcalloc(1+csa->P->m, sizeof(int));
239.454 + csa->work2 = val = xcalloc(1+csa->P->m, sizeof(double));
239.455 + csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char));
239.456 + memset(&flag[1], 0, csa->P->m);
239.457 + /* no current column exists */
239.458 + j = 0, len = 0;
239.459 +loop: if (indicator(csa, 0)) goto done;
239.460 + /* field 1 must be blank */
239.461 + if (csa->deck)
239.462 + { read_field(csa);
239.463 + if (csa->field[0] != '\0')
239.464 + error(csa, "field 1 must be blank\n");
239.465 + }
239.466 + else
239.467 + csa->fldno++;
239.468 + /* field 2: column or kind name */
239.469 + read_field(csa), patch_name(csa, csa->field);
239.470 + strcpy(name, csa->field);
239.471 + /* field 3: row name or keyword 'MARKER' */
239.472 + read_field(csa), patch_name(csa, csa->field);
239.473 + if (strcmp(csa->field, "'MARKER'") == 0)
239.474 + { /* process kind data record */
239.475 + /* field 4 must be blank */
239.476 + if (csa->deck)
239.477 + { read_field(csa);
239.478 + if (csa->field[0] != '\0')
239.479 + error(csa, "field 4 must be blank\n");
239.480 + }
239.481 + else
239.482 + csa->fldno++;
239.483 + /* field 5: keyword 'INTORG' or 'INTEND' */
239.484 + read_field(csa), patch_name(csa, csa->field);
239.485 + if (strcmp(csa->field, "'INTORG'") == 0)
239.486 + kind = GLP_IV;
239.487 + else if (strcmp(csa->field, "'INTEND'") == 0)
239.488 + kind = GLP_CV;
239.489 + else if (csa->field[0] == '\0')
239.490 + error(csa, "missing keyword in field 5\n");
239.491 + else
239.492 + error(csa, "invalid keyword in field 5\n");
239.493 + /* field 6 must be blank */
239.494 + skip_field(csa);
239.495 + goto loop;
239.496 + }
239.497 + /* process column name specified in field 2 */
239.498 + if (name[0] == '\0')
239.499 + { /* the same column as in previous data record */
239.500 + if (j == 0)
239.501 + error(csa, "missing column name in field 2\n");
239.502 + }
239.503 + else if (j != 0 && strcmp(name, csa->P->col[j]->name) == 0)
239.504 + { /* the same column as in previous data record */
239.505 + xassert(j != 0);
239.506 + }
239.507 + else
239.508 + { /* store the current column */
239.509 + if (j != 0)
239.510 + { glp_set_mat_col(csa->P, j, len, ind, val);
239.511 + while (len > 0) flag[ind[len--]] = 0;
239.512 + }
239.513 + /* create new column */
239.514 + if (glp_find_col(csa->P, name) != 0)
239.515 + error(csa, "column `%s' multiply specified\n", name);
239.516 + j = glp_add_cols(csa->P, 1);
239.517 + glp_set_col_name(csa->P, j, name);
239.518 + glp_set_col_kind(csa->P, j, kind);
239.519 + if (kind == GLP_CV)
239.520 + glp_set_col_bnds(csa->P, j, GLP_LO, 0.0, 0.0);
239.521 + else if (kind == GLP_IV)
239.522 + glp_set_col_bnds(csa->P, j, GLP_DB, 0.0, 1.0);
239.523 + else
239.524 + xassert(kind != kind);
239.525 + }
239.526 + /* process fields 3-4 and 5-6 */
239.527 + for (f = 3; f <= 5; f += 2)
239.528 + { /* field 3 or 5: row name */
239.529 + if (f == 3)
239.530 + { if (csa->field[0] == '\0')
239.531 + error(csa, "missing row name in field 3\n");
239.532 + }
239.533 + else
239.534 + { read_field(csa), patch_name(csa, csa->field);
239.535 + if (csa->field[0] == '\0')
239.536 + { /* if field 5 is blank, field 6 also must be blank */
239.537 + skip_field(csa);
239.538 + continue;
239.539 + }
239.540 + }
239.541 + i = glp_find_row(csa->P, csa->field);
239.542 + if (i == 0)
239.543 + error(csa, "row `%s' not found\n", csa->field);
239.544 + if (flag[i])
239.545 + error(csa, "duplicate coefficient in row `%s'\n",
239.546 + csa->field);
239.547 + /* field 4 or 6: coefficient value */
239.548 + aij = read_number(csa);
239.549 + if (fabs(aij) < csa->parm->tol_mps) aij = 0.0;
239.550 + len++, ind[len] = i, val[len] = aij, flag[i] = 1;
239.551 + }
239.552 + goto loop;
239.553 +done: /* store the last column */
239.554 + if (j != 0)
239.555 + glp_set_mat_col(csa->P, j, len, ind, val);
239.556 + /* free working arrays */
239.557 + xfree(ind);
239.558 + xfree(val);
239.559 + xfree(flag);
239.560 + csa->work1 = csa->work2 = csa->work3 = NULL;
239.561 + return;
239.562 +}
239.563 +
239.564 +static void read_rhs(struct csa *csa)
239.565 +{ /* read RHS section */
239.566 + int i, f, v, type;
239.567 + double rhs;
239.568 + char name[255+1], *flag;
239.569 + /* allocate working array */
239.570 + csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char));
239.571 + memset(&flag[1], 0, csa->P->m);
239.572 + /* no current RHS vector exists */
239.573 + v = 0;
239.574 +loop: if (indicator(csa, 0)) goto done;
239.575 + /* field 1 must be blank */
239.576 + if (csa->deck)
239.577 + { read_field(csa);
239.578 + if (csa->field[0] != '\0')
239.579 + error(csa, "field 1 must be blank\n");
239.580 + }
239.581 + else
239.582 + csa->fldno++;
239.583 + /* field 2: RHS vector name */
239.584 + read_field(csa), patch_name(csa, csa->field);
239.585 + if (csa->field[0] == '\0')
239.586 + { /* the same RHS vector as in previous data record */
239.587 + if (v == 0)
239.588 + { warning(csa, "missing RHS vector name in field 2\n");
239.589 + goto blnk;
239.590 + }
239.591 + }
239.592 + else if (v != 0 && strcmp(csa->field, name) == 0)
239.593 + { /* the same RHS vector as in previous data record */
239.594 + xassert(v != 0);
239.595 + }
239.596 + else
239.597 +blnk: { /* new RHS vector */
239.598 + if (v != 0)
239.599 + error(csa, "multiple RHS vectors not supported\n");
239.600 + v++;
239.601 + strcpy(name, csa->field);
239.602 + }
239.603 + /* process fields 3-4 and 5-6 */
239.604 + for (f = 3; f <= 5; f += 2)
239.605 + { /* field 3 or 5: row name */
239.606 + read_field(csa), patch_name(csa, csa->field);
239.607 + if (csa->field[0] == '\0')
239.608 + { if (f == 3)
239.609 + error(csa, "missing row name in field 3\n");
239.610 + else
239.611 + { /* if field 5 is blank, field 6 also must be blank */
239.612 + skip_field(csa);
239.613 + continue;
239.614 + }
239.615 + }
239.616 + i = glp_find_row(csa->P, csa->field);
239.617 + if (i == 0)
239.618 + error(csa, "row `%s' not found\n", csa->field);
239.619 + if (flag[i])
239.620 + error(csa, "duplicate right-hand side for row `%s'\n",
239.621 + csa->field);
239.622 + /* field 4 or 6: right-hand side value */
239.623 + rhs = read_number(csa);
239.624 + if (fabs(rhs) < csa->parm->tol_mps) rhs = 0.0;
239.625 + type = csa->P->row[i]->type;
239.626 + if (type == GLP_FR)
239.627 + { if (i == csa->obj_row)
239.628 + glp_set_obj_coef(csa->P, 0, rhs);
239.629 + else if (rhs != 0.0)
239.630 + warning(csa, "non-zero right-hand side for free row `%s'"
239.631 + " ignored\n", csa->P->row[i]->name);
239.632 + }
239.633 + else
239.634 + glp_set_row_bnds(csa->P, i, type, rhs, rhs);
239.635 + flag[i] = 1;
239.636 + }
239.637 + goto loop;
239.638 +done: /* free working array */
239.639 + xfree(flag);
239.640 + csa->work3 = NULL;
239.641 + return;
239.642 +}
239.643 +
239.644 +static void read_ranges(struct csa *csa)
239.645 +{ /* read RANGES section */
239.646 + int i, f, v, type;
239.647 + double rhs, rng;
239.648 + char name[255+1], *flag;
239.649 + /* allocate working array */
239.650 + csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char));
239.651 + memset(&flag[1], 0, csa->P->m);
239.652 + /* no current RANGES vector exists */
239.653 + v = 0;
239.654 +loop: if (indicator(csa, 0)) goto done;
239.655 + /* field 1 must be blank */
239.656 + if (csa->deck)
239.657 + { read_field(csa);
239.658 + if (csa->field[0] != '\0')
239.659 + error(csa, "field 1 must be blank\n");
239.660 + }
239.661 + else
239.662 + csa->fldno++;
239.663 + /* field 2: RANGES vector name */
239.664 + read_field(csa), patch_name(csa, csa->field);
239.665 + if (csa->field[0] == '\0')
239.666 + { /* the same RANGES vector as in previous data record */
239.667 + if (v == 0)
239.668 + { warning(csa, "missing RANGES vector name in field 2\n");
239.669 + goto blnk;
239.670 + }
239.671 + }
239.672 + else if (v != 0 && strcmp(csa->field, name) == 0)
239.673 + { /* the same RANGES vector as in previous data record */
239.674 + xassert(v != 0);
239.675 + }
239.676 + else
239.677 +blnk: { /* new RANGES vector */
239.678 + if (v != 0)
239.679 + error(csa, "multiple RANGES vectors not supported\n");
239.680 + v++;
239.681 + strcpy(name, csa->field);
239.682 + }
239.683 + /* process fields 3-4 and 5-6 */
239.684 + for (f = 3; f <= 5; f += 2)
239.685 + { /* field 3 or 5: row name */
239.686 + read_field(csa), patch_name(csa, csa->field);
239.687 + if (csa->field[0] == '\0')
239.688 + { if (f == 3)
239.689 + error(csa, "missing row name in field 3\n");
239.690 + else
239.691 + { /* if field 5 is blank, field 6 also must be blank */
239.692 + skip_field(csa);
239.693 + continue;
239.694 + }
239.695 + }
239.696 + i = glp_find_row(csa->P, csa->field);
239.697 + if (i == 0)
239.698 + error(csa, "row `%s' not found\n", csa->field);
239.699 + if (flag[i])
239.700 + error(csa, "duplicate range for row `%s'\n", csa->field);
239.701 + /* field 4 or 6: range value */
239.702 + rng = read_number(csa);
239.703 + if (fabs(rng) < csa->parm->tol_mps) rng = 0.0;
239.704 + type = csa->P->row[i]->type;
239.705 + if (type == GLP_FR)
239.706 + warning(csa, "range for free row `%s' ignored\n",
239.707 + csa->P->row[i]->name);
239.708 + else if (type == GLP_LO)
239.709 + { rhs = csa->P->row[i]->lb;
239.710 + glp_set_row_bnds(csa->P, i, rhs == 0.0 ? GLP_FX : GLP_DB,
239.711 + rhs, rhs + fabs(rng));
239.712 + }
239.713 + else if (type == GLP_UP)
239.714 + { rhs = csa->P->row[i]->ub;
239.715 + glp_set_row_bnds(csa->P, i, rhs == 0.0 ? GLP_FX : GLP_DB,
239.716 + rhs - fabs(rng), rhs);
239.717 + }
239.718 + else if (type == GLP_FX)
239.719 + { rhs = csa->P->row[i]->lb;
239.720 + if (rng > 0.0)
239.721 + glp_set_row_bnds(csa->P, i, GLP_DB, rhs, rhs + rng);
239.722 + else if (rng < 0.0)
239.723 + glp_set_row_bnds(csa->P, i, GLP_DB, rhs + rng, rhs);
239.724 + }
239.725 + else
239.726 + xassert(type != type);
239.727 + flag[i] = 1;
239.728 + }
239.729 + goto loop;
239.730 +done: /* free working array */
239.731 + xfree(flag);
239.732 + csa->work3 = NULL;
239.733 + return;
239.734 +}
239.735 +
239.736 +static void read_bounds(struct csa *csa)
239.737 +{ /* read BOUNDS section */
239.738 + GLPCOL *col;
239.739 + int j, v, mask, data;
239.740 + double bnd, lb, ub;
239.741 + char type[2+1], name[255+1], *flag;
239.742 + /* allocate working array */
239.743 + csa->work3 = flag = xcalloc(1+csa->P->n, sizeof(char));
239.744 + memset(&flag[1], 0, csa->P->n);
239.745 + /* no current BOUNDS vector exists */
239.746 + v = 0;
239.747 +loop: if (indicator(csa, 0)) goto done;
239.748 + /* field 1: bound type */
239.749 + read_field(csa);
239.750 + if (strcmp(csa->field, "LO") == 0)
239.751 + mask = 0x01, data = 1;
239.752 + else if (strcmp(csa->field, "UP") == 0)
239.753 + mask = 0x10, data = 1;
239.754 + else if (strcmp(csa->field, "FX") == 0)
239.755 + mask = 0x11, data = 1;
239.756 + else if (strcmp(csa->field, "FR") == 0)
239.757 + mask = 0x11, data = 0;
239.758 + else if (strcmp(csa->field, "MI") == 0)
239.759 + mask = 0x01, data = 0;
239.760 + else if (strcmp(csa->field, "PL") == 0)
239.761 + mask = 0x10, data = 0;
239.762 + else if (strcmp(csa->field, "LI") == 0)
239.763 + mask = 0x01, data = 1;
239.764 + else if (strcmp(csa->field, "UI") == 0)
239.765 + mask = 0x10, data = 1;
239.766 + else if (strcmp(csa->field, "BV") == 0)
239.767 + mask = 0x11, data = 0;
239.768 + else if (csa->field[0] == '\0')
239.769 + error(csa, "missing bound type in field 1\n");
239.770 + else
239.771 + error(csa, "invalid bound type in field 1\n");
239.772 + strcpy(type, csa->field);
239.773 + /* field 2: BOUNDS vector name */
239.774 + read_field(csa), patch_name(csa, csa->field);
239.775 + if (csa->field[0] == '\0')
239.776 + { /* the same BOUNDS vector as in previous data record */
239.777 + if (v == 0)
239.778 + { warning(csa, "missing BOUNDS vector name in field 2\n");
239.779 + goto blnk;
239.780 + }
239.781 + }
239.782 + else if (v != 0 && strcmp(csa->field, name) == 0)
239.783 + { /* the same BOUNDS vector as in previous data record */
239.784 + xassert(v != 0);
239.785 + }
239.786 + else
239.787 +blnk: { /* new BOUNDS vector */
239.788 + if (v != 0)
239.789 + error(csa, "multiple BOUNDS vectors not supported\n");
239.790 + v++;
239.791 + strcpy(name, csa->field);
239.792 + }
239.793 + /* field 3: column name */
239.794 + read_field(csa), patch_name(csa, csa->field);
239.795 + if (csa->field[0] == '\0')
239.796 + error(csa, "missing column name in field 3\n");
239.797 + j = glp_find_col(csa->P, csa->field);
239.798 + if (j == 0)
239.799 + error(csa, "column `%s' not found\n", csa->field);
239.800 + if ((flag[j] & mask) == 0x01)
239.801 + error(csa, "duplicate lower bound for column `%s'\n",
239.802 + csa->field);
239.803 + if ((flag[j] & mask) == 0x10)
239.804 + error(csa, "duplicate upper bound for column `%s'\n",
239.805 + csa->field);
239.806 + xassert((flag[j] & mask) == 0x00);
239.807 + /* field 4: bound value */
239.808 + if (data)
239.809 + { bnd = read_number(csa);
239.810 + if (fabs(bnd) < csa->parm->tol_mps) bnd = 0.0;
239.811 + }
239.812 + else
239.813 + read_field(csa), bnd = 0.0;
239.814 + /* get current column bounds */
239.815 + col = csa->P->col[j];
239.816 + if (col->type == GLP_FR)
239.817 + lb = -DBL_MAX, ub = +DBL_MAX;
239.818 + else if (col->type == GLP_LO)
239.819 + lb = col->lb, ub = +DBL_MAX;
239.820 + else if (col->type == GLP_UP)
239.821 + lb = -DBL_MAX, ub = col->ub;
239.822 + else if (col->type == GLP_DB)
239.823 + lb = col->lb, ub = col->ub;
239.824 + else if (col->type == GLP_FX)
239.825 + lb = ub = col->lb;
239.826 + else
239.827 + xassert(col != col);
239.828 + /* change column bounds */
239.829 + if (strcmp(type, "LO") == 0)
239.830 + lb = bnd;
239.831 + else if (strcmp(type, "UP") == 0)
239.832 + ub = bnd;
239.833 + else if (strcmp(type, "FX") == 0)
239.834 + lb = ub = bnd;
239.835 + else if (strcmp(type, "FR") == 0)
239.836 + lb = -DBL_MAX, ub = +DBL_MAX;
239.837 + else if (strcmp(type, "MI") == 0)
239.838 + lb = -DBL_MAX;
239.839 + else if (strcmp(type, "PL") == 0)
239.840 + ub = +DBL_MAX;
239.841 + else if (strcmp(type, "LI") == 0)
239.842 + { glp_set_col_kind(csa->P, j, GLP_IV);
239.843 + lb = ceil(bnd);
239.844 + }
239.845 + else if (strcmp(type, "UI") == 0)
239.846 + { glp_set_col_kind(csa->P, j, GLP_IV);
239.847 + ub = floor(bnd);
239.848 + }
239.849 + else if (strcmp(type, "BV") == 0)
239.850 + { glp_set_col_kind(csa->P, j, GLP_IV);
239.851 + lb = 0.0, ub = 1.0;
239.852 + }
239.853 + else
239.854 + xassert(type != type);
239.855 + /* set new column bounds */
239.856 + if (lb == -DBL_MAX && ub == +DBL_MAX)
239.857 + glp_set_col_bnds(csa->P, j, GLP_FR, lb, ub);
239.858 + else if (ub == +DBL_MAX)
239.859 + glp_set_col_bnds(csa->P, j, GLP_LO, lb, ub);
239.860 + else if (lb == -DBL_MAX)
239.861 + glp_set_col_bnds(csa->P, j, GLP_UP, lb, ub);
239.862 + else if (lb != ub)
239.863 + glp_set_col_bnds(csa->P, j, GLP_DB, lb, ub);
239.864 + else
239.865 + glp_set_col_bnds(csa->P, j, GLP_FX, lb, ub);
239.866 + flag[j] |= (char)mask;
239.867 + /* fields 5 and 6 must be blank */
239.868 + skip_field(csa);
239.869 + skip_field(csa);
239.870 + goto loop;
239.871 +done: /* free working array */
239.872 + xfree(flag);
239.873 + csa->work3 = NULL;
239.874 + return;
239.875 +}
239.876 +
239.877 +int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
239.878 + const char *fname)
239.879 +{ /* read problem data in MPS format */
239.880 + glp_mpscp _parm;
239.881 + struct csa _csa, *csa = &_csa;
239.882 + int ret;
239.883 + xprintf("Reading problem data from `%s'...\n", fname);
239.884 + if (!(fmt == GLP_MPS_DECK || fmt == GLP_MPS_FILE))
239.885 + xerror("glp_read_mps: fmt = %d; invalid parameter\n", fmt);
239.886 + if (parm == NULL)
239.887 + glp_init_mpscp(&_parm), parm = &_parm;
239.888 + /* check control parameters */
239.889 + check_parm("glp_read_mps", parm);
239.890 + /* initialize common storage area */
239.891 + csa->P = P;
239.892 + csa->deck = (fmt == GLP_MPS_DECK);
239.893 + csa->parm = parm;
239.894 + csa->fname = fname;
239.895 + csa->fp = NULL;
239.896 + if (setjmp(csa->jump))
239.897 + { ret = 1;
239.898 + goto done;
239.899 + }
239.900 + csa->recno = csa->recpos = 0;
239.901 + csa->c = '\n';
239.902 + csa->fldno = 0;
239.903 + csa->field[0] = '\0';
239.904 + csa->w80 = csa->wef = 0;
239.905 + csa->obj_row = 0;
239.906 + csa->work1 = csa->work2 = csa->work3 = NULL;
239.907 + /* erase problem object */
239.908 + glp_erase_prob(P);
239.909 + glp_create_index(P);
239.910 + /* open input MPS file */
239.911 + csa->fp = xfopen(fname, "r");
239.912 + if (csa->fp == NULL)
239.913 + { xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
239.914 + ret = 1;
239.915 + goto done;
239.916 + }
239.917 + /* read NAME indicator record */
239.918 + read_name(csa);
239.919 + if (P->name != NULL)
239.920 + xprintf("Problem: %s\n", P->name);
239.921 + /* read ROWS section */
239.922 + if (!(indicator(csa, 0) && strcmp(csa->field, "ROWS") == 0))
239.923 + error(csa, "missing ROWS indicator record\n");
239.924 + read_rows(csa);
239.925 + /* determine objective row */
239.926 + if (parm->obj_name == NULL || parm->obj_name[0] == '\0')
239.927 + { /* use the first row of N type */
239.928 + int i;
239.929 + for (i = 1; i <= P->m; i++)
239.930 + { if (P->row[i]->type == GLP_FR)
239.931 + { csa->obj_row = i;
239.932 + break;
239.933 + }
239.934 + }
239.935 + if (csa->obj_row == 0)
239.936 + warning(csa, "unable to determine objective row\n");
239.937 + }
239.938 + else
239.939 + { /* use a row with specified name */
239.940 + int i;
239.941 + for (i = 1; i <= P->m; i++)
239.942 + { xassert(P->row[i]->name != NULL);
239.943 + if (strcmp(parm->obj_name, P->row[i]->name) == 0)
239.944 + { csa->obj_row = i;
239.945 + break;
239.946 + }
239.947 + }
239.948 + if (csa->obj_row == 0)
239.949 + error(csa, "objective row `%s' not found\n",
239.950 + parm->obj_name);
239.951 + }
239.952 + if (csa->obj_row != 0)
239.953 + { glp_set_obj_name(P, P->row[csa->obj_row]->name);
239.954 + xprintf("Objective: %s\n", P->obj);
239.955 + }
239.956 + /* read COLUMNS section */
239.957 + if (strcmp(csa->field, "COLUMNS") != 0)
239.958 + error(csa, "missing COLUMNS indicator record\n");
239.959 + read_columns(csa);
239.960 + /* set objective coefficients */
239.961 + if (csa->obj_row != 0)
239.962 + { GLPAIJ *aij;
239.963 + for (aij = P->row[csa->obj_row]->ptr; aij != NULL; aij =
239.964 + aij->r_next) glp_set_obj_coef(P, aij->col->j, aij->val);
239.965 + }
239.966 + /* read optional RHS section */
239.967 + if (strcmp(csa->field, "RHS") == 0)
239.968 + read_rhs(csa);
239.969 + /* read optional RANGES section */
239.970 + if (strcmp(csa->field, "RANGES") == 0)
239.971 + read_ranges(csa);
239.972 + /* read optional BOUNDS section */
239.973 + if (strcmp(csa->field, "BOUNDS") == 0)
239.974 + read_bounds(csa);
239.975 + /* read ENDATA indicator record */
239.976 + if (strcmp(csa->field, "ENDATA") != 0)
239.977 + error(csa, "invalid use of %s indicator record\n",
239.978 + csa->field);
239.979 + /* print some statistics */
239.980 + xprintf("%d row%s, %d column%s, %d non-zero%s\n",
239.981 + P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
239.982 + P->nnz, P->nnz == 1 ? "" : "s");
239.983 + if (glp_get_num_int(P) > 0)
239.984 + { int ni = glp_get_num_int(P);
239.985 + int nb = glp_get_num_bin(P);
239.986 + if (ni == 1)
239.987 + { if (nb == 0)
239.988 + xprintf("One variable is integer\n");
239.989 + else
239.990 + xprintf("One variable is binary\n");
239.991 + }
239.992 + else
239.993 + { xprintf("%d integer variables, ", ni);
239.994 + if (nb == 0)
239.995 + xprintf("none");
239.996 + else if (nb == 1)
239.997 + xprintf("one");
239.998 + else if (nb == ni)
239.999 + xprintf("all");
239.1000 + else
239.1001 + xprintf("%d", nb);
239.1002 + xprintf(" of which %s binary\n", nb == 1 ? "is" : "are");
239.1003 + }
239.1004 + }
239.1005 + xprintf("%d records were read\n", csa->recno);
239.1006 + /* problem data has been successfully read */
239.1007 + glp_delete_index(P);
239.1008 + glp_sort_matrix(P);
239.1009 + ret = 0;
239.1010 +done: if (csa->fp != NULL) xfclose(csa->fp);
239.1011 + if (csa->work1 != NULL) xfree(csa->work1);
239.1012 + if (csa->work2 != NULL) xfree(csa->work2);
239.1013 + if (csa->work3 != NULL) xfree(csa->work3);
239.1014 + if (ret != 0) glp_erase_prob(P);
239.1015 + return ret;
239.1016 +}
239.1017 +
239.1018 +/***********************************************************************
239.1019 +* NAME
239.1020 +*
239.1021 +* glp_write_mps - write problem data in MPS format
239.1022 +*
239.1023 +* SYNOPSIS
239.1024 +*
239.1025 +* int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
239.1026 +* const char *fname);
239.1027 +*
239.1028 +* DESCRIPTION
239.1029 +*
239.1030 +* The routine glp_write_mps writes problem data in MPS format to a
239.1031 +* text file.
239.1032 +*
239.1033 +* The parameter fmt specifies the version of MPS format:
239.1034 +*
239.1035 +* GLP_MPS_DECK - fixed (ancient) MPS format;
239.1036 +* GLP_MPS_FILE - free (modern) MPS format.
239.1037 +*
239.1038 +* The parameter parm is a pointer to the structure glp_mpscp, which
239.1039 +* specifies control parameters used by the routine. If parm is NULL,
239.1040 +* the routine uses default settings.
239.1041 +*
239.1042 +* The character string fname specifies a name of the text file to be
239.1043 +* written.
239.1044 +*
239.1045 +* RETURNS
239.1046 +*
239.1047 +* If the operation was successful, the routine glp_read_mps returns
239.1048 +* zero. Otherwise, it prints an error message and returns non-zero. */
239.1049 +
239.1050 +#define csa csa1
239.1051 +
239.1052 +struct csa
239.1053 +{ /* common storage area */
239.1054 + glp_prob *P;
239.1055 + /* pointer to problem object */
239.1056 + int deck;
239.1057 + /* MPS format (0 - free, 1 - fixed) */
239.1058 + const glp_mpscp *parm;
239.1059 + /* pointer to control parameters */
239.1060 + char field[255+1];
239.1061 + /* field buffer */
239.1062 +};
239.1063 +
239.1064 +static char *mps_name(struct csa *csa)
239.1065 +{ /* make problem name */
239.1066 + char *f;
239.1067 + if (csa->P->name == NULL)
239.1068 + csa->field[0] = '\0';
239.1069 + else if (csa->deck)
239.1070 + { strncpy(csa->field, csa->P->name, 8);
239.1071 + csa->field[8] = '\0';
239.1072 + }
239.1073 + else
239.1074 + strcpy(csa->field, csa->P->name);
239.1075 + for (f = csa->field; *f != '\0'; f++)
239.1076 + if (*f == ' ') *f = '_';
239.1077 + return csa->field;
239.1078 +}
239.1079 +
239.1080 +static char *row_name(struct csa *csa, int i)
239.1081 +{ /* make i-th row name */
239.1082 + char *f;
239.1083 + xassert(0 <= i && i <= csa->P->m);
239.1084 + if (i == 0 || csa->P->row[i]->name == NULL ||
239.1085 + csa->deck && strlen(csa->P->row[i]->name) > 8)
239.1086 + sprintf(csa->field, "R%07d", i);
239.1087 + else
239.1088 + { strcpy(csa->field, csa->P->row[i]->name);
239.1089 + for (f = csa->field; *f != '\0'; f++)
239.1090 + if (*f == ' ') *f = '_';
239.1091 + }
239.1092 + return csa->field;
239.1093 +}
239.1094 +
239.1095 +static char *col_name(struct csa *csa, int j)
239.1096 +{ /* make j-th column name */
239.1097 + char *f;
239.1098 + xassert(1 <= j && j <= csa->P->n);
239.1099 + if (csa->P->col[j]->name == NULL ||
239.1100 + csa->deck && strlen(csa->P->col[j]->name) > 8)
239.1101 + sprintf(csa->field, "C%07d", j);
239.1102 + else
239.1103 + { strcpy(csa->field, csa->P->col[j]->name);
239.1104 + for (f = csa->field; *f != '\0'; f++)
239.1105 + if (*f == ' ') *f = '_';
239.1106 + }
239.1107 + return csa->field;
239.1108 +}
239.1109 +
239.1110 +static char *mps_numb(struct csa *csa, double val)
239.1111 +{ /* format floating-point number */
239.1112 + int dig;
239.1113 + char *exp;
239.1114 + for (dig = 12; dig >= 6; dig--)
239.1115 + { if (val != 0.0 && fabs(val) < 0.002)
239.1116 + sprintf(csa->field, "%.*E", dig-1, val);
239.1117 + else
239.1118 + sprintf(csa->field, "%.*G", dig, val);
239.1119 + exp = strchr(csa->field, 'E');
239.1120 + if (exp != NULL)
239.1121 + sprintf(exp+1, "%d", atoi(exp+1));
239.1122 + if (strlen(csa->field) <= 12) break;
239.1123 + }
239.1124 + xassert(strlen(csa->field) <= 12);
239.1125 + return csa->field;
239.1126 +}
239.1127 +
239.1128 +int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
239.1129 + const char *fname)
239.1130 +{ /* write problem data in MPS format */
239.1131 + glp_mpscp _parm;
239.1132 + struct csa _csa, *csa = &_csa;
239.1133 + XFILE *fp;
239.1134 + int out_obj, one_col = 0, empty = 0;
239.1135 + int i, j, recno, marker, count, gap, ret;
239.1136 + xprintf("Writing problem data to `%s'...\n", fname);
239.1137 + if (!(fmt == GLP_MPS_DECK || fmt == GLP_MPS_FILE))
239.1138 + xerror("glp_write_mps: fmt = %d; invalid parameter\n", fmt);
239.1139 + if (parm == NULL)
239.1140 + glp_init_mpscp(&_parm), parm = &_parm;
239.1141 + /* check control parameters */
239.1142 + check_parm("glp_write_mps", parm);
239.1143 + /* initialize common storage area */
239.1144 + csa->P = P;
239.1145 + csa->deck = (fmt == GLP_MPS_DECK);
239.1146 + csa->parm = parm;
239.1147 + /* create output MPS file */
239.1148 + fp = xfopen(fname, "w"), recno = 0;
239.1149 + if (fp == NULL)
239.1150 + { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
239.1151 + ret = 1;
239.1152 + goto done;
239.1153 + }
239.1154 + /* write comment records */
239.1155 + xfprintf(fp, "* %-*s%s\n", P->name == NULL ? 1 : 12, "Problem:",
239.1156 + P->name == NULL ? "" : P->name), recno++;
239.1157 + xfprintf(fp, "* %-12s%s\n", "Class:", glp_get_num_int(P) == 0 ?
239.1158 + "LP" : "MIP"), recno++;
239.1159 + xfprintf(fp, "* %-12s%d\n", "Rows:", P->m), recno++;
239.1160 + if (glp_get_num_int(P) == 0)
239.1161 + xfprintf(fp, "* %-12s%d\n", "Columns:", P->n), recno++;
239.1162 + else
239.1163 + xfprintf(fp, "* %-12s%d (%d integer, %d binary)\n",
239.1164 + "Columns:", P->n, glp_get_num_int(P), glp_get_num_bin(P)),
239.1165 + recno++;
239.1166 + xfprintf(fp, "* %-12s%d\n", "Non-zeros:", P->nnz), recno++;
239.1167 + xfprintf(fp, "* %-12s%s\n", "Format:", csa->deck ? "Fixed MPS" :
239.1168 + "Free MPS"), recno++;
239.1169 + xfprintf(fp, "*\n", recno++);
239.1170 + /* write NAME indicator record */
239.1171 + xfprintf(fp, "NAME%*s%s\n",
239.1172 + P->name == NULL ? 0 : csa->deck ? 10 : 1, "", mps_name(csa)),
239.1173 + recno++;
239.1174 +#if 1
239.1175 + /* determine whether to write the objective row */
239.1176 + out_obj = 1;
239.1177 + for (i = 1; i <= P->m; i++)
239.1178 + { if (P->row[i]->type == GLP_FR)
239.1179 + { out_obj = 0;
239.1180 + break;
239.1181 + }
239.1182 + }
239.1183 +#endif
239.1184 + /* write ROWS section */
239.1185 + xfprintf(fp, "ROWS\n"), recno++;
239.1186 + for (i = (out_obj ? 0 : 1); i <= P->m; i++)
239.1187 + { int type;
239.1188 + type = (i == 0 ? GLP_FR : P->row[i]->type);
239.1189 + if (type == GLP_FR)
239.1190 + type = 'N';
239.1191 + else if (type == GLP_LO)
239.1192 + type = 'G';
239.1193 + else if (type == GLP_UP)
239.1194 + type = 'L';
239.1195 + else if (type == GLP_DB || type == GLP_FX)
239.1196 + type = 'E';
239.1197 + else
239.1198 + xassert(type != type);
239.1199 + xfprintf(fp, " %c%*s%s\n", type, csa->deck ? 2 : 1, "",
239.1200 + row_name(csa, i)), recno++;
239.1201 + }
239.1202 + /* write COLUMNS section */
239.1203 + xfprintf(fp, "COLUMNS\n"), recno++;
239.1204 + marker = 0;
239.1205 + for (j = 1; j <= P->n; j++)
239.1206 + { GLPAIJ cj, *aij;
239.1207 + int kind;
239.1208 + kind = P->col[j]->kind;
239.1209 + if (kind == GLP_CV)
239.1210 + { if (marker % 2 == 1)
239.1211 + { /* close current integer block */
239.1212 + marker++;
239.1213 + xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTEND'\n",
239.1214 + csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "",
239.1215 + csa->deck ? 17 : 1, ""), recno++;
239.1216 + }
239.1217 + }
239.1218 + else if (kind == GLP_IV)
239.1219 + { if (marker % 2 == 0)
239.1220 + { /* open new integer block */
239.1221 + marker++;
239.1222 + xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTORG'\n",
239.1223 + csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "",
239.1224 + csa->deck ? 17 : 1, ""), recno++;
239.1225 + }
239.1226 + }
239.1227 + else
239.1228 + xassert(kind != kind);
239.1229 + if (out_obj && P->col[j]->coef != 0.0)
239.1230 + { /* make fake objective coefficient */
239.1231 + aij = &cj;
239.1232 + aij->row = NULL;
239.1233 + aij->val = P->col[j]->coef;
239.1234 + aij->c_next = P->col[j]->ptr;
239.1235 + }
239.1236 + else
239.1237 + aij = P->col[j]->ptr;
239.1238 +#if 1 /* FIXME */
239.1239 + if (aij == NULL)
239.1240 + { /* empty column */
239.1241 + empty++;
239.1242 + xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
239.1243 + csa->deck ? 8 : 1, col_name(csa, j));
239.1244 + /* we need a row */
239.1245 + xassert(P->m > 0);
239.1246 + xfprintf(fp, "%*s%-*s",
239.1247 + csa->deck ? 2 : 1, "", csa->deck ? 8 : 1,
239.1248 + row_name(csa, 1));
239.1249 + xfprintf(fp, "%*s0%*s$ empty column\n",
239.1250 + csa->deck ? 13 : 1, "", csa->deck ? 3 : 1, ""), recno++;
239.1251 + }
239.1252 +#endif
239.1253 + count = 0;
239.1254 + for (aij = aij; aij != NULL; aij = aij->c_next)
239.1255 + { if (one_col || count % 2 == 0)
239.1256 + xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
239.1257 + csa->deck ? 8 : 1, col_name(csa, j));
239.1258 + gap = (one_col || count % 2 == 0 ? 2 : 3);
239.1259 + xfprintf(fp, "%*s%-*s",
239.1260 + csa->deck ? gap : 1, "", csa->deck ? 8 : 1,
239.1261 + row_name(csa, aij->row == NULL ? 0 : aij->row->i));
239.1262 + xfprintf(fp, "%*s%*s",
239.1263 + csa->deck ? 2 : 1, "", csa->deck ? 12 : 1,
239.1264 + mps_numb(csa, aij->val)), count++;
239.1265 + if (one_col || count % 2 == 0)
239.1266 + xfprintf(fp, "\n"), recno++;
239.1267 + }
239.1268 + if (!(one_col || count % 2 == 0))
239.1269 + xfprintf(fp, "\n"), recno++;
239.1270 + }
239.1271 + if (marker % 2 == 1)
239.1272 + { /* close last integer block */
239.1273 + marker++;
239.1274 + xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTEND'\n",
239.1275 + csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "",
239.1276 + csa->deck ? 17 : 1, ""), recno++;
239.1277 + }
239.1278 +#if 1
239.1279 + if (empty > 0)
239.1280 + xprintf("Warning: problem has %d empty column(s)\n", empty);
239.1281 +#endif
239.1282 + /* write RHS section */
239.1283 + xfprintf(fp, "RHS\n"), recno++;
239.1284 + count = 0;
239.1285 + for (i = (out_obj ? 0 : 1); i <= P->m; i++)
239.1286 + { int type;
239.1287 + double rhs;
239.1288 + if (i == 0)
239.1289 + rhs = P->c0;
239.1290 + else
239.1291 + { type = P->row[i]->type;
239.1292 + if (type == GLP_FR)
239.1293 + rhs = 0.0;
239.1294 + else if (type == GLP_LO)
239.1295 + rhs = P->row[i]->lb;
239.1296 + else if (type == GLP_UP)
239.1297 + rhs = P->row[i]->ub;
239.1298 + else if (type == GLP_DB || type == GLP_FX)
239.1299 + rhs = P->row[i]->lb;
239.1300 + else
239.1301 + xassert(type != type);
239.1302 + }
239.1303 + if (rhs != 0.0)
239.1304 + { if (one_col || count % 2 == 0)
239.1305 + xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
239.1306 + csa->deck ? 8 : 1, "RHS1");
239.1307 + gap = (one_col || count % 2 == 0 ? 2 : 3);
239.1308 + xfprintf(fp, "%*s%-*s",
239.1309 + csa->deck ? gap : 1, "", csa->deck ? 8 : 1,
239.1310 + row_name(csa, i));
239.1311 + xfprintf(fp, "%*s%*s",
239.1312 + csa->deck ? 2 : 1, "", csa->deck ? 12 : 1,
239.1313 + mps_numb(csa, rhs)), count++;
239.1314 + if (one_col || count % 2 == 0)
239.1315 + xfprintf(fp, "\n"), recno++;
239.1316 + }
239.1317 + }
239.1318 + if (!(one_col || count % 2 == 0))
239.1319 + xfprintf(fp, "\n"), recno++;
239.1320 + /* write RANGES section */
239.1321 + for (i = P->m; i >= 1; i--)
239.1322 + if (P->row[i]->type == GLP_DB) break;
239.1323 + if (i == 0) goto bnds;
239.1324 + xfprintf(fp, "RANGES\n"), recno++;
239.1325 + count = 0;
239.1326 + for (i = 1; i <= P->m; i++)
239.1327 + { if (P->row[i]->type == GLP_DB)
239.1328 + { if (one_col || count % 2 == 0)
239.1329 + xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
239.1330 + csa->deck ? 8 : 1, "RNG1");
239.1331 + gap = (one_col || count % 2 == 0 ? 2 : 3);
239.1332 + xfprintf(fp, "%*s%-*s",
239.1333 + csa->deck ? gap : 1, "", csa->deck ? 8 : 1,
239.1334 + row_name(csa, i));
239.1335 + xfprintf(fp, "%*s%*s",
239.1336 + csa->deck ? 2 : 1, "", csa->deck ? 12 : 1,
239.1337 + mps_numb(csa, P->row[i]->ub - P->row[i]->lb)), count++;
239.1338 + if (one_col || count % 2 == 0)
239.1339 + xfprintf(fp, "\n"), recno++;
239.1340 + }
239.1341 + }
239.1342 + if (!(one_col || count % 2 == 0))
239.1343 + xfprintf(fp, "\n"), recno++;
239.1344 +bnds: /* write BOUNDS section */
239.1345 + for (j = P->n; j >= 1; j--)
239.1346 + if (!(P->col[j]->type == GLP_LO && P->col[j]->lb == 0.0))
239.1347 + break;
239.1348 + if (j == 0) goto endt;
239.1349 + xfprintf(fp, "BOUNDS\n"), recno++;
239.1350 + for (j = 1; j <= P->n; j++)
239.1351 + { int type, data[2];
239.1352 + double bnd[2];
239.1353 + char *spec[2];
239.1354 + spec[0] = spec[1] = NULL;
239.1355 + type = P->col[j]->type;
239.1356 + if (type == GLP_FR)
239.1357 + spec[0] = "FR", data[0] = 0;
239.1358 + else if (type == GLP_LO)
239.1359 + { if (P->col[j]->lb != 0.0)
239.1360 + spec[0] = "LO", data[0] = 1, bnd[0] = P->col[j]->lb;
239.1361 + if (P->col[j]->kind == GLP_IV)
239.1362 + spec[1] = "PL", data[1] = 0;
239.1363 + }
239.1364 + else if (type == GLP_UP)
239.1365 + { spec[0] = "MI", data[0] = 0;
239.1366 + spec[1] = "UP", data[1] = 1, bnd[1] = P->col[j]->ub;
239.1367 + }
239.1368 + else if (type == GLP_DB)
239.1369 + { if (P->col[j]->lb != 0.0)
239.1370 + spec[0] = "LO", data[0] = 1, bnd[0] = P->col[j]->lb;
239.1371 + spec[1] = "UP", data[1] = 1, bnd[1] = P->col[j]->ub;
239.1372 + }
239.1373 + else if (type == GLP_FX)
239.1374 + spec[0] = "FX", data[0] = 1, bnd[0] = P->col[j]->lb;
239.1375 + else
239.1376 + xassert(type != type);
239.1377 + for (i = 0; i <= 1; i++)
239.1378 + { if (spec[i] != NULL)
239.1379 + { xfprintf(fp, " %s %-*s%*s%-*s", spec[i],
239.1380 + csa->deck ? 8 : 1, "BND1", csa->deck ? 2 : 1, "",
239.1381 + csa->deck ? 8 : 1, col_name(csa, j));
239.1382 + if (data[i])
239.1383 + xfprintf(fp, "%*s%*s", csa->deck ? 2 : 1, "",
239.1384 + csa->deck ? 12 : 1, mps_numb(csa, bnd[i]));
239.1385 + xfprintf(fp, "\n"), recno++;
239.1386 + }
239.1387 + }
239.1388 + }
239.1389 +endt: /* write ENDATA indicator record */
239.1390 + xfprintf(fp, "ENDATA\n"), recno++;
239.1391 + xfflush(fp);
239.1392 + if (xferror(fp))
239.1393 + { xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
239.1394 + ret = 1;
239.1395 + goto done;
239.1396 + }
239.1397 + /* problem data has been successfully written */
239.1398 + xprintf("%d records were written\n", recno);
239.1399 + ret = 0;
239.1400 +done: if (fp != NULL) xfclose(fp);
239.1401 + return ret;
239.1402 +}
239.1403 +
239.1404 +/* eof */
240.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
240.2 +++ b/src/glpnet.h Mon Dec 06 13:09:21 2010 +0100
240.3 @@ -0,0 +1,60 @@
240.4 +/* glpnet.h (graph and network algorithms) */
240.5 +
240.6 +/***********************************************************************
240.7 +* This code is part of GLPK (GNU Linear Programming Kit).
240.8 +*
240.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
240.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
240.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
240.12 +* E-mail: <mao@gnu.org>.
240.13 +*
240.14 +* GLPK is free software: you can redistribute it and/or modify it
240.15 +* under the terms of the GNU General Public License as published by
240.16 +* the Free Software Foundation, either version 3 of the License, or
240.17 +* (at your option) any later version.
240.18 +*
240.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
240.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
240.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
240.22 +* License for more details.
240.23 +*
240.24 +* You should have received a copy of the GNU General Public License
240.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
240.26 +***********************************************************************/
240.27 +
240.28 +#ifndef GLPNET_H
240.29 +#define GLPNET_H
240.30 +
240.31 +#define mc21a _glp_mc21a
240.32 +int mc21a(int n, const int icn[], const int ip[], const int lenr[],
240.33 + int iperm[], int pr[], int arp[], int cv[], int out[]);
240.34 +/* permutations for zero-free diagonal */
240.35 +
240.36 +#define mc13d _glp_mc13d
240.37 +int mc13d(int n, const int icn[], const int ip[], const int lenr[],
240.38 + int ior[], int ib[], int lowl[], int numb[], int prev[]);
240.39 +/* permutations to block triangular form */
240.40 +
240.41 +#define okalg _glp_okalg
240.42 +int okalg(int nv, int na, const int tail[], const int head[],
240.43 + const int low[], const int cap[], const int cost[], int x[],
240.44 + int pi[]);
240.45 +/* out-of-kilter algorithm */
240.46 +
240.47 +#define ffalg _glp_ffalg
240.48 +void ffalg(int nv, int na, const int tail[], const int head[],
240.49 + int s, int t, const int cap[], int x[], char cut[]);
240.50 +/* Ford-Fulkerson algorithm */
240.51 +
240.52 +#define wclique _glp_wclique
240.53 +int wclique(int n, const int w[], const unsigned char a[], int ind[]);
240.54 +/* find maximum weight clique with Ostergard's algorithm */
240.55 +
240.56 +#define kellerman _glp_kellerman
240.57 +int kellerman(int n, int (*func)(void *info, int i, int ind[]),
240.58 + void *info, void /* glp_graph */ *H);
240.59 +/* cover edges by cliques with Kellerman's heuristic */
240.60 +
240.61 +#endif
240.62 +
240.63 +/* eof */
241.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
241.2 +++ b/src/glpnet01.c Mon Dec 06 13:09:21 2010 +0100
241.3 @@ -0,0 +1,301 @@
241.4 +/* glpnet01.c (permutations for zero-free diagonal) */
241.5 +
241.6 +/***********************************************************************
241.7 +* This code is part of GLPK (GNU Linear Programming Kit).
241.8 +*
241.9 +* This code is the result of translation of the Fortran subroutines
241.10 +* MC21A and MC21B associated with the following paper:
241.11 +*
241.12 +* I.S.Duff, Algorithm 575: Permutations for zero-free diagonal, ACM
241.13 +* Trans. on Math. Softw. 7 (1981), 387-390.
241.14 +*
241.15 +* Use of ACM Algorithms is subject to the ACM Software Copyright and
241.16 +* License Agreement. See <http://www.acm.org/publications/policies>.
241.17 +*
241.18 +* The translation was made by Andrew Makhorin <mao@gnu.org>.
241.19 +*
241.20 +* GLPK is free software: you can redistribute it and/or modify it
241.21 +* under the terms of the GNU General Public License as published by
241.22 +* the Free Software Foundation, either version 3 of the License, or
241.23 +* (at your option) any later version.
241.24 +*
241.25 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
241.26 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
241.27 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
241.28 +* License for more details.
241.29 +*
241.30 +* You should have received a copy of the GNU General Public License
241.31 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
241.32 +***********************************************************************/
241.33 +
241.34 +#include "glpnet.h"
241.35 +
241.36 +/***********************************************************************
241.37 +* NAME
241.38 +*
241.39 +* mc21a - permutations for zero-free diagonal
241.40 +*
241.41 +* SYNOPSIS
241.42 +*
241.43 +* #include "glpnet.h"
241.44 +* int mc21a(int n, const int icn[], const int ip[], const int lenr[],
241.45 +* int iperm[], int pr[], int arp[], int cv[], int out[]);
241.46 +*
241.47 +* DESCRIPTION
241.48 +*
241.49 +* Given the pattern of nonzeros of a sparse matrix, the routine mc21a
241.50 +* attempts to find a permutation of its rows that makes the matrix have
241.51 +* no zeros on its diagonal.
241.52 +*
241.53 +* INPUT PARAMETERS
241.54 +*
241.55 +* n order of matrix.
241.56 +*
241.57 +* icn array containing the column indices of the non-zeros. Those
241.58 +* belonging to a single row must be contiguous but the ordering
241.59 +* of column indices within each row is unimportant and wasted
241.60 +* space between rows is permitted.
241.61 +*
241.62 +* ip ip[i], i = 1,2,...,n, is the position in array icn of the
241.63 +* first column index of a non-zero in row i.
241.64 +*
241.65 +* lenr lenr[i], i = 1,2,...,n, is the number of non-zeros in row i.
241.66 +*
241.67 +* OUTPUT PARAMETER
241.68 +*
241.69 +* iperm contains permutation to make diagonal have the smallest
241.70 +* number of zeros on it. Elements (iperm[i], i), i = 1,2,...,n,
241.71 +* are non-zero at the end of the algorithm unless the matrix is
241.72 +* structurally singular. In this case, (iperm[i], i) will be
241.73 +* zero for n - numnz entries.
241.74 +*
241.75 +* WORKING ARRAYS
241.76 +*
241.77 +* pr working array of length [1+n], where pr[0] is not used.
241.78 +* pr[i] is the previous row to i in the depth first search.
241.79 +*
241.80 +* arp working array of length [1+n], where arp[0] is not used.
241.81 +* arp[i] is one less than the number of non-zeros in row i which
241.82 +* have not been scanned when looking for a cheap assignment.
241.83 +*
241.84 +* cv working array of length [1+n], where cv[0] is not used.
241.85 +* cv[i] is the most recent row extension at which column i was
241.86 +* visited.
241.87 +*
241.88 +* out working array of length [1+n], where out[0] is not used.
241.89 +* out[i] is one less than the number of non-zeros in row i
241.90 +* which have not been scanned during one pass through the main
241.91 +* loop.
241.92 +*
241.93 +* RETURNS
241.94 +*
241.95 +* The routine mc21a returns numnz, the number of non-zeros on diagonal
241.96 +* of permuted matrix. */
241.97 +
241.98 +int mc21a(int n, const int icn[], const int ip[], const int lenr[],
241.99 + int iperm[], int pr[], int arp[], int cv[], int out[])
241.100 +{ int i, ii, in1, in2, j, j1, jord, k, kk, numnz;
241.101 + /* Initialization of arrays. */
241.102 + for (i = 1; i <= n; i++)
241.103 + { arp[i] = lenr[i] - 1;
241.104 + cv[i] = iperm[i] = 0;
241.105 + }
241.106 + numnz = 0;
241.107 + /* Main loop. */
241.108 + /* Each pass round this loop either results in a new assignment
241.109 + or gives a row with no assignment. */
241.110 + for (jord = 1; jord <= n; jord++)
241.111 + { j = jord;
241.112 + pr[j] = -1;
241.113 + for (k = 1; k <= jord; k++)
241.114 + { /* Look for a cheap assignment. */
241.115 + in1 = arp[j];
241.116 + if (in1 >= 0)
241.117 + { in2 = ip[j] + lenr[j] - 1;
241.118 + in1 = in2 - in1;
241.119 + for (ii = in1; ii <= in2; ii++)
241.120 + { i = icn[ii];
241.121 + if (iperm[i] == 0) goto L110;
241.122 + }
241.123 + /* No cheap assignment in row. */
241.124 + arp[j] = -1;
241.125 + }
241.126 + /* Begin looking for assignment chain starting with row j.*/
241.127 + out[j] = lenr[j] - 1;
241.128 + /* Inner loop. Extends chain by one or backtracks. */
241.129 + for (kk = 1; kk <= jord; kk++)
241.130 + { in1 = out[j];
241.131 + if (in1 >= 0)
241.132 + { in2 = ip[j] + lenr[j] - 1;
241.133 + in1 = in2 - in1;
241.134 + /* Forward scan. */
241.135 + for (ii = in1; ii <= in2; ii++)
241.136 + { i = icn[ii];
241.137 + if (cv[i] != jord)
241.138 + { /* Column i has not yet been accessed during
241.139 + this pass. */
241.140 + j1 = j;
241.141 + j = iperm[i];
241.142 + cv[i] = jord;
241.143 + pr[j] = j1;
241.144 + out[j1] = in2 - ii - 1;
241.145 + goto L100;
241.146 + }
241.147 + }
241.148 + }
241.149 + /* Backtracking step. */
241.150 + j = pr[j];
241.151 + if (j == -1) goto L130;
241.152 + }
241.153 +L100: ;
241.154 + }
241.155 +L110: /* New assignment is made. */
241.156 + iperm[i] = j;
241.157 + arp[j] = in2 - ii - 1;
241.158 + numnz++;
241.159 + for (k = 1; k <= jord; k++)
241.160 + { j = pr[j];
241.161 + if (j == -1) break;
241.162 + ii = ip[j] + lenr[j] - out[j] - 2;
241.163 + i = icn[ii];
241.164 + iperm[i] = j;
241.165 + }
241.166 +L130: ;
241.167 + }
241.168 + /* If matrix is structurally singular, we now complete the
241.169 + permutation iperm. */
241.170 + if (numnz < n)
241.171 + { for (i = 1; i <= n; i++)
241.172 + arp[i] = 0;
241.173 + k = 0;
241.174 + for (i = 1; i <= n; i++)
241.175 + { if (iperm[i] == 0)
241.176 + out[++k] = i;
241.177 + else
241.178 + arp[iperm[i]] = i;
241.179 + }
241.180 + k = 0;
241.181 + for (i = 1; i <= n; i++)
241.182 + { if (arp[i] == 0)
241.183 + iperm[out[++k]] = i;
241.184 + }
241.185 + }
241.186 + return numnz;
241.187 +}
241.188 +
241.189 +/**********************************************************************/
241.190 +
241.191 +#if 0
241.192 +#include "glplib.h"
241.193 +
241.194 +int sing;
241.195 +
241.196 +void ranmat(int m, int n, int icn[], int iptr[], int nnnp1, int *knum,
241.197 + int iw[]);
241.198 +
241.199 +void fa01bs(int max, int *nrand);
241.200 +
241.201 +int main(void)
241.202 +{ /* test program for the routine mc21a */
241.203 + /* these runs on random matrices cause all possible statements in
241.204 + mc21a to be executed */
241.205 + int i, iold, j, j1, j2, jj, knum, l, licn, n, nov4, num, numnz;
241.206 + int ip[1+21], icn[1+1000], iperm[1+20], lenr[1+20], iw1[1+80];
241.207 + licn = 1000;
241.208 + /* run on random matrices of orders 1 through 20 */
241.209 + for (n = 1; n <= 20; n++)
241.210 + { nov4 = n / 4;
241.211 + if (nov4 < 1) nov4 = 1;
241.212 +L10: fa01bs(nov4, &l);
241.213 + knum = l * n;
241.214 + /* knum is requested number of non-zeros in random matrix */
241.215 + if (knum > licn) goto L10;
241.216 + /* if sing is false, matrix is guaranteed structurally
241.217 + non-singular */
241.218 + sing = ((n / 2) * 2 == n);
241.219 + /* call to subroutine to generate random matrix */
241.220 + ranmat(n, n, icn, ip, n+1, &knum, iw1);
241.221 + /* knum is now actual number of non-zeros in random matrix */
241.222 + if (knum > licn) goto L10;
241.223 + xprintf("n = %2d; nz = %4d; sing = %d\n", n, knum, sing);
241.224 + /* set up array of row lengths */
241.225 + for (i = 1; i <= n; i++)
241.226 + lenr[i] = ip[i+1] - ip[i];
241.227 + /* call to mc21a */
241.228 + numnz = mc21a(n, icn, ip, lenr, iperm, &iw1[0], &iw1[n],
241.229 + &iw1[n+n], &iw1[n+n+n]);
241.230 + /* testing to see if there are numnz non-zeros on the diagonal
241.231 + of the permuted matrix. */
241.232 + num = 0;
241.233 + for (i = 1; i <= n; i++)
241.234 + { iold = iperm[i];
241.235 + j1 = ip[iold];
241.236 + j2 = j1 + lenr[iold] - 1;
241.237 + if (j2 < j1) continue;
241.238 + for (jj = j1; jj <= j2; jj++)
241.239 + { j = icn[jj];
241.240 + if (j == i)
241.241 + { num++;
241.242 + break;
241.243 + }
241.244 + }
241.245 + }
241.246 + if (num != numnz)
241.247 + xprintf("Failure in mc21a, numnz = %d instead of %d\n",
241.248 + numnz, num);
241.249 + }
241.250 + return 0;
241.251 +}
241.252 +
241.253 +void ranmat(int m, int n, int icn[], int iptr[], int nnnp1, int *knum,
241.254 + int iw[])
241.255 +{ /* subroutine to generate random matrix */
241.256 + int i, ii, inum, j, lrow, matnum;
241.257 + inum = (*knum / n) * 2;
241.258 + if (inum > n-1) inum = n-1;
241.259 + matnum = 1;
241.260 + /* each pass through this loop generates a row of the matrix */
241.261 + for (j = 1; j <= m; j++)
241.262 + { iptr[j] = matnum;
241.263 + if (!(sing || j > n))
241.264 + icn[matnum++] = j;
241.265 + if (n == 1) continue;
241.266 + for (i = 1; i <= n; i++) iw[i] = 0;
241.267 + if (!sing) iw[j] = 1;
241.268 + fa01bs(inum, &lrow);
241.269 + lrow--;
241.270 + if (lrow == 0) continue;
241.271 + /* lrow off-diagonal non-zeros in row j of the matrix */
241.272 + for (ii = 1; ii <= lrow; ii++)
241.273 + { for (;;)
241.274 + { fa01bs(n, &i);
241.275 + if (iw[i] != 1) break;
241.276 + }
241.277 + iw[i] = 1;
241.278 + icn[matnum++] = i;
241.279 + }
241.280 + }
241.281 + for (i = m+1; i <= nnnp1; i++)
241.282 + iptr[i] = matnum;
241.283 + *knum = matnum - 1;
241.284 + return;
241.285 +}
241.286 +
241.287 +double g = 1431655765.0;
241.288 +
241.289 +double fa01as(int i)
241.290 +{ /* random number generator */
241.291 + g = fmod(g * 9228907.0, 4294967296.0);
241.292 + if (i >= 0)
241.293 + return g / 4294967296.0;
241.294 + else
241.295 + return 2.0 * g / 4294967296.0 - 1.0;
241.296 +}
241.297 +
241.298 +void fa01bs(int max, int *nrand)
241.299 +{ *nrand = (int)(fa01as(1) * (double)max) + 1;
241.300 + return;
241.301 +}
241.302 +#endif
241.303 +
241.304 +/* eof */
242.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
242.2 +++ b/src/glpnet02.c Mon Dec 06 13:09:21 2010 +0100
242.3 @@ -0,0 +1,314 @@
242.4 +/* glpnet02.c (permutations to block triangular form) */
242.5 +
242.6 +/***********************************************************************
242.7 +* This code is part of GLPK (GNU Linear Programming Kit).
242.8 +*
242.9 +* This code is the result of translation of the Fortran subroutines
242.10 +* MC13D and MC13E associated with the following paper:
242.11 +*
242.12 +* I.S.Duff, J.K.Reid, Algorithm 529: Permutations to block triangular
242.13 +* form, ACM Trans. on Math. Softw. 4 (1978), 189-192.
242.14 +*
242.15 +* Use of ACM Algorithms is subject to the ACM Software Copyright and
242.16 +* License Agreement. See <http://www.acm.org/publications/policies>.
242.17 +*
242.18 +* The translation was made by Andrew Makhorin <mao@gnu.org>.
242.19 +*
242.20 +* GLPK is free software: you can redistribute it and/or modify it
242.21 +* under the terms of the GNU General Public License as published by
242.22 +* the Free Software Foundation, either version 3 of the License, or
242.23 +* (at your option) any later version.
242.24 +*
242.25 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
242.26 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
242.27 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
242.28 +* License for more details.
242.29 +*
242.30 +* You should have received a copy of the GNU General Public License
242.31 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
242.32 +***********************************************************************/
242.33 +
242.34 +#include "glpnet.h"
242.35 +
242.36 +/***********************************************************************
242.37 +* NAME
242.38 +*
242.39 +* mc13d - permutations to block triangular form
242.40 +*
242.41 +* SYNOPSIS
242.42 +*
242.43 +* #include "glpnet.h"
242.44 +* int mc13d(int n, const int icn[], const int ip[], const int lenr[],
242.45 +* int ior[], int ib[], int lowl[], int numb[], int prev[]);
242.46 +*
242.47 +* DESCRIPTION
242.48 +*
242.49 +* Given the column numbers of the nonzeros in each row of the sparse
242.50 +* matrix, the routine mc13d finds a symmetric permutation that makes
242.51 +* the matrix block lower triangular.
242.52 +*
242.53 +* INPUT PARAMETERS
242.54 +*
242.55 +* n order of the matrix.
242.56 +*
242.57 +* icn array containing the column indices of the non-zeros. Those
242.58 +* belonging to a single row must be contiguous but the ordering
242.59 +* of column indices within each row is unimportant and wasted
242.60 +* space between rows is permitted.
242.61 +*
242.62 +* ip ip[i], i = 1,2,...,n, is the position in array icn of the
242.63 +* first column index of a non-zero in row i.
242.64 +*
242.65 +* lenr lenr[i], i = 1,2,...,n, is the number of non-zeros in row i.
242.66 +*
242.67 +* OUTPUT PARAMETERS
242.68 +*
242.69 +* ior ior[i], i = 1,2,...,n, gives the position on the original
242.70 +* ordering of the row or column which is in position i in the
242.71 +* permuted form.
242.72 +*
242.73 +* ib ib[i], i = 1,2,...,num, is the row number in the permuted
242.74 +* matrix of the beginning of block i, 1 <= num <= n.
242.75 +*
242.76 +* WORKING ARRAYS
242.77 +*
242.78 +* arp working array of length [1+n], where arp[0] is not used.
242.79 +* arp[i] is one less than the number of unsearched edges leaving
242.80 +* node i. At the end of the algorithm it is set to a permutation
242.81 +* which puts the matrix in block lower triangular form.
242.82 +*
242.83 +* ib working array of length [1+n], where ib[0] is not used.
242.84 +* ib[i] is the position in the ordering of the start of the ith
242.85 +* block. ib[n+1-i] holds the node number of the ith node on the
242.86 +* stack.
242.87 +*
242.88 +* lowl working array of length [1+n], where lowl[0] is not used.
242.89 +* lowl[i] is the smallest stack position of any node to which a
242.90 +* path from node i has been found. It is set to n+1 when node i
242.91 +* is removed from the stack.
242.92 +*
242.93 +* numb working array of length [1+n], where numb[0] is not used.
242.94 +* numb[i] is the position of node i in the stack if it is on it,
242.95 +* is the permuted order of node i for those nodes whose final
242.96 +* position has been found and is otherwise zero.
242.97 +*
242.98 +* prev working array of length [1+n], where prev[0] is not used.
242.99 +* prev[i] is the node at the end of the path when node i was
242.100 +* placed on the stack.
242.101 +*
242.102 +* RETURNS
242.103 +*
242.104 +* The routine mc13d returns num, the number of blocks found. */
242.105 +
242.106 +int mc13d(int n, const int icn[], const int ip[], const int lenr[],
242.107 + int ior[], int ib[], int lowl[], int numb[], int prev[])
242.108 +{ int *arp = ior;
242.109 + int dummy, i, i1, i2, icnt, ii, isn, ist, ist1, iv, iw, j, lcnt,
242.110 + nnm1, num, stp;
242.111 + /* icnt is the number of nodes whose positions in final ordering
242.112 + have been found. */
242.113 + icnt = 0;
242.114 + /* num is the number of blocks that have been found. */
242.115 + num = 0;
242.116 + nnm1 = n + n - 1;
242.117 + /* Initialization of arrays. */
242.118 + for (j = 1; j <= n; j++)
242.119 + { numb[j] = 0;
242.120 + arp[j] = lenr[j] - 1;
242.121 + }
242.122 + for (isn = 1; isn <= n; isn++)
242.123 + { /* Look for a starting node. */
242.124 + if (numb[isn] != 0) continue;
242.125 + iv = isn;
242.126 + /* ist is the number of nodes on the stack ... it is the stack
242.127 + pointer. */
242.128 + ist = 1;
242.129 + /* Put node iv at beginning of stack. */
242.130 + lowl[iv] = numb[iv] = 1;
242.131 + ib[n] = iv;
242.132 + /* The body of this loop puts a new node on the stack or
242.133 + backtracks. */
242.134 + for (dummy = 1; dummy <= nnm1; dummy++)
242.135 + { i1 = arp[iv];
242.136 + /* Have all edges leaving node iv been searched? */
242.137 + if (i1 >= 0)
242.138 + { i2 = ip[iv] + lenr[iv] - 1;
242.139 + i1 = i2 - i1;
242.140 + /* Look at edges leaving node iv until one enters a new
242.141 + node or all edges are exhausted. */
242.142 + for (ii = i1; ii <= i2; ii++)
242.143 + { iw = icn[ii];
242.144 + /* Has node iw been on stack already? */
242.145 + if (numb[iw] == 0) goto L70;
242.146 + /* Update value of lowl[iv] if necessary. */
242.147 + if (lowl[iw] < lowl[iv]) lowl[iv] = lowl[iw];
242.148 + }
242.149 + /* There are no more edges leaving node iv. */
242.150 + arp[iv] = -1;
242.151 + }
242.152 + /* Is node iv the root of a block? */
242.153 + if (lowl[iv] < numb[iv]) goto L60;
242.154 + /* Order nodes in a block. */
242.155 + num++;
242.156 + ist1 = n + 1 - ist;
242.157 + lcnt = icnt + 1;
242.158 + /* Peel block off the top of the stack starting at the top
242.159 + and working down to the root of the block. */
242.160 + for (stp = ist1; stp <= n; stp++)
242.161 + { iw = ib[stp];
242.162 + lowl[iw] = n + 1;
242.163 + numb[iw] = ++icnt;
242.164 + if (iw == iv) break;
242.165 + }
242.166 + ist = n - stp;
242.167 + ib[num] = lcnt;
242.168 + /* Are there any nodes left on the stack? */
242.169 + if (ist != 0) goto L60;
242.170 + /* Have all the nodes been ordered? */
242.171 + if (icnt < n) break;
242.172 + goto L100;
242.173 +L60: /* Backtrack to previous node on path. */
242.174 + iw = iv;
242.175 + iv = prev[iv];
242.176 + /* Update value of lowl[iv] if necessary. */
242.177 + if (lowl[iw] < lowl[iv]) lowl[iv] = lowl[iw];
242.178 + continue;
242.179 +L70: /* Put new node on the stack. */
242.180 + arp[iv] = i2 - ii - 1;
242.181 + prev[iw] = iv;
242.182 + iv = iw;
242.183 + lowl[iv] = numb[iv] = ++ist;
242.184 + ib[n+1-ist] = iv;
242.185 + }
242.186 + }
242.187 +L100: /* Put permutation in the required form. */
242.188 + for (i = 1; i <= n; i++)
242.189 + arp[numb[i]] = i;
242.190 + return num;
242.191 +}
242.192 +
242.193 +/**********************************************************************/
242.194 +
242.195 +#if 0
242.196 +#include "glplib.h"
242.197 +
242.198 +void test(int n, int ipp);
242.199 +
242.200 +int main(void)
242.201 +{ /* test program for routine mc13d */
242.202 + test( 1, 0);
242.203 + test( 2, 1);
242.204 + test( 2, 2);
242.205 + test( 3, 3);
242.206 + test( 4, 4);
242.207 + test( 5, 10);
242.208 + test(10, 10);
242.209 + test(10, 20);
242.210 + test(20, 20);
242.211 + test(20, 50);
242.212 + test(50, 50);
242.213 + test(50, 200);
242.214 + return 0;
242.215 +}
242.216 +
242.217 +void fa01bs(int max, int *nrand);
242.218 +
242.219 +void setup(int n, char a[1+50][1+50], int ip[], int icn[], int lenr[]);
242.220 +
242.221 +void test(int n, int ipp)
242.222 +{ int ip[1+50], icn[1+1000], ior[1+50], ib[1+51], iw[1+150],
242.223 + lenr[1+50];
242.224 + char a[1+50][1+50], hold[1+100];
242.225 + int i, ii, iblock, ij, index, j, jblock, jj, k9, num;
242.226 + xprintf("\n\n\nMatrix is of order %d and has %d off-diagonal non-"
242.227 + "zeros\n", n, ipp);
242.228 + for (j = 1; j <= n; j++)
242.229 + { for (i = 1; i <= n; i++)
242.230 + a[i][j] = 0;
242.231 + a[j][j] = 1;
242.232 + }
242.233 + for (k9 = 1; k9 <= ipp; k9++)
242.234 + { /* these statements should be replaced by calls to your
242.235 + favorite random number generator to place two pseudo-random
242.236 + numbers between 1 and n in the variables i and j */
242.237 + for (;;)
242.238 + { fa01bs(n, &i);
242.239 + fa01bs(n, &j);
242.240 + if (!a[i][j]) break;
242.241 + }
242.242 + a[i][j] = 1;
242.243 + }
242.244 + /* setup converts matrix a[i,j] to required sparsity-oriented
242.245 + storage format */
242.246 + setup(n, a, ip, icn, lenr);
242.247 + num = mc13d(n, icn, ip, lenr, ior, ib, &iw[0], &iw[n], &iw[n+n]);
242.248 + /* output reordered matrix with blocking to improve clarity */
242.249 + xprintf("\nThe reordered matrix which has %d block%s is of the fo"
242.250 + "rm\n", num, num == 1 ? "" : "s");
242.251 + ib[num+1] = n + 1;
242.252 + index = 100;
242.253 + iblock = 1;
242.254 + for (i = 1; i <= n; i++)
242.255 + { for (ij = 1; ij <= index; ij++)
242.256 + hold[ij] = ' ';
242.257 + if (i == ib[iblock])
242.258 + { xprintf("\n");
242.259 + iblock++;
242.260 + }
242.261 + jblock = 1;
242.262 + index = 0;
242.263 + for (j = 1; j <= n; j++)
242.264 + { if (j == ib[jblock])
242.265 + { hold[++index] = ' ';
242.266 + jblock++;
242.267 + }
242.268 + ii = ior[i];
242.269 + jj = ior[j];
242.270 + hold[++index] = (char)(a[ii][jj] ? 'X' : '0');
242.271 + }
242.272 + xprintf("%.*s\n", index, &hold[1]);
242.273 + }
242.274 + xprintf("\nThe starting point for each block is given by\n");
242.275 + for (i = 1; i <= num; i++)
242.276 + { if ((i - 1) % 12 == 0) xprintf("\n");
242.277 + xprintf(" %4d", ib[i]);
242.278 + }
242.279 + xprintf("\n");
242.280 + return;
242.281 +}
242.282 +
242.283 +void setup(int n, char a[1+50][1+50], int ip[], int icn[], int lenr[])
242.284 +{ int i, j, ind;
242.285 + for (i = 1; i <= n; i++)
242.286 + lenr[i] = 0;
242.287 + ind = 1;
242.288 + for (i = 1; i <= n; i++)
242.289 + { ip[i] = ind;
242.290 + for (j = 1; j <= n; j++)
242.291 + { if (a[i][j])
242.292 + { lenr[i]++;
242.293 + icn[ind++] = j;
242.294 + }
242.295 + }
242.296 + }
242.297 + return;
242.298 +}
242.299 +
242.300 +double g = 1431655765.0;
242.301 +
242.302 +double fa01as(int i)
242.303 +{ /* random number generator */
242.304 + g = fmod(g * 9228907.0, 4294967296.0);
242.305 + if (i >= 0)
242.306 + return g / 4294967296.0;
242.307 + else
242.308 + return 2.0 * g / 4294967296.0 - 1.0;
242.309 +}
242.310 +
242.311 +void fa01bs(int max, int *nrand)
242.312 +{ *nrand = (int)(fa01as(1) * (double)max) + 1;
242.313 + return;
242.314 +}
242.315 +#endif
242.316 +
242.317 +/* eof */
243.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
243.2 +++ b/src/glpnet03.c Mon Dec 06 13:09:21 2010 +0100
243.3 @@ -0,0 +1,776 @@
243.4 +/* glpnet03.c (Klingman's network problem generator) */
243.5 +
243.6 +/***********************************************************************
243.7 +* This code is part of GLPK (GNU Linear Programming Kit).
243.8 +*
243.9 +* This code is the result of translation of the Fortran program NETGEN
243.10 +* developed by Dr. Darwin Klingman, which is publically available from
243.11 +* NETLIB at <http://www.netlib.org/lp/generators>.
243.12 +*
243.13 +* The translation was made by Andrew Makhorin <mao@gnu.org>.
243.14 +*
243.15 +* GLPK is free software: you can redistribute it and/or modify it
243.16 +* under the terms of the GNU General Public License as published by
243.17 +* the Free Software Foundation, either version 3 of the License, or
243.18 +* (at your option) any later version.
243.19 +*
243.20 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
243.21 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
243.22 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
243.23 +* License for more details.
243.24 +*
243.25 +* You should have received a copy of the GNU General Public License
243.26 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
243.27 +***********************************************************************/
243.28 +
243.29 +#include "glpapi.h"
243.30 +
243.31 +/***********************************************************************
243.32 +* NAME
243.33 +*
243.34 +* glp_netgen - Klingman's network problem generator
243.35 +*
243.36 +* SYNOPSIS
243.37 +*
243.38 +* int glp_netgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
243.39 +* const int parm[1+15]);
243.40 +*
243.41 +* DESCRIPTION
243.42 +*
243.43 +* The routine glp_netgen is a network problem generator developed by
243.44 +* Dr. Darwin Klingman. It can create capacitated and uncapacitated
243.45 +* minimum cost flow (or transshipment), transportation, and assignment
243.46 +* problems.
243.47 +*
243.48 +* The parameter G specifies the graph object, to which the generated
243.49 +* problem data have to be stored. Note that on entry the graph object
243.50 +* is erased with the routine glp_erase_graph.
243.51 +*
243.52 +* The parameter v_rhs specifies an offset of the field of type double
243.53 +* in the vertex data block, to which the routine stores the supply or
243.54 +* demand value. If v_rhs < 0, the value is not stored.
243.55 +*
243.56 +* The parameter a_cap specifies an offset of the field of type double
243.57 +* in the arc data block, to which the routine stores the arc capacity.
243.58 +* If a_cap < 0, the capacity is not stored.
243.59 +*
243.60 +* The parameter a_cost specifies an offset of the field of type double
243.61 +* in the arc data block, to which the routine stores the per-unit cost
243.62 +* if the arc flow. If a_cost < 0, the cost is not stored.
243.63 +*
243.64 +* The array parm contains description of the network to be generated:
243.65 +*
243.66 +* parm[0] not used
243.67 +* parm[1] (iseed) 8-digit positive random number seed
243.68 +* parm[2] (nprob) 8-digit problem id number
243.69 +* parm[3] (nodes) total number of nodes
243.70 +* parm[4] (nsorc) total number of source nodes (including
243.71 +* transshipment nodes)
243.72 +* parm[5] (nsink) total number of sink nodes (including
243.73 +* transshipment nodes)
243.74 +* parm[6] (iarcs) number of arcs
243.75 +* parm[7] (mincst) minimum cost for arcs
243.76 +* parm[8] (maxcst) maximum cost for arcs
243.77 +* parm[9] (itsup) total supply
243.78 +* parm[10] (ntsorc) number of transshipment source nodes
243.79 +* parm[11] (ntsink) number of transshipment sink nodes
243.80 +* parm[12] (iphic) percentage of skeleton arcs to be given
243.81 +* the maximum cost
243.82 +* parm[13] (ipcap) percentage of arcs to be capacitated
243.83 +* parm[14] (mincap) minimum upper bound for capacitated arcs
243.84 +* parm[15] (maxcap) maximum upper bound for capacitated arcs
243.85 +*
243.86 +* The routine generates a transportation problem if:
243.87 +*
243.88 +* nsorc + nsink = nodes, ntsorc = 0, and ntsink = 0.
243.89 +*
243.90 +* The routine generates an assignment problem if the requirements for
243.91 +* a transportation problem are met and:
243.92 +*
243.93 +* nsorc = nsink and itsup = nsorc.
243.94 +*
243.95 +* RETURNS
243.96 +*
243.97 +* If the instance was successfully generated, the routine glp_netgen
243.98 +* returns zero; otherwise, if specified parameters are inconsistent,
243.99 +* the routine returns a non-zero error code.
243.100 +*
243.101 +* REFERENCES
243.102 +*
243.103 +* D.Klingman, A.Napier, and J.Stutz. NETGEN: A program for generating
243.104 +* large scale capacitated assignment, transportation, and minimum cost
243.105 +* flow networks. Management Science 20 (1974), 814-20. */
243.106 +
243.107 +struct csa
243.108 +{ /* common storage area */
243.109 + glp_graph *G;
243.110 + int v_rhs, a_cap, a_cost;
243.111 + int nodes, iarcs, mincst, maxcst, itsup, nsorc, nsink, nonsor,
243.112 + nfsink, narcs, nsort, nftsor, ipcap, mincap, maxcap, ktl,
243.113 + nodlft, *ipred, *ihead, *itail, *iflag, *isup, *lsinks, mult,
243.114 + modul, i15, i16, jran;
243.115 +};
243.116 +
243.117 +#define G (csa->G)
243.118 +#define v_rhs (csa->v_rhs)
243.119 +#define a_cap (csa->a_cap)
243.120 +#define a_cost (csa->a_cost)
243.121 +#define nodes (csa->nodes)
243.122 +#define iarcs (csa->iarcs)
243.123 +#define mincst (csa->mincst)
243.124 +#define maxcst (csa->maxcst)
243.125 +#define itsup (csa->itsup)
243.126 +#define nsorc (csa->nsorc)
243.127 +#define nsink (csa->nsink)
243.128 +#define nonsor (csa->nonsor)
243.129 +#define nfsink (csa->nfsink)
243.130 +#define narcs (csa->narcs)
243.131 +#define nsort (csa->nsort)
243.132 +#define nftsor (csa->nftsor)
243.133 +#define ipcap (csa->ipcap)
243.134 +#define mincap (csa->mincap)
243.135 +#define maxcap (csa->maxcap)
243.136 +#define ktl (csa->ktl)
243.137 +#define nodlft (csa->nodlft)
243.138 +#if 0
243.139 +/* spent a day to find out this bug */
243.140 +#define ist (csa->ist)
243.141 +#else
243.142 +#define ist (ipred[0])
243.143 +#endif
243.144 +#define ipred (csa->ipred)
243.145 +#define ihead (csa->ihead)
243.146 +#define itail (csa->itail)
243.147 +#define iflag (csa->iflag)
243.148 +#define isup (csa->isup)
243.149 +#define lsinks (csa->lsinks)
243.150 +#define mult (csa->mult)
243.151 +#define modul (csa->modul)
243.152 +#define i15 (csa->i15)
243.153 +#define i16 (csa->i16)
243.154 +#define jran (csa->jran)
243.155 +
243.156 +static void cresup(struct csa *csa);
243.157 +static void chain(struct csa *csa, int lpick, int lsorc);
243.158 +static void chnarc(struct csa *csa, int lsorc);
243.159 +static void sort(struct csa *csa);
243.160 +static void pickj(struct csa *csa, int it);
243.161 +static void assign(struct csa *csa);
243.162 +static void setran(struct csa *csa, int iseed);
243.163 +static int iran(struct csa *csa, int ilow, int ihigh);
243.164 +
243.165 +int glp_netgen(glp_graph *G_, int _v_rhs, int _a_cap, int _a_cost,
243.166 + const int parm[1+15])
243.167 +{ struct csa _csa, *csa = &_csa;
243.168 + int iseed, nprob, ntsorc, ntsink, iphic, i, nskel, nltr, ltsink,
243.169 + ntrans, npsink, nftr, npsorc, ntravl, ntrrem, lsorc, lpick,
243.170 + nsksr, nsrchn, j, item, l, ks, k, ksp, li, n, ii, it, ih, icap,
243.171 + jcap, icost, jcost, ret;
243.172 + G = G_;
243.173 + v_rhs = _v_rhs;
243.174 + a_cap = _a_cap;
243.175 + a_cost = _a_cost;
243.176 + if (G != NULL)
243.177 + { if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
243.178 + xerror("glp_netgen: v_rhs = %d; invalid offset\n", v_rhs);
243.179 + if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
243.180 + xerror("glp_netgen: a_cap = %d; invalid offset\n", a_cap);
243.181 + if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
243.182 + xerror("glp_netgen: a_cost = %d; invalid offset\n", a_cost);
243.183 + }
243.184 + /* Input the user's random number seed and fix it if
243.185 + non-positive. */
243.186 + iseed = parm[1];
243.187 + nprob = parm[2];
243.188 + if (iseed <= 0) iseed = 13502460;
243.189 + setran(csa, iseed);
243.190 + /* Input the user's problem characteristics. */
243.191 + nodes = parm[3];
243.192 + nsorc = parm[4];
243.193 + nsink = parm[5];
243.194 + iarcs = parm[6];
243.195 + mincst = parm[7];
243.196 + maxcst = parm[8];
243.197 + itsup = parm[9];
243.198 + ntsorc = parm[10];
243.199 + ntsink = parm[11];
243.200 + iphic = parm[12];
243.201 + ipcap = parm[13];
243.202 + mincap = parm[14];
243.203 + maxcap = parm[15];
243.204 + /* Check the size of the problem. */
243.205 + if (!(10 <= nodes && nodes <= 100000))
243.206 + { ret = 1;
243.207 + goto done;
243.208 + }
243.209 + /* Check user supplied parameters for consistency. */
243.210 + if (!(nsorc >= 0 && nsink >= 0 && nsorc + nsink <= nodes))
243.211 + { ret = 2;
243.212 + goto done;
243.213 + }
243.214 + if (iarcs < 0)
243.215 + { ret = 3;
243.216 + goto done;
243.217 + }
243.218 + if (mincst > maxcst)
243.219 + { ret = 4;
243.220 + goto done;
243.221 + }
243.222 + if (itsup < 0)
243.223 + { ret = 5;
243.224 + goto done;
243.225 + }
243.226 + if (!(0 <= ntsorc && ntsorc <= nsorc))
243.227 + { ret = 6;
243.228 + goto done;
243.229 + }
243.230 + if (!(0 <= ntsink && ntsink <= nsink))
243.231 + { ret = 7;
243.232 + goto done;
243.233 + }
243.234 + if (!(0 <= iphic && iphic <= 100))
243.235 + { ret = 8;
243.236 + goto done;
243.237 + }
243.238 + if (!(0 <= ipcap && ipcap <= 100))
243.239 + { ret = 9;
243.240 + goto done;
243.241 + }
243.242 + if (mincap > maxcap)
243.243 + { ret = 10;
243.244 + goto done;
243.245 + }
243.246 + /* Initailize the graph object. */
243.247 + if (G != NULL)
243.248 + { glp_erase_graph(G, G->v_size, G->a_size);
243.249 + glp_add_vertices(G, nodes);
243.250 + if (v_rhs >= 0)
243.251 + { double zero = 0.0;
243.252 + for (i = 1; i <= nodes; i++)
243.253 + { glp_vertex *v = G->v[i];
243.254 + memcpy((char *)v->data + v_rhs, &zero, sizeof(double));
243.255 + }
243.256 + }
243.257 + }
243.258 + /* Allocate working arrays. */
243.259 + ipred = xcalloc(1+nodes, sizeof(int));
243.260 + ihead = xcalloc(1+nodes, sizeof(int));
243.261 + itail = xcalloc(1+nodes, sizeof(int));
243.262 + iflag = xcalloc(1+nodes, sizeof(int));
243.263 + isup = xcalloc(1+nodes, sizeof(int));
243.264 + lsinks = xcalloc(1+nodes, sizeof(int));
243.265 + /* Print the problem documentation records. */
243.266 + if (G == NULL)
243.267 + { xprintf("BEGIN\n");
243.268 + xprintf("NETGEN PROBLEM%8d%10s%10d NODES AND%10d ARCS\n",
243.269 + nprob, "", nodes, iarcs);
243.270 + xprintf("USER:%11d%11d%11d%11d%11d%11d\nDATA:%11d%11d%11d%11d%"
243.271 + "11d%11d\n", iseed, nsorc, nsink, mincst,
243.272 + maxcst, itsup, ntsorc, ntsink, iphic, ipcap,
243.273 + mincap, maxcap);
243.274 + }
243.275 + else
243.276 + glp_set_graph_name(G, "NETGEN");
243.277 + /* Set various constants used in the program. */
243.278 + narcs = 0;
243.279 + nskel = 0;
243.280 + nltr = nodes - nsink;
243.281 + ltsink = nltr + ntsink;
243.282 + ntrans = nltr - nsorc;
243.283 + nfsink = nltr + 1;
243.284 + nonsor = nodes - nsorc + ntsorc;
243.285 + npsink = nsink - ntsink;
243.286 + nodlft = nodes - nsink + ntsink;
243.287 + nftr = nsorc + 1;
243.288 + nftsor = nsorc - ntsorc + 1;
243.289 + npsorc = nsorc - ntsorc;
243.290 + /* Randomly distribute the supply among the source nodes. */
243.291 + if (npsorc + npsink == nodes && npsorc == npsink &&
243.292 + itsup == nsorc)
243.293 + { assign(csa);
243.294 + nskel = nsorc;
243.295 + goto L390;
243.296 + }
243.297 + cresup(csa);
243.298 + /* Print the supply records. */
243.299 + if (G == NULL)
243.300 + { xprintf("SUPPLY\n");
243.301 + for (i = 1; i <= nsorc; i++)
243.302 + xprintf("%6s%6d%18s%10d\n", "", i, "", isup[i]);
243.303 + xprintf("ARCS\n");
243.304 + }
243.305 + else
243.306 + { if (v_rhs >= 0)
243.307 + { for (i = 1; i <= nsorc; i++)
243.308 + { double temp = (double)isup[i];
243.309 + glp_vertex *v = G->v[i];
243.310 + memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
243.311 + }
243.312 + }
243.313 + }
243.314 + /* Make the sources point to themselves in ipred array. */
243.315 + for (i = 1; i <= nsorc; i++)
243.316 + ipred[i] = i;
243.317 + if (ntrans == 0) goto L170;
243.318 + /* Chain the transshipment nodes together in the ipred array. */
243.319 + ist = nftr;
243.320 + ipred[nltr] = 0;
243.321 + for (i = nftr; i < nltr; i++)
243.322 + ipred[i] = i+1;
243.323 + /* Form even length chains for 60 percent of the transshipments.*/
243.324 + ntravl = 6 * ntrans / 10;
243.325 + ntrrem = ntrans - ntravl;
243.326 +L140: lsorc = 1;
243.327 + while (ntravl != 0)
243.328 + { lpick = iran(csa, 1, ntravl + ntrrem);
243.329 + ntravl--;
243.330 + chain(csa, lpick, lsorc);
243.331 + if (lsorc == nsorc) goto L140;
243.332 + lsorc++;
243.333 + }
243.334 + /* Add the remaining transshipments to the chains. */
243.335 + while (ntrrem != 0)
243.336 + {
243.337 + lpick = iran(csa, 1, ntrrem);
243.338 + ntrrem--;
243.339 + lsorc = iran(csa, 1, nsorc);
243.340 + chain(csa, lpick, lsorc);
243.341 + }
243.342 +L170: /* Set all demands equal to zero. */
243.343 + for (i = nfsink; i <= nodes; i++)
243.344 + ipred[i] = 0;
243.345 + /* The following loop takes one chain at a time (through the use
243.346 + of logic contained in the loop and calls to other routines) and
243.347 + creates the remaining network arcs. */
243.348 + for (lsorc = 1; lsorc <= nsorc; lsorc++)
243.349 + { chnarc(csa, lsorc);
243.350 + for (i = nfsink; i <= nodes; i++)
243.351 + iflag[i] = 0;
243.352 + /* Choose the number of sinks to be hooked up to the current
243.353 + chain. */
243.354 + if (ntrans != 0)
243.355 + nsksr = (nsort * 2 * nsink) / ntrans;
243.356 + else
243.357 + nsksr = nsink / nsorc + 1;
243.358 + if (nsksr < 2) nsksr = 2;
243.359 + if (nsksr > nsink) nsksr = nsink;
243.360 + nsrchn = nsort;
243.361 + /* Randomly pick nsksr sinks and put their names in lsinks. */
243.362 + ktl = nsink;
243.363 + for (j = 1; j <= nsksr; j++)
243.364 + { item = iran(csa, 1, ktl);
243.365 + ktl--;
243.366 + for (l = nfsink; l <= nodes; l++)
243.367 + { if (iflag[l] != 1)
243.368 + { item--;
243.369 + if (item == 0) goto L230;
243.370 + }
243.371 + }
243.372 + break;
243.373 +L230: lsinks[j] = l;
243.374 + iflag[l] = 1;
243.375 + }
243.376 + /* If last source chain, add all sinks with zero demand to
243.377 + lsinks list. */
243.378 + if (lsorc == nsorc)
243.379 + { for (j = nfsink; j <= nodes; j++)
243.380 + { if (ipred[j] == 0 && iflag[j] != 1)
243.381 + { nsksr++;
243.382 + lsinks[nsksr] = j;
243.383 + iflag[j] = 1;
243.384 + }
243.385 + }
243.386 + }
243.387 + /* Create demands for group of sinks in lsinks. */
243.388 + ks = isup[lsorc] / nsksr;
243.389 + k = ipred[lsorc];
243.390 + for (i = 1; i <= nsksr; i++)
243.391 + { nsort++;
243.392 + ksp = iran(csa, 1, ks);
243.393 + j = iran(csa, 1, nsksr);
243.394 + itail[nsort] = k;
243.395 + li = lsinks[i];
243.396 + ihead[nsort] = li;
243.397 + ipred[li] += ksp;
243.398 + li = lsinks[j];
243.399 + ipred[li] += ks - ksp;
243.400 + n = iran(csa, 1, nsrchn);
243.401 + k = lsorc;
243.402 + for (ii = 1; ii <= n; ii++)
243.403 + k = ipred[k];
243.404 + }
243.405 + li = lsinks[1];
243.406 + ipred[li] += isup[lsorc] - ks * nsksr;
243.407 + nskel += nsort;
243.408 + /* Sort the arcs in the chain from source lsorc using itail as
243.409 + sort key. */
243.410 + sort(csa);
243.411 + /* Print this part of skeleton and create the arcs for these
243.412 + nodes. */
243.413 + i = 1;
243.414 + itail[nsort+1] = 0;
243.415 +L300: for (j = nftsor; j <= nodes; j++)
243.416 + iflag[j] = 0;
243.417 + ktl = nonsor - 1;
243.418 + it = itail[i];
243.419 + iflag[it] = 1;
243.420 +L320: ih = ihead[i];
243.421 + iflag[ih] = 1;
243.422 + narcs++;
243.423 + ktl--;
243.424 + /* Determine if this skeleton arc should be capacitated. */
243.425 + icap = itsup;
243.426 + jcap = iran(csa, 1, 100);
243.427 + if (jcap <= ipcap)
243.428 + { icap = isup[lsorc];
243.429 + if (mincap > icap) icap = mincap;
243.430 + }
243.431 + /* Determine if this skeleton arc should have the maximum
243.432 + cost. */
243.433 + icost = maxcst;
243.434 + jcost = iran(csa, 1, 100);
243.435 + if (jcost > iphic)
243.436 + icost = iran(csa, mincst, maxcst);
243.437 + if (G == NULL)
243.438 + xprintf("%6s%6d%6d%2s%10d%10d\n", "", it, ih, "", icost,
243.439 + icap);
243.440 + else
243.441 + { glp_arc *a = glp_add_arc(G, it, ih);
243.442 + if (a_cap >= 0)
243.443 + { double temp = (double)icap;
243.444 + memcpy((char *)a->data + a_cap, &temp, sizeof(double));
243.445 + }
243.446 + if (a_cost >= 0)
243.447 + { double temp = (double)icost;
243.448 + memcpy((char *)a->data + a_cost, &temp, sizeof(double));
243.449 + }
243.450 + }
243.451 + i++;
243.452 + if (itail[i] == it) goto L320;
243.453 + pickj(csa, it);
243.454 + if (i <= nsort) goto L300;
243.455 + }
243.456 + /* Create arcs from the transshipment sinks. */
243.457 + if (ntsink != 0)
243.458 + { for (i = nfsink; i <= ltsink; i++)
243.459 + { for (j = nftsor; j <= nodes; j++)
243.460 + iflag[j] = 0;
243.461 + ktl = nonsor - 1;
243.462 + iflag[i] = 1;
243.463 + pickj(csa, i);
243.464 + }
243.465 + }
243.466 +L390: /* Print the demand records and end record. */
243.467 + if (G == NULL)
243.468 + { xprintf("DEMAND\n");
243.469 + for (i = nfsink; i <= nodes; i++)
243.470 + xprintf("%6s%6d%18s%10d\n", "", i, "", ipred[i]);
243.471 + xprintf("END\n");
243.472 + }
243.473 + else
243.474 + { if (v_rhs >= 0)
243.475 + { for (i = nfsink; i <= nodes; i++)
243.476 + { double temp = - (double)ipred[i];
243.477 + glp_vertex *v = G->v[i];
243.478 + memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
243.479 + }
243.480 + }
243.481 + }
243.482 + /* Free working arrays. */
243.483 + xfree(ipred);
243.484 + xfree(ihead);
243.485 + xfree(itail);
243.486 + xfree(iflag);
243.487 + xfree(isup);
243.488 + xfree(lsinks);
243.489 + /* The instance has been successfully generated. */
243.490 + ret = 0;
243.491 +done: return ret;
243.492 +}
243.493 +
243.494 +/***********************************************************************
243.495 +* The routine cresup randomly distributes the total supply among the
243.496 +* source nodes. */
243.497 +
243.498 +static void cresup(struct csa *csa)
243.499 +{ int i, j, ks, ksp;
243.500 + xassert(itsup > nsorc);
243.501 + ks = itsup / nsorc;
243.502 + for (i = 1; i <= nsorc; i++)
243.503 + isup[i] = 0;
243.504 + for (i = 1; i <= nsorc; i++)
243.505 + { ksp = iran(csa, 1, ks);
243.506 + j = iran(csa, 1, nsorc);
243.507 + isup[i] += ksp;
243.508 + isup[j] += ks - ksp;
243.509 + }
243.510 + j = iran(csa, 1, nsorc);
243.511 + isup[j] += itsup - ks * nsorc;
243.512 + return;
243.513 +}
243.514 +
243.515 +/***********************************************************************
243.516 +* The routine chain adds node lpick to the end of the chain with source
243.517 +* node lsorc. */
243.518 +
243.519 +static void chain(struct csa *csa, int lpick, int lsorc)
243.520 +{ int i, j, k, l, m;
243.521 + k = 0;
243.522 + m = ist;
243.523 + for (i = 1; i <= lpick; i++)
243.524 + { l = k;
243.525 + k = m;
243.526 + m = ipred[k];
243.527 + }
243.528 + ipred[l] = m;
243.529 + j = ipred[lsorc];
243.530 + ipred[k] = j;
243.531 + ipred[lsorc] = k;
243.532 + return;
243.533 +}
243.534 +
243.535 +/***********************************************************************
243.536 +* The routine chnarc puts the arcs in the chain from source lsorc into
243.537 +* the ihead and itail arrays for sorting. */
243.538 +
243.539 +static void chnarc(struct csa *csa, int lsorc)
243.540 +{ int ito, ifrom;
243.541 + nsort = 0;
243.542 + ito = ipred[lsorc];
243.543 +L10: if (ito == lsorc) return;
243.544 + nsort++;
243.545 + ifrom = ipred[ito];
243.546 + ihead[nsort] = ito;
243.547 + itail[nsort] = ifrom;
243.548 + ito = ifrom;
243.549 + goto L10;
243.550 +}
243.551 +
243.552 +/***********************************************************************
243.553 +* The routine sort sorts the nsort arcs in the ihead and itail arrays.
243.554 +* ihead is used as the sort key (i.e. forward star sort order). */
243.555 +
243.556 +static void sort(struct csa *csa)
243.557 +{ int i, j, k, l, m, n, it;
243.558 + n = nsort;
243.559 + m = n;
243.560 +L10: m /= 2;
243.561 + if (m == 0) return;
243.562 + k = n - m;
243.563 + j = 1;
243.564 +L20: i = j;
243.565 +L30: l = i + m;
243.566 + if (itail[i] <= itail[l]) goto L40;
243.567 + it = itail[i];
243.568 + itail[i] = itail[l];
243.569 + itail[l] = it;
243.570 + it = ihead[i];
243.571 + ihead[i] = ihead[l];
243.572 + ihead[l] = it;
243.573 + i -= m;
243.574 + if (i >= 1) goto L30;
243.575 +L40: j++;
243.576 + if (j <= k) goto L20;
243.577 + goto L10;
243.578 +}
243.579 +
243.580 +/***********************************************************************
243.581 +* The routine pickj creates a random number of arcs out of node 'it'.
243.582 +* Various parameters are dynamically adjusted in an attempt to ensure
243.583 +* that the generated network has the correct number of arcs. */
243.584 +
243.585 +static void pickj(struct csa *csa, int it)
243.586 +{ int j, k, l, nn, nupbnd, icap, jcap, icost;
243.587 + if ((nodlft - 1) * 2 > iarcs - narcs - 1)
243.588 + { nodlft--;
243.589 + return;
243.590 + }
243.591 + if ((iarcs - narcs + nonsor - ktl - 1) / nodlft - nonsor + 1 >= 0)
243.592 + k = nonsor;
243.593 + else
243.594 + { nupbnd = (iarcs - narcs - nodlft) / nodlft * 2;
243.595 +L40: k = iran(csa, 1, nupbnd);
243.596 + if (nodlft == 1) k = iarcs - narcs;
243.597 + if ((nodlft - 1) * (nonsor - 1) < iarcs - narcs - k) goto L40;
243.598 + }
243.599 + nodlft--;
243.600 + for (j = 1; j <= k; j++)
243.601 + { nn = iran(csa, 1, ktl);
243.602 + ktl--;
243.603 + for (l = nftsor; l <= nodes; l++)
243.604 + { if (iflag[l] != 1)
243.605 + { nn--;
243.606 + if (nn == 0) goto L70;
243.607 + }
243.608 + }
243.609 + return;
243.610 +L70: iflag[l] = 1;
243.611 + icap = itsup;
243.612 + jcap = iran(csa, 1, 100);
243.613 + if (jcap <= ipcap)
243.614 + icap = iran(csa, mincap, maxcap);
243.615 + icost = iran(csa, mincst, maxcst);
243.616 + if (G == NULL)
243.617 + xprintf("%6s%6d%6d%2s%10d%10d\n", "", it, l, "", icost,
243.618 + icap);
243.619 + else
243.620 + { glp_arc *a = glp_add_arc(G, it, l);
243.621 + if (a_cap >= 0)
243.622 + { double temp = (double)icap;
243.623 + memcpy((char *)a->data + a_cap, &temp, sizeof(double));
243.624 + }
243.625 + if (a_cost >= 0)
243.626 + { double temp = (double)icost;
243.627 + memcpy((char *)a->data + a_cost, &temp, sizeof(double));
243.628 + }
243.629 + }
243.630 + narcs++;
243.631 + }
243.632 + return;
243.633 +}
243.634 +
243.635 +/***********************************************************************
243.636 +* The routine assign generate assignment problems. It defines the unit
243.637 +* supplies, builds a skeleton, then calls pickj to create the arcs. */
243.638 +
243.639 +static void assign(struct csa *csa)
243.640 +{ int i, it, nn, l, ll, icost;
243.641 + if (G == NULL)
243.642 + xprintf("SUPPLY\n");
243.643 + for (i = 1; i <= nsorc; i++)
243.644 + { isup[i] = 1;
243.645 + iflag[i] = 0;
243.646 + if (G == NULL)
243.647 + xprintf("%6s%6d%18s%10d\n", "", i, "", isup[i]);
243.648 + else
243.649 + { if (v_rhs >= 0)
243.650 + { double temp = (double)isup[i];
243.651 + glp_vertex *v = G->v[i];
243.652 + memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
243.653 + }
243.654 + }
243.655 + }
243.656 + if (G == NULL)
243.657 + xprintf("ARCS\n");
243.658 + for (i = nfsink; i <= nodes; i++)
243.659 + ipred[i] = 1;
243.660 + for (it = 1; it <= nsorc; it++)
243.661 + { for (i = nfsink; i <= nodes; i++)
243.662 + iflag[i] = 0;
243.663 + ktl = nsink - 1;
243.664 + nn = iran(csa, 1, nsink - it + 1);
243.665 + for (l = 1; l <= nsorc; l++)
243.666 + { if (iflag[l] != 1)
243.667 + { nn--;
243.668 + if (nn == 0) break;
243.669 + }
243.670 + }
243.671 + narcs++;
243.672 + ll = nsorc + l;
243.673 + icost = iran(csa, mincst, maxcst);
243.674 + if (G == NULL)
243.675 + xprintf("%6s%6d%6d%2s%10d%10d\n", "", it, ll, "", icost,
243.676 + isup[1]);
243.677 + else
243.678 + { glp_arc *a = glp_add_arc(G, it, ll);
243.679 + if (a_cap >= 0)
243.680 + { double temp = (double)isup[1];
243.681 + memcpy((char *)a->data + a_cap, &temp, sizeof(double));
243.682 + }
243.683 + if (a_cost >= 0)
243.684 + { double temp = (double)icost;
243.685 + memcpy((char *)a->data + a_cost, &temp, sizeof(double));
243.686 + }
243.687 + }
243.688 + iflag[l] = 1;
243.689 + iflag[ll] = 1;
243.690 + pickj(csa, it);
243.691 + }
243.692 + return;
243.693 +}
243.694 +
243.695 +/***********************************************************************
243.696 +* Portable congruential (uniform) random number generator:
243.697 +*
243.698 +* next_value = ((7**5) * previous_value) modulo ((2**31)-1)
243.699 +*
243.700 +* This generator consists of three routines:
243.701 +*
243.702 +* (1) setran - initializes constants and seed
243.703 +* (2) iran - generates an integer random number
243.704 +* (3) rran - generates a real random number
243.705 +*
243.706 +* The generator requires a machine with at least 32 bits of precision.
243.707 +* The seed (iseed) must be in the range [1,(2**31)-1]. */
243.708 +
243.709 +static void setran(struct csa *csa, int iseed)
243.710 +{ xassert(iseed >= 1);
243.711 + mult = 16807;
243.712 + modul = 2147483647;
243.713 + i15 = 1 << 15;
243.714 + i16 = 1 << 16;
243.715 + jran = iseed;
243.716 + return;
243.717 +}
243.718 +
243.719 +/***********************************************************************
243.720 +* The routine iran generates an integer random number between ilow and
243.721 +* ihigh. If ilow > ihigh then iran returns ihigh. */
243.722 +
243.723 +static int iran(struct csa *csa, int ilow, int ihigh)
243.724 +{ int ixhi, ixlo, ixalo, leftlo, ixahi, ifulhi, irtlo, iover,
243.725 + irthi, j;
243.726 + ixhi = jran / i16;
243.727 + ixlo = jran - ixhi * i16;
243.728 + ixalo = ixlo * mult;
243.729 + leftlo = ixalo / i16;
243.730 + ixahi = ixhi * mult;
243.731 + ifulhi = ixahi + leftlo;
243.732 + irtlo = ixalo - leftlo * i16;
243.733 + iover = ifulhi / i15;
243.734 + irthi = ifulhi - iover * i15;
243.735 + jran = ((irtlo - modul) + irthi * i16) + iover;
243.736 + if (jran < 0) jran += modul;
243.737 + j = ihigh - ilow + 1;
243.738 + if (j > 0)
243.739 + return jran % j + ilow;
243.740 + else
243.741 + return ihigh;
243.742 +}
243.743 +
243.744 +/**********************************************************************/
243.745 +
243.746 +#if 0
243.747 +static int scan(char card[80+1], int pos, int len)
243.748 +{ char buf[10+1];
243.749 + memcpy(buf, &card[pos-1], len);
243.750 + buf[len] = '\0';
243.751 + return atoi(buf);
243.752 +}
243.753 +
243.754 +int main(void)
243.755 +{ int parm[1+15];
243.756 + char card[80+1];
243.757 + xassert(fgets(card, sizeof(card), stdin) == card);
243.758 + parm[1] = scan(card, 1, 8);
243.759 + parm[2] = scan(card, 9, 8);
243.760 + xassert(fgets(card, sizeof(card), stdin) == card);
243.761 + parm[3] = scan(card, 1, 5);
243.762 + parm[4] = scan(card, 6, 5);
243.763 + parm[5] = scan(card, 11, 5);
243.764 + parm[6] = scan(card, 16, 5);
243.765 + parm[7] = scan(card, 21, 5);
243.766 + parm[8] = scan(card, 26, 5);
243.767 + parm[9] = scan(card, 31, 10);
243.768 + parm[10] = scan(card, 41, 5);
243.769 + parm[11] = scan(card, 46, 5);
243.770 + parm[12] = scan(card, 51, 5);
243.771 + parm[13] = scan(card, 56, 5);
243.772 + parm[14] = scan(card, 61, 10);
243.773 + parm[15] = scan(card, 71, 10);
243.774 + glp_netgen(NULL, 0, 0, 0, parm);
243.775 + return 0;
243.776 +}
243.777 +#endif
243.778 +
243.779 +/* eof */
244.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
244.2 +++ b/src/glpnet04.c Mon Dec 06 13:09:21 2010 +0100
244.3 @@ -0,0 +1,768 @@
244.4 +/* glpnet04.c (grid-like network problem generator) */
244.5 +
244.6 +/***********************************************************************
244.7 +* This code is part of GLPK (GNU Linear Programming Kit).
244.8 +*
244.9 +* This code is a modified version of the program GRIDGEN, a grid-like
244.10 +* network problem generator developed by Yusin Lee and Jim Orlin.
244.11 +* The original code is publically available on the DIMACS ftp site at:
244.12 +* <ftp://dimacs.rutgers.edu/pub/netflow/generators/network/gridgen>.
244.13 +*
244.14 +* All changes concern only the program interface, so this modified
244.15 +* version produces exactly the same instances as the original version.
244.16 +*
244.17 +* Changes were made by Andrew Makhorin <mao@gnu.org>.
244.18 +*
244.19 +* GLPK is free software: you can redistribute it and/or modify it
244.20 +* under the terms of the GNU General Public License as published by
244.21 +* the Free Software Foundation, either version 3 of the License, or
244.22 +* (at your option) any later version.
244.23 +*
244.24 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
244.25 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
244.26 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
244.27 +* License for more details.
244.28 +*
244.29 +* You should have received a copy of the GNU General Public License
244.30 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
244.31 +***********************************************************************/
244.32 +
244.33 +#include "glpapi.h"
244.34 +
244.35 +/***********************************************************************
244.36 +* NAME
244.37 +*
244.38 +* glp_gridgen - grid-like network problem generator
244.39 +*
244.40 +* SYNOPSIS
244.41 +*
244.42 +* int glp_gridgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
244.43 +* const int parm[1+14]);
244.44 +*
244.45 +* DESCRIPTION
244.46 +*
244.47 +* The routine glp_gridgen is a grid-like network problem generator
244.48 +* developed by Yusin Lee and Jim Orlin.
244.49 +*
244.50 +* The parameter G specifies the graph object, to which the generated
244.51 +* problem data have to be stored. Note that on entry the graph object
244.52 +* is erased with the routine glp_erase_graph.
244.53 +*
244.54 +* The parameter v_rhs specifies an offset of the field of type double
244.55 +* in the vertex data block, to which the routine stores the supply or
244.56 +* demand value. If v_rhs < 0, the value is not stored.
244.57 +*
244.58 +* The parameter a_cap specifies an offset of the field of type double
244.59 +* in the arc data block, to which the routine stores the arc capacity.
244.60 +* If a_cap < 0, the capacity is not stored.
244.61 +*
244.62 +* The parameter a_cost specifies an offset of the field of type double
244.63 +* in the arc data block, to which the routine stores the per-unit cost
244.64 +* if the arc flow. If a_cost < 0, the cost is not stored.
244.65 +*
244.66 +* The array parm contains description of the network to be generated:
244.67 +*
244.68 +* parm[0] not used
244.69 +* parm[1] two-ways arcs indicator:
244.70 +* 1 - if links in both direction should be generated
244.71 +* 0 - otherwise
244.72 +* parm[2] random number seed (a positive integer)
244.73 +* parm[3] number of nodes (the number of nodes generated might be
244.74 +* slightly different to make the network a grid)
244.75 +* parm[4] grid width
244.76 +* parm[5] number of sources
244.77 +* parm[6] number of sinks
244.78 +* parm[7] average degree
244.79 +* parm[8] total flow
244.80 +* parm[9] distribution of arc costs:
244.81 +* 1 - uniform
244.82 +* 2 - exponential
244.83 +* parm[10] lower bound for arc cost (uniform)
244.84 +* 100 * lambda (exponential)
244.85 +* parm[11] upper bound for arc cost (uniform)
244.86 +* not used (exponential)
244.87 +* parm[12] distribution of arc capacities:
244.88 +* 1 - uniform
244.89 +* 2 - exponential
244.90 +* parm[13] lower bound for arc capacity (uniform)
244.91 +* 100 * lambda (exponential)
244.92 +* parm[14] upper bound for arc capacity (uniform)
244.93 +* not used (exponential)
244.94 +*
244.95 +* RETURNS
244.96 +*
244.97 +* If the instance was successfully generated, the routine glp_gridgen
244.98 +* returns zero; otherwise, if specified parameters are inconsistent,
244.99 +* the routine returns a non-zero error code.
244.100 +*
244.101 +* COMMENTS
244.102 +*
244.103 +* This network generator generates a grid-like network plus a super
244.104 +* node. In additional to the arcs connecting the nodes in the grid,
244.105 +* there is an arc from each supply node to the super node and from the
244.106 +* super node to each demand node to guarantee feasiblity. These arcs
244.107 +* have very high costs and very big capacities.
244.108 +*
244.109 +* The idea of this network generator is as follows: First, a grid of
244.110 +* n1 * n2 is generated. For example, 5 * 3. The nodes are numbered as
244.111 +* 1 to 15, and the supernode is numbered as n1*n2+1. Then arcs between
244.112 +* adjacent nodes are generated. For these arcs, the user is allowed to
244.113 +* specify either to generate two-way arcs or one-way arcs. If two-way
244.114 +* arcs are to be generated, two arcs, one in each direction, will be
244.115 +* generated between each adjacent node pairs. Otherwise, only one arc
244.116 +* will be generated. If this is the case, the arcs will be generated
244.117 +* in alterntive directions as shown below.
244.118 +*
244.119 +* 1 ---> 2 ---> 3 ---> 4 ---> 5
244.120 +* | ^ | ^ |
244.121 +* | | | | |
244.122 +* V | V | V
244.123 +* 6 <--- 7 <--- 8 <--- 9 <--- 10
244.124 +* | ^ | ^ |
244.125 +* | | | | |
244.126 +* V | V | V
244.127 +* 11 --->12 --->13 --->14 ---> 15
244.128 +*
244.129 +* Then the arcs between the super node and the source/sink nodes are
244.130 +* added as mentioned before. If the number of arcs still doesn't reach
244.131 +* the requirement, additional arcs will be added by uniformly picking
244.132 +* random node pairs. There is no checking to prevent multiple arcs
244.133 +* between any pair of nodes. However, there will be no self-arcs (arcs
244.134 +* that poins back to its tail node) in the network.
244.135 +*
244.136 +* The source and sink nodes are selected uniformly in the network, and
244.137 +* the imbalances of each source/sink node are also assigned by uniform
244.138 +* distribution. */
244.139 +
244.140 +struct stat_para
244.141 +{ /* structure for statistical distributions */
244.142 + int distribution;
244.143 + /* the distribution: */
244.144 +#define UNIFORM 1 /* uniform distribution */
244.145 +#define EXPONENTIAL 2 /* exponential distribution */
244.146 + double parameter[5];
244.147 + /* the parameters of the distribution */
244.148 +};
244.149 +
244.150 +struct arcs
244.151 +{ int from;
244.152 + /* the FROM node of that arc */
244.153 + int to;
244.154 + /* the TO node of that arc */
244.155 + int cost;
244.156 + /* original cost of that arc */
244.157 + int u;
244.158 + /* capacity of the arc */
244.159 +};
244.160 +
244.161 +struct imbalance
244.162 +{ int node;
244.163 + /* Node ID */
244.164 + int supply;
244.165 + /* Supply of that node */
244.166 +};
244.167 +
244.168 +struct csa
244.169 +{ /* common storage area */
244.170 + glp_graph *G;
244.171 + int v_rhs, a_cap, a_cost;
244.172 + int seed;
244.173 + /* random number seed */
244.174 + int seed_original;
244.175 + /* the original seed from input */
244.176 + int two_way;
244.177 + /* 0: generate arcs in both direction for the basic grid, except
244.178 + for the arcs to/from the super node. 1: o/w */
244.179 + int n_node;
244.180 + /* total number of nodes in the network, numbered 1 to n_node,
244.181 + including the super node, which is the last one */
244.182 + int n_arc;
244.183 + /* total number of arcs in the network, counting EVERY arc. */
244.184 + int n_grid_arc;
244.185 + /* number of arcs in the basic grid, including the arcs to/from
244.186 + the super node */
244.187 + int n_source, n_sink;
244.188 + /* number of source and sink nodes */
244.189 + int avg_degree;
244.190 + /* average degree, arcs to and from the super node are counted */
244.191 + int t_supply;
244.192 + /* total supply in the network */
244.193 + int n1, n2;
244.194 + /* the two edges of the network grid. n1 >= n2 */
244.195 + struct imbalance *source_list, *sink_list;
244.196 + /* head of the array of source/sink nodes */
244.197 + struct stat_para arc_costs;
244.198 + /* the distribution of arc costs */
244.199 + struct stat_para capacities;
244.200 + /* distribution of the capacities of the arcs */
244.201 + struct arcs *arc_list;
244.202 + /* head of the arc list array. Arcs in this array are in the
244.203 + order of grid_arcs, arcs to/from super node, and other arcs */
244.204 +};
244.205 +
244.206 +#define G (csa->G)
244.207 +#define v_rhs (csa->v_rhs)
244.208 +#define a_cap (csa->a_cap)
244.209 +#define a_cost (csa->a_cost)
244.210 +#define seed (csa->seed)
244.211 +#define seed_original (csa->seed_original)
244.212 +#define two_way (csa->two_way)
244.213 +#define n_node (csa->n_node)
244.214 +#define n_arc (csa->n_arc)
244.215 +#define n_grid_arc (csa->n_grid_arc)
244.216 +#define n_source (csa->n_source)
244.217 +#define n_sink (csa->n_sink)
244.218 +#define avg_degree (csa->avg_degree)
244.219 +#define t_supply (csa->t_supply)
244.220 +#define n1 (csa->n1)
244.221 +#define n2 (csa->n2)
244.222 +#define source_list (csa->source_list)
244.223 +#define sink_list (csa->sink_list)
244.224 +#define arc_costs (csa->arc_costs)
244.225 +#define capacities (csa->capacities)
244.226 +#define arc_list (csa->arc_list)
244.227 +
244.228 +static void assign_capacities(struct csa *csa);
244.229 +static void assign_costs(struct csa *csa);
244.230 +static void assign_imbalance(struct csa *csa);
244.231 +static int exponential(struct csa *csa, double lambda[1]);
244.232 +static struct arcs *gen_additional_arcs(struct csa *csa, struct arcs
244.233 + *arc_ptr);
244.234 +static struct arcs *gen_basic_grid(struct csa *csa, struct arcs
244.235 + *arc_ptr);
244.236 +static void gen_more_arcs(struct csa *csa, struct arcs *arc_ptr);
244.237 +static void generate(struct csa *csa);
244.238 +static void output(struct csa *csa);
244.239 +static double randy(struct csa *csa);
244.240 +static void select_source_sinks(struct csa *csa);
244.241 +static int uniform(struct csa *csa, double a[2]);
244.242 +
244.243 +int glp_gridgen(glp_graph *G_, int _v_rhs, int _a_cap, int _a_cost,
244.244 + const int parm[1+14])
244.245 +{ struct csa _csa, *csa = &_csa;
244.246 + int n, ret;
244.247 + G = G_;
244.248 + v_rhs = _v_rhs;
244.249 + a_cap = _a_cap;
244.250 + a_cost = _a_cost;
244.251 + if (G != NULL)
244.252 + { if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
244.253 + xerror("glp_gridgen: v_rhs = %d; invalid offset\n", v_rhs);
244.254 + if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
244.255 + xerror("glp_gridgen: a_cap = %d; invalid offset\n", a_cap);
244.256 + if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
244.257 + xerror("glp_gridgen: a_cost = %d; invalid offset\n", a_cost)
244.258 + ;
244.259 + }
244.260 + /* Check the parameters for consistency. */
244.261 + if (!(parm[1] == 0 || parm[1] == 1))
244.262 + { ret = 1;
244.263 + goto done;
244.264 + }
244.265 + if (parm[2] < 1)
244.266 + { ret = 2;
244.267 + goto done;
244.268 + }
244.269 + if (!(10 <= parm[3] && parm[3] <= 40000))
244.270 + { ret = 3;
244.271 + goto done;
244.272 + }
244.273 + if (!(1 <= parm[4] && parm[4] <= 40000))
244.274 + { ret = 4;
244.275 + goto done;
244.276 + }
244.277 + if (!(parm[5] >= 0 && parm[6] >= 0 && parm[5] + parm[6] <=
244.278 + parm[3]))
244.279 + { ret = 5;
244.280 + goto done;
244.281 + }
244.282 + if (!(1 <= parm[7] && parm[7] <= parm[3]))
244.283 + { ret = 6;
244.284 + goto done;
244.285 + }
244.286 + if (parm[8] < 0)
244.287 + { ret = 7;
244.288 + goto done;
244.289 + }
244.290 + if (!(parm[9] == 1 || parm[9] == 2))
244.291 + { ret = 8;
244.292 + goto done;
244.293 + }
244.294 + if (parm[9] == 1 && parm[10] > parm[11] ||
244.295 + parm[9] == 2 && parm[10] < 1)
244.296 + { ret = 9;
244.297 + goto done;
244.298 + }
244.299 + if (!(parm[12] == 1 || parm[12] == 2))
244.300 + { ret = 10;
244.301 + goto done;
244.302 + }
244.303 + if (parm[12] == 1 && !(0 <= parm[13] && parm[13] <= parm[14]) ||
244.304 + parm[12] == 2 && parm[13] < 1)
244.305 + { ret = 11;
244.306 + goto done;
244.307 + }
244.308 + /* Initialize the graph object. */
244.309 + if (G != NULL)
244.310 + { glp_erase_graph(G, G->v_size, G->a_size);
244.311 + glp_set_graph_name(G, "GRIDGEN");
244.312 + }
244.313 + /* Copy the generator parameters. */
244.314 + two_way = parm[1];
244.315 + seed_original = seed = parm[2];
244.316 + n_node = parm[3];
244.317 + n = parm[4];
244.318 + n_source = parm[5];
244.319 + n_sink = parm[6];
244.320 + avg_degree = parm[7];
244.321 + t_supply = parm[8];
244.322 + arc_costs.distribution = parm[9];
244.323 + if (parm[9] == 1)
244.324 + { arc_costs.parameter[0] = parm[10];
244.325 + arc_costs.parameter[1] = parm[11];
244.326 + }
244.327 + else
244.328 + { arc_costs.parameter[0] = (double)parm[10] / 100.0;
244.329 + arc_costs.parameter[1] = 0.0;
244.330 + }
244.331 + capacities.distribution = parm[12];
244.332 + if (parm[12] == 1)
244.333 + { capacities.parameter[0] = parm[13];
244.334 + capacities.parameter[1] = parm[14];
244.335 + }
244.336 + else
244.337 + { capacities.parameter[0] = (double)parm[13] / 100.0;
244.338 + capacities.parameter[1] = 0.0;
244.339 + }
244.340 + /* Calculate the edge lengths of the grid according to the
244.341 + input. */
244.342 + if (n * n >= n_node)
244.343 + { n1 = n;
244.344 + n2 = (int)((double)n_node / (double)n + 0.5);
244.345 + }
244.346 + else
244.347 + { n2 = n;
244.348 + n1 = (int)((double)n_node / (double)n + 0.5);
244.349 + }
244.350 + /* Recalculate the total number of nodes and plus 1 for the super
244.351 + node. */
244.352 + n_node = n1 * n2 + 1;
244.353 + n_arc = n_node * avg_degree;
244.354 + n_grid_arc = (two_way + 1) * ((n1 - 1) * n2 + (n2 - 1) * n1) +
244.355 + n_source + n_sink;
244.356 + if (n_grid_arc > n_arc) n_arc = n_grid_arc;
244.357 + arc_list = xcalloc(n_arc, sizeof(struct arcs));
244.358 + source_list = xcalloc(n_source, sizeof(struct imbalance));
244.359 + sink_list = xcalloc(n_sink, sizeof(struct imbalance));
244.360 + /* Generate a random network. */
244.361 + generate(csa);
244.362 + /* Output the network. */
244.363 + output(csa);
244.364 + /* Free all allocated memory. */
244.365 + xfree(arc_list);
244.366 + xfree(source_list);
244.367 + xfree(sink_list);
244.368 + /* The instance has been successfully generated. */
244.369 + ret = 0;
244.370 +done: return ret;
244.371 +}
244.372 +
244.373 +#undef random
244.374 +
244.375 +static void assign_capacities(struct csa *csa)
244.376 +{ /* Assign a capacity to each arc. */
244.377 + struct arcs *arc_ptr = arc_list;
244.378 + int (*random)(struct csa *csa, double *);
244.379 + int i;
244.380 + /* Determine the random number generator to use. */
244.381 + switch (arc_costs.distribution)
244.382 + { case UNIFORM:
244.383 + random = uniform;
244.384 + break;
244.385 + case EXPONENTIAL:
244.386 + random = exponential;
244.387 + break;
244.388 + default:
244.389 + xassert(csa != csa);
244.390 + }
244.391 + /* Assign capacities to grid arcs. */
244.392 + for (i = n_source + n_sink; i < n_grid_arc; i++, arc_ptr++)
244.393 + arc_ptr->u = random(csa, capacities.parameter);
244.394 + i = i - n_source - n_sink;
244.395 + /* Assign capacities to arcs to/from supernode. */
244.396 + for (; i < n_grid_arc; i++, arc_ptr++)
244.397 + arc_ptr->u = t_supply;
244.398 + /* Assign capacities to all other arcs. */
244.399 + for (; i < n_arc; i++, arc_ptr++)
244.400 + arc_ptr->u = random(csa, capacities.parameter);
244.401 + return;
244.402 +}
244.403 +
244.404 +static void assign_costs(struct csa *csa)
244.405 +{ /* Assign a cost to each arc. */
244.406 + struct arcs *arc_ptr = arc_list;
244.407 + int (*random)(struct csa *csa, double *);
244.408 + int i;
244.409 + /* A high cost assigned to arcs to/from the supernode. */
244.410 + int high_cost;
244.411 + /* The maximum cost assigned to arcs in the base grid. */
244.412 + int max_cost = 0;
244.413 + /* Determine the random number generator to use. */
244.414 + switch (arc_costs.distribution)
244.415 + { case UNIFORM:
244.416 + random = uniform;
244.417 + break;
244.418 + case EXPONENTIAL:
244.419 + random = exponential;
244.420 + break;
244.421 + default:
244.422 + xassert(csa != csa);
244.423 + }
244.424 + /* Assign costs to arcs in the base grid. */
244.425 + for (i = n_source + n_sink; i < n_grid_arc; i++, arc_ptr++)
244.426 + { arc_ptr->cost = random(csa, arc_costs.parameter);
244.427 + if (max_cost < arc_ptr->cost) max_cost = arc_ptr->cost;
244.428 + }
244.429 + i = i - n_source - n_sink;
244.430 + /* Assign costs to arcs to/from the super node. */
244.431 + high_cost = max_cost * 2;
244.432 + for (; i < n_grid_arc; i++, arc_ptr++)
244.433 + arc_ptr->cost = high_cost;
244.434 + /* Assign costs to all other arcs. */
244.435 + for (; i < n_arc; i++, arc_ptr++)
244.436 + arc_ptr->cost = random(csa, arc_costs.parameter);
244.437 + return;
244.438 +}
244.439 +
244.440 +static void assign_imbalance(struct csa *csa)
244.441 +{ /* Assign an imbalance to each node. */
244.442 + int total, i;
244.443 + double avg;
244.444 + struct imbalance *ptr;
244.445 + /* assign the supply nodes */
244.446 + avg = 2.0 * t_supply / n_source;
244.447 + do
244.448 + { for (i = 1, total = t_supply, ptr = source_list + 1;
244.449 + i < n_source; i++, ptr++)
244.450 + { ptr->supply = (int)(randy(csa) * avg + 0.5);
244.451 + total -= ptr->supply;
244.452 + }
244.453 + source_list->supply = total;
244.454 + }
244.455 + /* redo all if the assignment "overshooted" */
244.456 + while (total <= 0);
244.457 + /* assign the demand nodes */
244.458 + avg = -2.0 * t_supply / n_sink;
244.459 + do
244.460 + { for (i = 1, total = t_supply, ptr = sink_list + 1;
244.461 + i < n_sink; i++, ptr++)
244.462 + { ptr->supply = (int)(randy(csa) * avg - 0.5);
244.463 + total += ptr->supply;
244.464 + }
244.465 + sink_list->supply = - total;
244.466 + }
244.467 + while (total <= 0);
244.468 + return;
244.469 +}
244.470 +
244.471 +static int exponential(struct csa *csa, double lambda[1])
244.472 +{ /* Returns an "exponentially distributed" integer with parameter
244.473 + lambda. */
244.474 + return ((int)(- lambda[0] * log((double)randy(csa)) + 0.5));
244.475 +}
244.476 +
244.477 +static struct arcs *gen_additional_arcs(struct csa *csa, struct arcs
244.478 + *arc_ptr)
244.479 +{ /* Generate an arc from each source to the supernode and from
244.480 + supernode to each sink. */
244.481 + int i;
244.482 + for (i = 0; i < n_source; i++, arc_ptr++)
244.483 + { arc_ptr->from = source_list[i].node;
244.484 + arc_ptr->to = n_node;
244.485 + }
244.486 + for (i = 0; i < n_sink; i++, arc_ptr++)
244.487 + { arc_ptr->to = sink_list[i].node;
244.488 + arc_ptr->from = n_node;
244.489 + }
244.490 + return arc_ptr;
244.491 +}
244.492 +
244.493 +static struct arcs *gen_basic_grid(struct csa *csa, struct arcs
244.494 + *arc_ptr)
244.495 +{ /* Generate the basic grid. */
244.496 + int direction = 1, i, j, k;
244.497 + if (two_way)
244.498 + { /* Generate an arc in each direction. */
244.499 + for (i = 1; i < n_node; i += n1)
244.500 + { for (j = i, k = j + n1 - 1; j < k; j++)
244.501 + { arc_ptr->from = j;
244.502 + arc_ptr->to = j + 1;
244.503 + arc_ptr++;
244.504 + arc_ptr->from = j + 1;
244.505 + arc_ptr->to = j;
244.506 + arc_ptr++;
244.507 + }
244.508 + }
244.509 + for (i = 1; i <= n1; i++)
244.510 + { for (j = i + n1; j < n_node; j += n1)
244.511 + { arc_ptr->from = j;
244.512 + arc_ptr->to = j - n1;
244.513 + arc_ptr++;
244.514 + arc_ptr->from = j - n1;
244.515 + arc_ptr->to = j;
244.516 + arc_ptr++;
244.517 + }
244.518 + }
244.519 + }
244.520 + else
244.521 + { /* Generate one arc in each direction. */
244.522 + for (i = 1; i < n_node; i += n1)
244.523 + { if (direction == 1)
244.524 + j = i;
244.525 + else
244.526 + j = i + 1;
244.527 + for (k = j + n1 - 1; j < k; j++)
244.528 + { arc_ptr->from = j;
244.529 + arc_ptr->to = j + direction;
244.530 + arc_ptr++;
244.531 + }
244.532 + direction = - direction;
244.533 + }
244.534 + for (i = 1; i <= n1; i++)
244.535 + { j = i + n1;
244.536 + if (direction == 1)
244.537 + { for (; j < n_node; j += n1)
244.538 + { arc_ptr->from = j - n1;
244.539 + arc_ptr->to = j;
244.540 + arc_ptr++;
244.541 + }
244.542 + }
244.543 + else
244.544 + { for (; j < n_node; j += n1)
244.545 + { arc_ptr->from = j - n1;
244.546 + arc_ptr->to = j;
244.547 + arc_ptr++;
244.548 + }
244.549 + }
244.550 + direction = - direction;
244.551 + }
244.552 + }
244.553 + return arc_ptr;
244.554 +}
244.555 +
244.556 +static void gen_more_arcs(struct csa *csa, struct arcs *arc_ptr)
244.557 +{ /* Generate random arcs to meet the specified density. */
244.558 + int i;
244.559 + double ab[2];
244.560 + ab[0] = 0.9;
244.561 + ab[1] = n_node - 0.99; /* upper limit is n_node-1 because the
244.562 + supernode cannot be selected */
244.563 + for (i = n_grid_arc; i < n_arc; i++, arc_ptr++)
244.564 + { arc_ptr->from = uniform(csa, ab);
244.565 + arc_ptr->to = uniform(csa, ab);
244.566 + if (arc_ptr->from == arc_ptr->to)
244.567 + { arc_ptr--;
244.568 + i--;
244.569 + }
244.570 + }
244.571 + return;
244.572 +}
244.573 +
244.574 +static void generate(struct csa *csa)
244.575 +{ /* Generate a random network. */
244.576 + struct arcs *arc_ptr = arc_list;
244.577 + arc_ptr = gen_basic_grid(csa, arc_ptr);
244.578 + select_source_sinks(csa);
244.579 + arc_ptr = gen_additional_arcs(csa, arc_ptr);
244.580 + gen_more_arcs(csa, arc_ptr);
244.581 + assign_costs(csa);
244.582 + assign_capacities(csa);
244.583 + assign_imbalance(csa);
244.584 + return;
244.585 +}
244.586 +
244.587 +static void output(struct csa *csa)
244.588 +{ /* Output the network in DIMACS format. */
244.589 + struct arcs *arc_ptr;
244.590 + struct imbalance *imb_ptr;
244.591 + int i;
244.592 + if (G != NULL) goto skip;
244.593 + /* Output "c", "p" records. */
244.594 + xprintf("c generated by GRIDGEN\n");
244.595 + xprintf("c seed %d\n", seed_original);
244.596 + xprintf("c nodes %d\n", n_node);
244.597 + xprintf("c grid size %d X %d\n", n1, n2);
244.598 + xprintf("c sources %d sinks %d\n", n_source, n_sink);
244.599 + xprintf("c avg. degree %d\n", avg_degree);
244.600 + xprintf("c supply %d\n", t_supply);
244.601 + switch (arc_costs.distribution)
244.602 + { case UNIFORM:
244.603 + xprintf("c arc costs: UNIFORM distr. min %d max %d\n",
244.604 + (int)arc_costs.parameter[0],
244.605 + (int)arc_costs.parameter[1]);
244.606 + break;
244.607 + case EXPONENTIAL:
244.608 + xprintf("c arc costs: EXPONENTIAL distr. lambda %d\n",
244.609 + (int)arc_costs.parameter[0]);
244.610 + break;
244.611 + default:
244.612 + xassert(csa != csa);
244.613 + }
244.614 + switch (capacities.distribution)
244.615 + { case UNIFORM:
244.616 + xprintf("c arc caps : UNIFORM distr. min %d max %d\n",
244.617 + (int)capacities.parameter[0],
244.618 + (int)capacities.parameter[1]);
244.619 + break;
244.620 + case EXPONENTIAL:
244.621 + xprintf("c arc caps : EXPONENTIAL distr. %d lambda %d\n",
244.622 + (int)capacities.parameter[0]);
244.623 + break;
244.624 + default:
244.625 + xassert(csa != csa);
244.626 + }
244.627 +skip: if (G == NULL)
244.628 + xprintf("p min %d %d\n", n_node, n_arc);
244.629 + else
244.630 + { glp_add_vertices(G, n_node);
244.631 + if (v_rhs >= 0)
244.632 + { double zero = 0.0;
244.633 + for (i = 1; i <= n_node; i++)
244.634 + { glp_vertex *v = G->v[i];
244.635 + memcpy((char *)v->data + v_rhs, &zero, sizeof(double));
244.636 + }
244.637 + }
244.638 + }
244.639 + /* Output "n node supply". */
244.640 + for (i = 0, imb_ptr = source_list; i < n_source; i++, imb_ptr++)
244.641 + { if (G == NULL)
244.642 + xprintf("n %d %d\n", imb_ptr->node, imb_ptr->supply);
244.643 + else
244.644 + { if (v_rhs >= 0)
244.645 + { double temp = (double)imb_ptr->supply;
244.646 + glp_vertex *v = G->v[imb_ptr->node];
244.647 + memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
244.648 + }
244.649 + }
244.650 + }
244.651 + for (i = 0, imb_ptr = sink_list; i < n_sink; i++, imb_ptr++)
244.652 + { if (G == NULL)
244.653 + xprintf("n %d %d\n", imb_ptr->node, imb_ptr->supply);
244.654 + else
244.655 + { if (v_rhs >= 0)
244.656 + { double temp = (double)imb_ptr->supply;
244.657 + glp_vertex *v = G->v[imb_ptr->node];
244.658 + memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
244.659 + }
244.660 + }
244.661 + }
244.662 + /* Output "a from to lowcap=0 hicap cost". */
244.663 + for (i = 0, arc_ptr = arc_list; i < n_arc; i++, arc_ptr++)
244.664 + { if (G == NULL)
244.665 + xprintf("a %d %d 0 %d %d\n", arc_ptr->from, arc_ptr->to,
244.666 + arc_ptr->u, arc_ptr->cost);
244.667 + else
244.668 + { glp_arc *a = glp_add_arc(G, arc_ptr->from, arc_ptr->to);
244.669 + if (a_cap >= 0)
244.670 + { double temp = (double)arc_ptr->u;
244.671 + memcpy((char *)a->data + a_cap, &temp, sizeof(double));
244.672 + }
244.673 + if (a_cost >= 0)
244.674 + { double temp = (double)arc_ptr->cost;
244.675 + memcpy((char *)a->data + a_cost, &temp, sizeof(double));
244.676 + }
244.677 + }
244.678 + }
244.679 + return;
244.680 +}
244.681 +
244.682 +static double randy(struct csa *csa)
244.683 +{ /* Returns a random number between 0.0 and 1.0.
244.684 + See Ward Cheney & David Kincaid, "Numerical Mathematics and
244.685 + Computing," 2Ed, pp. 335. */
244.686 + seed = 16807 * seed % 2147483647;
244.687 + if (seed < 0) seed = - seed;
244.688 + return seed * 4.6566128752459e-10;
244.689 +}
244.690 +
244.691 +static void select_source_sinks(struct csa *csa)
244.692 +{ /* Randomly select the source nodes and sink nodes. */
244.693 + int i, *int_ptr;
244.694 + int *temp_list; /* a temporary list of nodes */
244.695 + struct imbalance *ptr;
244.696 + double ab[2]; /* parameter for random number generator */
244.697 + ab[0] = 0.9;
244.698 + ab[1] = n_node - 0.99; /* upper limit is n_node-1 because the
244.699 + supernode cannot be selected */
244.700 + temp_list = xcalloc(n_node, sizeof(int));
244.701 + for (i = 0, int_ptr = temp_list; i < n_node; i++, int_ptr++)
244.702 + *int_ptr = 0;
244.703 + /* Select the source nodes. */
244.704 + for (i = 0, ptr = source_list; i < n_source; i++, ptr++)
244.705 + { ptr->node = uniform(csa, ab);
244.706 + if (temp_list[ptr->node] == 1) /* check for duplicates */
244.707 + { ptr--;
244.708 + i--;
244.709 + }
244.710 + else
244.711 + temp_list[ptr->node] = 1;
244.712 + }
244.713 + /* Select the sink nodes. */
244.714 + for (i = 0, ptr = sink_list; i < n_sink; i++, ptr++)
244.715 + { ptr->node = uniform(csa, ab);
244.716 + if (temp_list[ptr->node] == 1)
244.717 + { ptr--;
244.718 + i--;
244.719 + }
244.720 + else
244.721 + temp_list[ptr->node] = 1;
244.722 + }
244.723 + xfree(temp_list);
244.724 + return;
244.725 +}
244.726 +
244.727 +int uniform(struct csa *csa, double a[2])
244.728 +{ /* Generates an integer uniformly selected from [a[0],a[1]]. */
244.729 + return (int)((a[1] - a[0]) * randy(csa) + a[0] + 0.5);
244.730 +}
244.731 +
244.732 +/**********************************************************************/
244.733 +
244.734 +#if 0
244.735 +int main(void)
244.736 +{ int parm[1+14];
244.737 + double temp;
244.738 + scanf("%d", &parm[1]);
244.739 + scanf("%d", &parm[2]);
244.740 + scanf("%d", &parm[3]);
244.741 + scanf("%d", &parm[4]);
244.742 + scanf("%d", &parm[5]);
244.743 + scanf("%d", &parm[6]);
244.744 + scanf("%d", &parm[7]);
244.745 + scanf("%d", &parm[8]);
244.746 + scanf("%d", &parm[9]);
244.747 + if (parm[9] == 1)
244.748 + { scanf("%d", &parm[10]);
244.749 + scanf("%d", &parm[11]);
244.750 + }
244.751 + else
244.752 + { scanf("%le", &temp);
244.753 + parm[10] = (int)(100.0 * temp + .5);
244.754 + parm[11] = 0;
244.755 + }
244.756 + scanf("%d", &parm[12]);
244.757 + if (parm[12] == 1)
244.758 + { scanf("%d", &parm[13]);
244.759 + scanf("%d", &parm[14]);
244.760 + }
244.761 + else
244.762 + { scanf("%le", &temp);
244.763 + parm[13] = (int)(100.0 * temp + .5);
244.764 + parm[14] = 0;
244.765 + }
244.766 + glp_gridgen(NULL, 0, 0, 0, parm);
244.767 + return 0;
244.768 +}
244.769 +#endif
244.770 +
244.771 +/* eof */
245.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
245.2 +++ b/src/glpnet05.c Mon Dec 06 13:09:21 2010 +0100
245.3 @@ -0,0 +1,367 @@
245.4 +/* glpnet05.c (Goldfarb's maximum flow problem generator) */
245.5 +
245.6 +/***********************************************************************
245.7 +* This code is part of GLPK (GNU Linear Programming Kit).
245.8 +*
245.9 +* This code is a modified version of the program RMFGEN, a maxflow
245.10 +* problem generator developed by D.Goldfarb and M.Grigoriadis, and
245.11 +* originally implemented by Tamas Badics <badics@rutcor.rutgers.edu>.
245.12 +* The original code is publically available on the DIMACS ftp site at:
245.13 +* <ftp://dimacs.rutgers.edu/pub/netflow/generators/network/genrmf>.
245.14 +*
245.15 +* All changes concern only the program interface, so this modified
245.16 +* version produces exactly the same instances as the original version.
245.17 +*
245.18 +* Changes were made by Andrew Makhorin <mao@gnu.org>.
245.19 +*
245.20 +* GLPK is free software: you can redistribute it and/or modify it
245.21 +* under the terms of the GNU General Public License as published by
245.22 +* the Free Software Foundation, either version 3 of the License, or
245.23 +* (at your option) any later version.
245.24 +*
245.25 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
245.26 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
245.27 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
245.28 +* License for more details.
245.29 +*
245.30 +* You should have received a copy of the GNU General Public License
245.31 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
245.32 +***********************************************************************/
245.33 +
245.34 +#include "glpapi.h"
245.35 +#include "glprng.h"
245.36 +
245.37 +/***********************************************************************
245.38 +* NAME
245.39 +*
245.40 +* glp_rmfgen - Goldfarb's maximum flow problem generator
245.41 +*
245.42 +* SYNOPSIS
245.43 +*
245.44 +* int glp_rmfgen(glp_graph *G, int *s, int *t, int a_cap,
245.45 +* const int parm[1+5]);
245.46 +*
245.47 +* DESCRIPTION
245.48 +*
245.49 +* The routine glp_rmfgen is a maximum flow problem generator developed
245.50 +* by D.Goldfarb and M.Grigoriadis.
245.51 +*
245.52 +* The parameter G specifies the graph object, to which the generated
245.53 +* problem data have to be stored. Note that on entry the graph object
245.54 +* is erased with the routine glp_erase_graph.
245.55 +*
245.56 +* The pointer s specifies a location, to which the routine stores the
245.57 +* source node number. If s is NULL, the node number is not stored.
245.58 +*
245.59 +* The pointer t specifies a location, to which the routine stores the
245.60 +* sink node number. If t is NULL, the node number is not stored.
245.61 +*
245.62 +* The parameter a_cap specifies an offset of the field of type double
245.63 +* in the arc data block, to which the routine stores the arc capacity.
245.64 +* If a_cap < 0, the capacity is not stored.
245.65 +*
245.66 +* The array parm contains description of the network to be generated:
245.67 +*
245.68 +* parm[0] not used
245.69 +* parm[1] (seed) random number seed (a positive integer)
245.70 +* parm[2] (a) frame size
245.71 +* parm[3] (b) depth
245.72 +* parm[4] (c1) minimal arc capacity
245.73 +* parm[5] (c2) maximal arc capacity
245.74 +*
245.75 +* RETURNS
245.76 +*
245.77 +* If the instance was successfully generated, the routine glp_netgen
245.78 +* returns zero; otherwise, if specified parameters are inconsistent,
245.79 +* the routine returns a non-zero error code.
245.80 +*
245.81 +* COMMENTS
245.82 +*
245.83 +* The generated network is as follows. It has b pieces of frames of
245.84 +* size a * a. (So alltogether the number of vertices is a * a * b)
245.85 +*
245.86 +* In each frame all the vertices are connected with their neighbours
245.87 +* (forth and back). In addition the vertices of a frame are connected
245.88 +* one to one with the vertices of next frame using a random permutation
245.89 +* of those vertices.
245.90 +*
245.91 +* The source is the lower left vertex of the first frame, the sink is
245.92 +* the upper right vertex of the b'th frame.
245.93 +*
245.94 +* t
245.95 +* +-------+
245.96 +* | .|
245.97 +* | . |
245.98 +* / | / |
245.99 +* +-------+/ -+ b
245.100 +* | | |/.
245.101 +* a | -v- |/
245.102 +* | | |/
245.103 +* +-------+ 1
245.104 +* s a
245.105 +*
245.106 +* The capacities are randomly chosen integers from the range of [c1,c2]
245.107 +* in the case of interconnecting edges, and c2 * a * a for the in-frame
245.108 +* edges.
245.109 +*
245.110 +* REFERENCES
245.111 +*
245.112 +* D.Goldfarb and M.D.Grigoriadis, "A computational comparison of the
245.113 +* Dinic and network simplex methods for maximum flow." Annals of Op.
245.114 +* Res. 13 (1988), pp. 83-123.
245.115 +*
245.116 +* U.Derigs and W.Meier, "Implementing Goldberg's max-flow algorithm:
245.117 +* A computational investigation." Zeitschrift fuer Operations Research
245.118 +* 33 (1989), pp. 383-403. */
245.119 +
245.120 +typedef struct VERTEX
245.121 +{ struct EDGE **edgelist;
245.122 + /* Pointer to the list of pointers to the adjacent edges.
245.123 + (No matter that to or from edges) */
245.124 + struct EDGE **current;
245.125 + /* Pointer to the current edge */
245.126 + int degree;
245.127 + /* Number of adjacent edges (both direction) */
245.128 + int index;
245.129 +} vertex;
245.130 +
245.131 +typedef struct EDGE
245.132 +{ int from;
245.133 + int to;
245.134 + int cap;
245.135 + /* Capacity */
245.136 +} edge;
245.137 +
245.138 +typedef struct NETWORK
245.139 +{ struct NETWORK *next, *prev;
245.140 + int vertnum;
245.141 + int edgenum;
245.142 + vertex *verts;
245.143 + /* Vertex array[1..vertnum] */
245.144 + edge *edges;
245.145 + /* Edge array[1..edgenum] */
245.146 + int source;
245.147 + /* Pointer to the source */
245.148 + int sink;
245.149 + /* Pointer to the sink */
245.150 +} network;
245.151 +
245.152 +struct csa
245.153 +{ /* common storage area */
245.154 + glp_graph *G;
245.155 + int *s, *t, a_cap;
245.156 + RNG *rand;
245.157 + network *N;
245.158 + int *Parr;
245.159 + int A, AA, C2AA, Ec;
245.160 +};
245.161 +
245.162 +#define G (csa->G)
245.163 +#define s (csa->s)
245.164 +#define t (csa->t)
245.165 +#define a_cap (csa->a_cap)
245.166 +#define N (csa->N)
245.167 +#define Parr (csa->Parr)
245.168 +#define A (csa->A)
245.169 +#define AA (csa->AA)
245.170 +#define C2AA (csa->C2AA)
245.171 +#define Ec (csa->Ec)
245.172 +
245.173 +#undef random
245.174 +#define random(A) (int)(rng_unif_01(csa->rand) * (double)(A))
245.175 +#define RANDOM(A, B) (int)(random((B) - (A) + 1) + (A))
245.176 +#define sgn(A) (((A) > 0) ? 1 : ((A) == 0) ? 0 : -1)
245.177 +
245.178 +static void make_edge(struct csa *csa, int from, int to, int c1, int c2)
245.179 +{ Ec++;
245.180 + N->edges[Ec].from = from;
245.181 + N->edges[Ec].to = to;
245.182 + N->edges[Ec].cap = RANDOM(c1, c2);
245.183 + return;
245.184 +}
245.185 +
245.186 +static void permute(struct csa *csa)
245.187 +{ int i, j, tmp;
245.188 + for (i = 1; i < AA; i++)
245.189 + { j = RANDOM(i, AA);
245.190 + tmp = Parr[i];
245.191 + Parr[i] = Parr[j];
245.192 + Parr[j] = tmp;
245.193 + }
245.194 + return;
245.195 +}
245.196 +
245.197 +static void connect(struct csa *csa, int offset, int cv, int x1, int y1)
245.198 +{ int cv1;
245.199 + cv1 = offset + (x1 - 1) * A + y1;
245.200 + Ec++;
245.201 + N->edges[Ec].from = cv;
245.202 + N->edges[Ec].to = cv1;
245.203 + N->edges[Ec].cap = C2AA;
245.204 + return;
245.205 +}
245.206 +
245.207 +static network *gen_rmf(struct csa *csa, int a, int b, int c1, int c2)
245.208 +{ /* generates a network with a*a*b nodes and 6a*a*b-4ab-2a*a edges
245.209 + random_frame network:
245.210 + Derigs & Meier, Methods & Models of OR (1989), 33:383-403 */
245.211 + int x, y, z, offset, cv;
245.212 + A = a;
245.213 + AA = a * a;
245.214 + C2AA = c2 * AA;
245.215 + Ec = 0;
245.216 + N = (network *)xmalloc(sizeof(network));
245.217 + N->vertnum = AA * b;
245.218 + N->edgenum = 5 * AA * b - 4 * A * b - AA;
245.219 + N->edges = (edge *)xcalloc(N->edgenum + 1, sizeof(edge));
245.220 + N->source = 1;
245.221 + N->sink = N->vertnum;
245.222 + Parr = (int *)xcalloc(AA + 1, sizeof(int));
245.223 + for (x = 1; x <= AA; x++)
245.224 + Parr[x] = x;
245.225 + for (z = 1; z <= b; z++)
245.226 + { offset = AA * (z - 1);
245.227 + if (z != b)
245.228 + permute(csa);
245.229 + for (x = 1; x <= A; x++)
245.230 + { for (y = 1; y <= A; y++)
245.231 + { cv = offset + (x - 1) * A + y;
245.232 + if (z != b)
245.233 + make_edge(csa, cv, offset + AA + Parr[cv - offset],
245.234 + c1, c2); /* the intermediate edges */
245.235 + if (y < A)
245.236 + connect(csa, offset, cv, x, y + 1);
245.237 + if (y > 1)
245.238 + connect(csa, offset, cv, x, y - 1);
245.239 + if (x < A)
245.240 + connect(csa, offset, cv, x + 1, y);
245.241 + if (x > 1)
245.242 + connect(csa, offset, cv, x - 1, y);
245.243 + }
245.244 + }
245.245 + }
245.246 + xfree(Parr);
245.247 + return N;
245.248 +}
245.249 +
245.250 +static void print_max_format(struct csa *csa, network *n, char *comm[],
245.251 + int dim)
245.252 +{ /* prints a network heading with dim lines of comments (no \n
245.253 + needs at the ends) */
245.254 + int i, vnum, e_num;
245.255 + edge *e;
245.256 + vnum = n->vertnum;
245.257 + e_num = n->edgenum;
245.258 + if (G == NULL)
245.259 + { for (i = 0; i < dim; i++)
245.260 + xprintf("c %s\n", comm[i]);
245.261 + xprintf("p max %7d %10d\n", vnum, e_num);
245.262 + xprintf("n %7d s\n", n->source);
245.263 + xprintf("n %7d t\n", n->sink);
245.264 + }
245.265 + else
245.266 + { glp_add_vertices(G, vnum);
245.267 + if (s != NULL) *s = n->source;
245.268 + if (t != NULL) *t = n->sink;
245.269 + }
245.270 + for (i = 1; i <= e_num; i++)
245.271 + { e = &n->edges[i];
245.272 + if (G == NULL)
245.273 + xprintf("a %7d %7d %10d\n", e->from, e->to, (int)e->cap);
245.274 + else
245.275 + { glp_arc *a = glp_add_arc(G, e->from, e->to);
245.276 + if (a_cap >= 0)
245.277 + { double temp = (double)e->cap;
245.278 + memcpy((char *)a->data + a_cap, &temp, sizeof(double));
245.279 + }
245.280 + }
245.281 + }
245.282 + return;
245.283 +}
245.284 +
245.285 +static void gen_free_net(network *n)
245.286 +{ xfree(n->edges);
245.287 + xfree(n);
245.288 + return;
245.289 +}
245.290 +
245.291 +int glp_rmfgen(glp_graph *G_, int *_s, int *_t, int _a_cap,
245.292 + const int parm[1+5])
245.293 +{ struct csa _csa, *csa = &_csa;
245.294 + network *n;
245.295 + char comm[10][80], *com1[10];
245.296 + int seed, a, b, c1, c2, ret;
245.297 + G = G_;
245.298 + s = _s;
245.299 + t = _t;
245.300 + a_cap = _a_cap;
245.301 + if (G != NULL)
245.302 + { if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
245.303 + xerror("glp_rmfgen: a_cap = %d; invalid offset\n", a_cap);
245.304 + }
245.305 + seed = parm[1];
245.306 + a = parm[2];
245.307 + b = parm[3];
245.308 + c1 = parm[4];
245.309 + c2 = parm[5];
245.310 + if (!(seed > 0 && 1 <= a && a <= 1000 && 1 <= b && b <= 1000 &&
245.311 + 0 <= c1 && c1 <= c2 && c2 <= 1000))
245.312 + { ret = 1;
245.313 + goto done;
245.314 + }
245.315 + if (G != NULL)
245.316 + { glp_erase_graph(G, G->v_size, G->a_size);
245.317 + glp_set_graph_name(G, "RMFGEN");
245.318 + }
245.319 + csa->rand = rng_create_rand();
245.320 + rng_init_rand(csa->rand, seed);
245.321 + n = gen_rmf(csa, a, b, c1, c2);
245.322 + sprintf(comm[0], "This file was generated by genrmf.");
245.323 + sprintf(comm[1], "The parameters are: a: %d b: %d c1: %d c2: %d",
245.324 + a, b, c1, c2);
245.325 + com1[0] = comm[0];
245.326 + com1[1] = comm[1];
245.327 + print_max_format(csa, n, com1, 2);
245.328 + gen_free_net(n);
245.329 + rng_delete_rand(csa->rand);
245.330 + ret = 0;
245.331 +done: return ret;
245.332 +}
245.333 +
245.334 +/**********************************************************************/
245.335 +
245.336 +#if 0
245.337 +int main(int argc, char *argv[])
245.338 +{ int seed, a, b, c1, c2, i, parm[1+5];
245.339 + seed = 123;
245.340 + a = b = c1 = c2 = -1;
245.341 + for (i = 1; i < argc; i++)
245.342 + { if (strcmp(argv[i], "-seed") == 0)
245.343 + seed = atoi(argv[++i]);
245.344 + else if (strcmp(argv[i], "-a") == 0)
245.345 + a = atoi(argv[++i]);
245.346 + else if (strcmp(argv[i], "-b") == 0)
245.347 + b = atoi(argv[++i]);
245.348 + else if (strcmp(argv[i], "-c1") == 0)
245.349 + c1 = atoi(argv[++i]);
245.350 + else if (strcmp(argv[i], "-c2") == 0)
245.351 + c2 = atoi(argv[++i]);
245.352 + }
245.353 + if (a < 0 || b < 0 || c1 < 0 || c2 < 0)
245.354 + { xprintf("Usage:\n");
245.355 + xprintf("genrmf [-seed seed] -a frame_size -b depth\n");
245.356 + xprintf(" -c1 cap_range1 -c2 cap_range2\n");
245.357 + }
245.358 + else
245.359 + { parm[1] = seed;
245.360 + parm[2] = a;
245.361 + parm[3] = b;
245.362 + parm[4] = c1;
245.363 + parm[5] = c2;
245.364 + glp_rmfgen(NULL, NULL, NULL, 0, parm);
245.365 + }
245.366 + return 0;
245.367 +}
245.368 +#endif
245.369 +
245.370 +/* eof */
246.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
246.2 +++ b/src/glpnet06.c Mon Dec 06 13:09:21 2010 +0100
246.3 @@ -0,0 +1,383 @@
246.4 +/* glpnet06.c (out-of-kilter algorithm) */
246.5 +
246.6 +/***********************************************************************
246.7 +* This code is part of GLPK (GNU Linear Programming Kit).
246.8 +*
246.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
246.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
246.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
246.12 +* E-mail: <mao@gnu.org>.
246.13 +*
246.14 +* GLPK is free software: you can redistribute it and/or modify it
246.15 +* under the terms of the GNU General Public License as published by
246.16 +* the Free Software Foundation, either version 3 of the License, or
246.17 +* (at your option) any later version.
246.18 +*
246.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
246.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
246.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
246.22 +* License for more details.
246.23 +*
246.24 +* You should have received a copy of the GNU General Public License
246.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
246.26 +***********************************************************************/
246.27 +
246.28 +#include "glpenv.h"
246.29 +#include "glpnet.h"
246.30 +
246.31 +/***********************************************************************
246.32 +* NAME
246.33 +*
246.34 +* okalg - out-of-kilter algorithm
246.35 +*
246.36 +* SYNOPSIS
246.37 +*
246.38 +* #include "glpnet.h"
246.39 +* int okalg(int nv, int na, const int tail[], const int head[],
246.40 +* const int low[], const int cap[], const int cost[], int x[],
246.41 +* int pi[]);
246.42 +*
246.43 +* DESCRIPTION
246.44 +*
246.45 +* The routine okalg implements the out-of-kilter algorithm to find a
246.46 +* minimal-cost circulation in the specified flow network.
246.47 +*
246.48 +* INPUT PARAMETERS
246.49 +*
246.50 +* nv is the number of nodes, nv >= 0.
246.51 +*
246.52 +* na is the number of arcs, na >= 0.
246.53 +*
246.54 +* tail[a], a = 1,...,na, is the index of tail node of arc a.
246.55 +*
246.56 +* head[a], a = 1,...,na, is the index of head node of arc a.
246.57 +*
246.58 +* low[a], a = 1,...,na, is an lower bound to the flow through arc a.
246.59 +*
246.60 +* cap[a], a = 1,...,na, is an upper bound to the flow through arc a,
246.61 +* which is the capacity of the arc.
246.62 +*
246.63 +* cost[a], a = 1,...,na, is a per-unit cost of the flow through arc a.
246.64 +*
246.65 +* NOTES
246.66 +*
246.67 +* 1. Multiple arcs are allowed, but self-loops are not allowed.
246.68 +*
246.69 +* 2. It is required that 0 <= low[a] <= cap[a] for all arcs.
246.70 +*
246.71 +* 3. Arc costs may have any sign.
246.72 +*
246.73 +* OUTPUT PARAMETERS
246.74 +*
246.75 +* x[a], a = 1,...,na, is optimal value of the flow through arc a.
246.76 +*
246.77 +* pi[i], i = 1,...,nv, is Lagrange multiplier for flow conservation
246.78 +* equality constraint corresponding to node i (the node potential).
246.79 +*
246.80 +* RETURNS
246.81 +*
246.82 +* 0 optimal circulation found;
246.83 +*
246.84 +* 1 there is no feasible circulation;
246.85 +*
246.86 +* 2 integer overflow occured;
246.87 +*
246.88 +* 3 optimality test failed (logic error).
246.89 +*
246.90 +* REFERENCES
246.91 +*
246.92 +* L.R.Ford, Jr., and D.R.Fulkerson, "Flows in Networks," The RAND
246.93 +* Corp., Report R-375-PR (August 1962), Chap. III "Minimal Cost Flow
246.94 +* Problems," pp.113-26. */
246.95 +
246.96 +static int overflow(int u, int v)
246.97 +{ /* check for integer overflow on computing u + v */
246.98 + if (u > 0 && v > 0 && u + v < 0) return 1;
246.99 + if (u < 0 && v < 0 && u + v > 0) return 1;
246.100 + return 0;
246.101 +}
246.102 +
246.103 +int okalg(int nv, int na, const int tail[], const int head[],
246.104 + const int low[], const int cap[], const int cost[], int x[],
246.105 + int pi[])
246.106 +{ int a, aok, delta, i, j, k, lambda, pos1, pos2, s, t, temp, ret,
246.107 + *ptr, *arc, *link, *list;
246.108 + /* sanity checks */
246.109 + xassert(nv >= 0);
246.110 + xassert(na >= 0);
246.111 + for (a = 1; a <= na; a++)
246.112 + { i = tail[a], j = head[a];
246.113 + xassert(1 <= i && i <= nv);
246.114 + xassert(1 <= j && j <= nv);
246.115 + xassert(i != j);
246.116 + xassert(0 <= low[a] && low[a] <= cap[a]);
246.117 + }
246.118 + /* allocate working arrays */
246.119 + ptr = xcalloc(1+nv+1, sizeof(int));
246.120 + arc = xcalloc(1+na+na, sizeof(int));
246.121 + link = xcalloc(1+nv, sizeof(int));
246.122 + list = xcalloc(1+nv, sizeof(int));
246.123 + /* ptr[i] := (degree of node i) */
246.124 + for (i = 1; i <= nv; i++)
246.125 + ptr[i] = 0;
246.126 + for (a = 1; a <= na; a++)
246.127 + { ptr[tail[a]]++;
246.128 + ptr[head[a]]++;
246.129 + }
246.130 + /* initialize arc pointers */
246.131 + ptr[1]++;
246.132 + for (i = 1; i < nv; i++)
246.133 + ptr[i+1] += ptr[i];
246.134 + ptr[nv+1] = ptr[nv];
246.135 + /* build arc lists */
246.136 + for (a = 1; a <= na; a++)
246.137 + { arc[--ptr[tail[a]]] = a;
246.138 + arc[--ptr[head[a]]] = a;
246.139 + }
246.140 + xassert(ptr[1] == 1);
246.141 + xassert(ptr[nv+1] == na+na+1);
246.142 + /* now the indices of arcs incident to node i are stored in
246.143 + locations arc[ptr[i]], arc[ptr[i]+1], ..., arc[ptr[i+1]-1] */
246.144 + /* initialize arc flows and node potentials */
246.145 + for (a = 1; a <= na; a++)
246.146 + x[a] = 0;
246.147 + for (i = 1; i <= nv; i++)
246.148 + pi[i] = 0;
246.149 +loop: /* main loop starts here */
246.150 + /* find out-of-kilter arc */
246.151 + aok = 0;
246.152 + for (a = 1; a <= na; a++)
246.153 + { i = tail[a], j = head[a];
246.154 + if (overflow(cost[a], pi[i] - pi[j]))
246.155 + { ret = 2;
246.156 + goto done;
246.157 + }
246.158 + lambda = cost[a] + (pi[i] - pi[j]);
246.159 + if (x[a] < low[a] || lambda < 0 && x[a] < cap[a])
246.160 + { /* arc a = i->j is out of kilter, and we need to increase
246.161 + the flow through this arc */
246.162 + aok = a, s = j, t = i;
246.163 + break;
246.164 + }
246.165 + if (x[a] > cap[a] || lambda > 0 && x[a] > low[a])
246.166 + { /* arc a = i->j is out of kilter, and we need to decrease
246.167 + the flow through this arc */
246.168 + aok = a, s = i, t = j;
246.169 + break;
246.170 + }
246.171 + }
246.172 + if (aok == 0)
246.173 + { /* all arcs are in kilter */
246.174 + /* check for feasibility */
246.175 + for (a = 1; a <= na; a++)
246.176 + { if (!(low[a] <= x[a] && x[a] <= cap[a]))
246.177 + { ret = 3;
246.178 + goto done;
246.179 + }
246.180 + }
246.181 + for (i = 1; i <= nv; i++)
246.182 + { temp = 0;
246.183 + for (k = ptr[i]; k < ptr[i+1]; k++)
246.184 + { a = arc[k];
246.185 + if (tail[a] == i)
246.186 + { /* a is outgoing arc */
246.187 + temp += x[a];
246.188 + }
246.189 + else if (head[a] == i)
246.190 + { /* a is incoming arc */
246.191 + temp -= x[a];
246.192 + }
246.193 + else
246.194 + xassert(a != a);
246.195 + }
246.196 + if (temp != 0)
246.197 + { ret = 3;
246.198 + goto done;
246.199 + }
246.200 + }
246.201 + /* check for optimality */
246.202 + for (a = 1; a <= na; a++)
246.203 + { i = tail[a], j = head[a];
246.204 + lambda = cost[a] + (pi[i] - pi[j]);
246.205 + if (lambda > 0 && x[a] != low[a] ||
246.206 + lambda < 0 && x[a] != cap[a])
246.207 + { ret = 3;
246.208 + goto done;
246.209 + }
246.210 + }
246.211 + /* current circulation is optimal */
246.212 + ret = 0;
246.213 + goto done;
246.214 + }
246.215 + /* now we need to find a cycle (t, a, s, ..., t), which allows
246.216 + increasing the flow along it, where a is the out-of-kilter arc
246.217 + just found */
246.218 + /* link[i] = 0 means that node i is not labelled yet;
246.219 + link[i] = a means that arc a immediately precedes node i */
246.220 + /* initially only node s is labelled */
246.221 + for (i = 1; i <= nv; i++)
246.222 + link[i] = 0;
246.223 + link[s] = aok, list[1] = s, pos1 = pos2 = 1;
246.224 + /* breadth first search */
246.225 + while (pos1 <= pos2)
246.226 + { /* dequeue node i */
246.227 + i = list[pos1++];
246.228 + /* consider all arcs incident to node i */
246.229 + for (k = ptr[i]; k < ptr[i+1]; k++)
246.230 + { a = arc[k];
246.231 + if (tail[a] == i)
246.232 + { /* a = i->j is a forward arc from s to t */
246.233 + j = head[a];
246.234 + /* if node j has been labelled, skip the arc */
246.235 + if (link[j] != 0) continue;
246.236 + /* if the arc does not allow increasing the flow through
246.237 + it, skip the arc */
246.238 + if (x[a] >= cap[a]) continue;
246.239 + if (overflow(cost[a], pi[i] - pi[j]))
246.240 + { ret = 2;
246.241 + goto done;
246.242 + }
246.243 + lambda = cost[a] + (pi[i] - pi[j]);
246.244 + if (lambda > 0 && x[a] >= low[a]) continue;
246.245 + }
246.246 + else if (head[a] == i)
246.247 + { /* a = i<-j is a backward arc from s to t */
246.248 + j = tail[a];
246.249 + /* if node j has been labelled, skip the arc */
246.250 + if (link[j] != 0) continue;
246.251 + /* if the arc does not allow decreasing the flow through
246.252 + it, skip the arc */
246.253 + if (x[a] <= low[a]) continue;
246.254 + if (overflow(cost[a], pi[j] - pi[i]))
246.255 + { ret = 2;
246.256 + goto done;
246.257 + }
246.258 + lambda = cost[a] + (pi[j] - pi[i]);
246.259 + if (lambda < 0 && x[a] <= cap[a]) continue;
246.260 + }
246.261 + else
246.262 + xassert(a != a);
246.263 + /* label node j and enqueue it */
246.264 + link[j] = a, list[++pos2] = j;
246.265 + /* check for breakthrough */
246.266 + if (j == t) goto brkt;
246.267 + }
246.268 + }
246.269 + /* NONBREAKTHROUGH */
246.270 + /* consider all arcs, whose one endpoint is labelled and other is
246.271 + not, and determine maximal change of node potentials */
246.272 + delta = 0;
246.273 + for (a = 1; a <= na; a++)
246.274 + { i = tail[a], j = head[a];
246.275 + if (link[i] != 0 && link[j] == 0)
246.276 + { /* a = i->j, where node i is labelled, node j is not */
246.277 + if (overflow(cost[a], pi[i] - pi[j]))
246.278 + { ret = 2;
246.279 + goto done;
246.280 + }
246.281 + lambda = cost[a] + (pi[i] - pi[j]);
246.282 + if (x[a] <= cap[a] && lambda > 0)
246.283 + if (delta == 0 || delta > + lambda) delta = + lambda;
246.284 + }
246.285 + else if (link[i] == 0 && link[j] != 0)
246.286 + { /* a = j<-i, where node j is labelled, node i is not */
246.287 + if (overflow(cost[a], pi[i] - pi[j]))
246.288 + { ret = 2;
246.289 + goto done;
246.290 + }
246.291 + lambda = cost[a] + (pi[i] - pi[j]);
246.292 + if (x[a] >= low[a] && lambda < 0)
246.293 + if (delta == 0 || delta > - lambda) delta = - lambda;
246.294 + }
246.295 + }
246.296 + if (delta == 0)
246.297 + { /* there is no feasible circulation */
246.298 + ret = 1;
246.299 + goto done;
246.300 + }
246.301 + /* increase potentials of all unlabelled nodes */
246.302 + for (i = 1; i <= nv; i++)
246.303 + { if (link[i] == 0)
246.304 + { if (overflow(pi[i], delta))
246.305 + { ret = 2;
246.306 + goto done;
246.307 + }
246.308 + pi[i] += delta;
246.309 + }
246.310 + }
246.311 + goto loop;
246.312 +brkt: /* BREAKTHROUGH */
246.313 + /* walk through arcs of the cycle (t, a, s, ..., t) found in the
246.314 + reverse order and determine maximal change of the flow */
246.315 + delta = 0;
246.316 + for (j = t;; j = i)
246.317 + { /* arc a immediately precedes node j in the cycle */
246.318 + a = link[j];
246.319 + if (head[a] == j)
246.320 + { /* a = i->j is a forward arc of the cycle */
246.321 + i = tail[a];
246.322 + lambda = cost[a] + (pi[i] - pi[j]);
246.323 + if (lambda > 0 && x[a] < low[a])
246.324 + { /* x[a] may be increased until its lower bound */
246.325 + temp = low[a] - x[a];
246.326 + }
246.327 + else if (lambda <= 0 && x[a] < cap[a])
246.328 + { /* x[a] may be increased until its upper bound */
246.329 + temp = cap[a] - x[a];
246.330 + }
246.331 + else
246.332 + xassert(a != a);
246.333 + }
246.334 + else if (tail[a] == j)
246.335 + { /* a = i<-j is a backward arc of the cycle */
246.336 + i = head[a];
246.337 + lambda = cost[a] + (pi[j] - pi[i]);
246.338 + if (lambda < 0 && x[a] > cap[a])
246.339 + { /* x[a] may be decreased until its upper bound */
246.340 + temp = x[a] - cap[a];
246.341 + }
246.342 + else if (lambda >= 0 && x[a] > low[a])
246.343 + { /* x[a] may be decreased until its lower bound */
246.344 + temp = x[a] - low[a];
246.345 + }
246.346 + else
246.347 + xassert(a != a);
246.348 + }
246.349 + else
246.350 + xassert(a != a);
246.351 + if (delta == 0 || delta > temp) delta = temp;
246.352 + /* check for end of the cycle */
246.353 + if (i == t) break;
246.354 + }
246.355 + xassert(delta > 0);
246.356 + /* increase the flow along the cycle */
246.357 + for (j = t;; j = i)
246.358 + { /* arc a immediately precedes node j in the cycle */
246.359 + a = link[j];
246.360 + if (head[a] == j)
246.361 + { /* a = i->j is a forward arc of the cycle */
246.362 + i = tail[a];
246.363 + /* overflow cannot occur */
246.364 + x[a] += delta;
246.365 + }
246.366 + else if (tail[a] == j)
246.367 + { /* a = i<-j is a backward arc of the cycle */
246.368 + i = head[a];
246.369 + /* overflow cannot occur */
246.370 + x[a] -= delta;
246.371 + }
246.372 + else
246.373 + xassert(a != a);
246.374 + /* check for end of the cycle */
246.375 + if (i == t) break;
246.376 + }
246.377 + goto loop;
246.378 +done: /* free working arrays */
246.379 + xfree(ptr);
246.380 + xfree(arc);
246.381 + xfree(link);
246.382 + xfree(list);
246.383 + return ret;
246.384 +}
246.385 +
246.386 +/* eof */
247.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
247.2 +++ b/src/glpnet07.c Mon Dec 06 13:09:21 2010 +0100
247.3 @@ -0,0 +1,222 @@
247.4 +/* glpnet07.c (Ford-Fulkerson algorithm) */
247.5 +
247.6 +/***********************************************************************
247.7 +* This code is part of GLPK (GNU Linear Programming Kit).
247.8 +*
247.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
247.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
247.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
247.12 +* E-mail: <mao@gnu.org>.
247.13 +*
247.14 +* GLPK is free software: you can redistribute it and/or modify it
247.15 +* under the terms of the GNU General Public License as published by
247.16 +* the Free Software Foundation, either version 3 of the License, or
247.17 +* (at your option) any later version.
247.18 +*
247.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
247.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
247.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
247.22 +* License for more details.
247.23 +*
247.24 +* You should have received a copy of the GNU General Public License
247.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
247.26 +***********************************************************************/
247.27 +
247.28 +#include "glpenv.h"
247.29 +#include "glpnet.h"
247.30 +
247.31 +/***********************************************************************
247.32 +* NAME
247.33 +*
247.34 +* ffalg - Ford-Fulkerson algorithm
247.35 +*
247.36 +* SYNOPSIS
247.37 +*
247.38 +* #include "glpnet.h"
247.39 +* void ffalg(int nv, int na, const int tail[], const int head[],
247.40 +* int s, int t, const int cap[], int x[], char cut[]);
247.41 +*
247.42 +* DESCRIPTION
247.43 +*
247.44 +* The routine ffalg implements the Ford-Fulkerson algorithm to find a
247.45 +* maximal flow in the specified flow network.
247.46 +*
247.47 +* INPUT PARAMETERS
247.48 +*
247.49 +* nv is the number of nodes, nv >= 2.
247.50 +*
247.51 +* na is the number of arcs, na >= 0.
247.52 +*
247.53 +* tail[a], a = 1,...,na, is the index of tail node of arc a.
247.54 +*
247.55 +* head[a], a = 1,...,na, is the index of head node of arc a.
247.56 +*
247.57 +* s is the source node index, 1 <= s <= nv.
247.58 +*
247.59 +* t is the sink node index, 1 <= t <= nv, t != s.
247.60 +*
247.61 +* cap[a], a = 1,...,na, is the capacity of arc a, cap[a] >= 0.
247.62 +*
247.63 +* NOTE: Multiple arcs are allowed, but self-loops are not allowed.
247.64 +*
247.65 +* OUTPUT PARAMETERS
247.66 +*
247.67 +* x[a], a = 1,...,na, is optimal value of the flow through arc a.
247.68 +*
247.69 +* cut[i], i = 1,...,nv, is 1 if node i is labelled, and 0 otherwise.
247.70 +* The set of arcs, whose one endpoint is labelled and other is not,
247.71 +* defines the minimal cut corresponding to the maximal flow found.
247.72 +* If the parameter cut is NULL, the cut information are not stored.
247.73 +*
247.74 +* REFERENCES
247.75 +*
247.76 +* L.R.Ford, Jr., and D.R.Fulkerson, "Flows in Networks," The RAND
247.77 +* Corp., Report R-375-PR (August 1962), Chap. I "Static Maximal Flow,"
247.78 +* pp.30-33. */
247.79 +
247.80 +void ffalg(int nv, int na, const int tail[], const int head[],
247.81 + int s, int t, const int cap[], int x[], char cut[])
247.82 +{ int a, delta, i, j, k, pos1, pos2, temp,
247.83 + *ptr, *arc, *link, *list;
247.84 + /* sanity checks */
247.85 + xassert(nv >= 2);
247.86 + xassert(na >= 0);
247.87 + xassert(1 <= s && s <= nv);
247.88 + xassert(1 <= t && t <= nv);
247.89 + xassert(s != t);
247.90 + for (a = 1; a <= na; a++)
247.91 + { i = tail[a], j = head[a];
247.92 + xassert(1 <= i && i <= nv);
247.93 + xassert(1 <= j && j <= nv);
247.94 + xassert(i != j);
247.95 + xassert(cap[a] >= 0);
247.96 + }
247.97 + /* allocate working arrays */
247.98 + ptr = xcalloc(1+nv+1, sizeof(int));
247.99 + arc = xcalloc(1+na+na, sizeof(int));
247.100 + link = xcalloc(1+nv, sizeof(int));
247.101 + list = xcalloc(1+nv, sizeof(int));
247.102 + /* ptr[i] := (degree of node i) */
247.103 + for (i = 1; i <= nv; i++)
247.104 + ptr[i] = 0;
247.105 + for (a = 1; a <= na; a++)
247.106 + { ptr[tail[a]]++;
247.107 + ptr[head[a]]++;
247.108 + }
247.109 + /* initialize arc pointers */
247.110 + ptr[1]++;
247.111 + for (i = 1; i < nv; i++)
247.112 + ptr[i+1] += ptr[i];
247.113 + ptr[nv+1] = ptr[nv];
247.114 + /* build arc lists */
247.115 + for (a = 1; a <= na; a++)
247.116 + { arc[--ptr[tail[a]]] = a;
247.117 + arc[--ptr[head[a]]] = a;
247.118 + }
247.119 + xassert(ptr[1] == 1);
247.120 + xassert(ptr[nv+1] == na+na+1);
247.121 + /* now the indices of arcs incident to node i are stored in
247.122 + locations arc[ptr[i]], arc[ptr[i]+1], ..., arc[ptr[i+1]-1] */
247.123 + /* initialize arc flows */
247.124 + for (a = 1; a <= na; a++)
247.125 + x[a] = 0;
247.126 +loop: /* main loop starts here */
247.127 + /* build augmenting tree rooted at s */
247.128 + /* link[i] = 0 means that node i is not labelled yet;
247.129 + link[i] = a means that arc a immediately precedes node i */
247.130 + /* initially node s is labelled as the root */
247.131 + for (i = 1; i <= nv; i++)
247.132 + link[i] = 0;
247.133 + link[s] = -1, list[1] = s, pos1 = pos2 = 1;
247.134 + /* breadth first search */
247.135 + while (pos1 <= pos2)
247.136 + { /* dequeue node i */
247.137 + i = list[pos1++];
247.138 + /* consider all arcs incident to node i */
247.139 + for (k = ptr[i]; k < ptr[i+1]; k++)
247.140 + { a = arc[k];
247.141 + if (tail[a] == i)
247.142 + { /* a = i->j is a forward arc from s to t */
247.143 + j = head[a];
247.144 + /* if node j has been labelled, skip the arc */
247.145 + if (link[j] != 0) continue;
247.146 + /* if the arc does not allow increasing the flow through
247.147 + it, skip the arc */
247.148 + if (x[a] == cap[a]) continue;
247.149 + }
247.150 + else if (head[a] == i)
247.151 + { /* a = i<-j is a backward arc from s to t */
247.152 + j = tail[a];
247.153 + /* if node j has been labelled, skip the arc */
247.154 + if (link[j] != 0) continue;
247.155 + /* if the arc does not allow decreasing the flow through
247.156 + it, skip the arc */
247.157 + if (x[a] == 0) continue;
247.158 + }
247.159 + else
247.160 + xassert(a != a);
247.161 + /* label node j and enqueue it */
247.162 + link[j] = a, list[++pos2] = j;
247.163 + /* check for breakthrough */
247.164 + if (j == t) goto brkt;
247.165 + }
247.166 + }
247.167 + /* NONBREAKTHROUGH */
247.168 + /* no augmenting path exists; current flow is maximal */
247.169 + /* store minimal cut information, if necessary */
247.170 + if (cut != NULL)
247.171 + { for (i = 1; i <= nv; i++)
247.172 + cut[i] = (char)(link[i] != 0);
247.173 + }
247.174 + goto done;
247.175 +brkt: /* BREAKTHROUGH */
247.176 + /* walk through arcs of the augmenting path (s, ..., t) found in
247.177 + the reverse order and determine maximal change of the flow */
247.178 + delta = 0;
247.179 + for (j = t; j != s; j = i)
247.180 + { /* arc a immediately precedes node j in the path */
247.181 + a = link[j];
247.182 + if (head[a] == j)
247.183 + { /* a = i->j is a forward arc of the cycle */
247.184 + i = tail[a];
247.185 + /* x[a] may be increased until its upper bound */
247.186 + temp = cap[a] - x[a];
247.187 + }
247.188 + else if (tail[a] == j)
247.189 + { /* a = i<-j is a backward arc of the cycle */
247.190 + i = head[a];
247.191 + /* x[a] may be decreased until its lower bound */
247.192 + temp = x[a];
247.193 + }
247.194 + else
247.195 + xassert(a != a);
247.196 + if (delta == 0 || delta > temp) delta = temp;
247.197 + }
247.198 + xassert(delta > 0);
247.199 + /* increase the flow along the path */
247.200 + for (j = t; j != s; j = i)
247.201 + { /* arc a immediately precedes node j in the path */
247.202 + a = link[j];
247.203 + if (head[a] == j)
247.204 + { /* a = i->j is a forward arc of the cycle */
247.205 + i = tail[a];
247.206 + x[a] += delta;
247.207 + }
247.208 + else if (tail[a] == j)
247.209 + { /* a = i<-j is a backward arc of the cycle */
247.210 + i = head[a];
247.211 + x[a] -= delta;
247.212 + }
247.213 + else
247.214 + xassert(a != a);
247.215 + }
247.216 + goto loop;
247.217 +done: /* free working arrays */
247.218 + xfree(ptr);
247.219 + xfree(arc);
247.220 + xfree(link);
247.221 + xfree(list);
247.222 + return;
247.223 +}
247.224 +
247.225 +/* eof */
248.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
248.2 +++ b/src/glpnet08.c Mon Dec 06 13:09:21 2010 +0100
248.3 @@ -0,0 +1,241 @@
248.4 +/* glpnet08.c */
248.5 +
248.6 +/***********************************************************************
248.7 +* This code is part of GLPK (GNU Linear Programming Kit).
248.8 +*
248.9 +* Two subroutines sub() and wclique() below are intended to find a
248.10 +* maximum weight clique in a given undirected graph. These subroutines
248.11 +* are slightly modified version of the program WCLIQUE developed by
248.12 +* Patric Ostergard <http://www.tcs.hut.fi/~pat/wclique.html> and based
248.13 +* on ideas from the article "P. R. J. Ostergard, A new algorithm for
248.14 +* the maximum-weight clique problem, submitted for publication", which
248.15 +* in turn is a generalization of the algorithm for unweighted graphs
248.16 +* presented in "P. R. J. Ostergard, A fast algorithm for the maximum
248.17 +* clique problem, submitted for publication".
248.18 +*
248.19 +* USED WITH PERMISSION OF THE AUTHOR OF THE ORIGINAL CODE.
248.20 +*
248.21 +* Changes were made by Andrew Makhorin <mao@gnu.org>.
248.22 +*
248.23 +* GLPK is free software: you can redistribute it and/or modify it
248.24 +* under the terms of the GNU General Public License as published by
248.25 +* the Free Software Foundation, either version 3 of the License, or
248.26 +* (at your option) any later version.
248.27 +*
248.28 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
248.29 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
248.30 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
248.31 +* License for more details.
248.32 +*
248.33 +* You should have received a copy of the GNU General Public License
248.34 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
248.35 +***********************************************************************/
248.36 +
248.37 +#include "glpenv.h"
248.38 +#include "glpnet.h"
248.39 +
248.40 +/***********************************************************************
248.41 +* NAME
248.42 +*
248.43 +* wclique - find maximum weight clique with Ostergard's algorithm
248.44 +*
248.45 +* SYNOPSIS
248.46 +*
248.47 +* int wclique(int n, const int w[], const unsigned char a[],
248.48 +* int ind[]);
248.49 +*
248.50 +* DESCRIPTION
248.51 +*
248.52 +* The routine wclique finds a maximum weight clique in an undirected
248.53 +* graph with Ostergard's algorithm.
248.54 +*
248.55 +* INPUT PARAMETERS
248.56 +*
248.57 +* n is the number of vertices, n > 0.
248.58 +*
248.59 +* w[i], i = 1,...,n, is a weight of vertex i.
248.60 +*
248.61 +* a[*] is the strict (without main diagonal) lower triangle of the
248.62 +* graph adjacency matrix in packed format.
248.63 +*
248.64 +* OUTPUT PARAMETER
248.65 +*
248.66 +* ind[k], k = 1,...,size, is the number of a vertex included in the
248.67 +* clique found, 1 <= ind[k] <= n, where size is the number of vertices
248.68 +* in the clique returned on exit.
248.69 +*
248.70 +* RETURNS
248.71 +*
248.72 +* The routine returns the clique size, i.e. the number of vertices in
248.73 +* the clique. */
248.74 +
248.75 +struct csa
248.76 +{ /* common storage area */
248.77 + int n;
248.78 + /* number of vertices */
248.79 + const int *wt; /* int wt[0:n-1]; */
248.80 + /* weights */
248.81 + const unsigned char *a;
248.82 + /* adjacency matrix (packed lower triangle without main diag.) */
248.83 + int record;
248.84 + /* weight of best clique */
248.85 + int rec_level;
248.86 + /* number of vertices in best clique */
248.87 + int *rec; /* int rec[0:n-1]; */
248.88 + /* best clique so far */
248.89 + int *clique; /* int clique[0:n-1]; */
248.90 + /* table for pruning */
248.91 + int *set; /* int set[0:n-1]; */
248.92 + /* current clique */
248.93 +};
248.94 +
248.95 +#define n (csa->n)
248.96 +#define wt (csa->wt)
248.97 +#define a (csa->a)
248.98 +#define record (csa->record)
248.99 +#define rec_level (csa->rec_level)
248.100 +#define rec (csa->rec)
248.101 +#define clique (csa->clique)
248.102 +#define set (csa->set)
248.103 +
248.104 +#if 0
248.105 +static int is_edge(struct csa *csa, int i, int j)
248.106 +{ /* if there is arc (i,j), the routine returns true; otherwise
248.107 + false; 0 <= i, j < n */
248.108 + int k;
248.109 + xassert(0 <= i && i < n);
248.110 + xassert(0 <= j && j < n);
248.111 + if (i == j) return 0;
248.112 + if (i < j) k = i, i = j, j = k;
248.113 + k = (i * (i - 1)) / 2 + j;
248.114 + return a[k / CHAR_BIT] &
248.115 + (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT));
248.116 +}
248.117 +#else
248.118 +#define is_edge(csa, i, j) ((i) == (j) ? 0 : \
248.119 + (i) > (j) ? is_edge1(i, j) : is_edge1(j, i))
248.120 +#define is_edge1(i, j) is_edge2(((i) * ((i) - 1)) / 2 + (j))
248.121 +#define is_edge2(k) (a[(k) / CHAR_BIT] & \
248.122 + (unsigned char)(1 << ((CHAR_BIT - 1) - (k) % CHAR_BIT)))
248.123 +#endif
248.124 +
248.125 +static void sub(struct csa *csa, int ct, int table[], int level,
248.126 + int weight, int l_weight)
248.127 +{ int i, j, k, curr_weight, left_weight, *p1, *p2, *newtable;
248.128 + newtable = xcalloc(n, sizeof(int));
248.129 + if (ct <= 0)
248.130 + { /* 0 or 1 elements left; include these */
248.131 + if (ct == 0)
248.132 + { set[level++] = table[0];
248.133 + weight += l_weight;
248.134 + }
248.135 + if (weight > record)
248.136 + { record = weight;
248.137 + rec_level = level;
248.138 + for (i = 0; i < level; i++) rec[i] = set[i];
248.139 + }
248.140 + goto done;
248.141 + }
248.142 + for (i = ct; i >= 0; i--)
248.143 + { if ((level == 0) && (i < ct)) goto done;
248.144 + k = table[i];
248.145 + if ((level > 0) && (clique[k] <= (record - weight)))
248.146 + goto done; /* prune */
248.147 + set[level] = k;
248.148 + curr_weight = weight + wt[k];
248.149 + l_weight -= wt[k];
248.150 + if (l_weight <= (record - curr_weight))
248.151 + goto done; /* prune */
248.152 + p1 = newtable;
248.153 + p2 = table;
248.154 + left_weight = 0;
248.155 + while (p2 < table + i)
248.156 + { j = *p2++;
248.157 + if (is_edge(csa, j, k))
248.158 + { *p1++ = j;
248.159 + left_weight += wt[j];
248.160 + }
248.161 + }
248.162 + if (left_weight <= (record - curr_weight)) continue;
248.163 + sub(csa, p1 - newtable - 1, newtable, level + 1, curr_weight,
248.164 + left_weight);
248.165 + }
248.166 +done: xfree(newtable);
248.167 + return;
248.168 +}
248.169 +
248.170 +int wclique(int _n, const int w[], const unsigned char _a[], int ind[])
248.171 +{ struct csa _csa, *csa = &_csa;
248.172 + int i, j, p, max_wt, max_nwt, wth, *used, *nwt, *pos;
248.173 + glp_long timer;
248.174 + n = _n;
248.175 + xassert(n > 0);
248.176 + wt = &w[1];
248.177 + a = _a;
248.178 + record = 0;
248.179 + rec_level = 0;
248.180 + rec = &ind[1];
248.181 + clique = xcalloc(n, sizeof(int));
248.182 + set = xcalloc(n, sizeof(int));
248.183 + used = xcalloc(n, sizeof(int));
248.184 + nwt = xcalloc(n, sizeof(int));
248.185 + pos = xcalloc(n, sizeof(int));
248.186 + /* start timer */
248.187 + timer = xtime();
248.188 + /* order vertices */
248.189 + for (i = 0; i < n; i++)
248.190 + { nwt[i] = 0;
248.191 + for (j = 0; j < n; j++)
248.192 + if (is_edge(csa, i, j)) nwt[i] += wt[j];
248.193 + }
248.194 + for (i = 0; i < n; i++)
248.195 + used[i] = 0;
248.196 + for (i = n-1; i >= 0; i--)
248.197 + { max_wt = -1;
248.198 + max_nwt = -1;
248.199 + for (j = 0; j < n; j++)
248.200 + { if ((!used[j]) && ((wt[j] > max_wt) || (wt[j] == max_wt
248.201 + && nwt[j] > max_nwt)))
248.202 + { max_wt = wt[j];
248.203 + max_nwt = nwt[j];
248.204 + p = j;
248.205 + }
248.206 + }
248.207 + pos[i] = p;
248.208 + used[p] = 1;
248.209 + for (j = 0; j < n; j++)
248.210 + if ((!used[j]) && (j != p) && (is_edge(csa, p, j)))
248.211 + nwt[j] -= wt[p];
248.212 + }
248.213 + /* main routine */
248.214 + wth = 0;
248.215 + for (i = 0; i < n; i++)
248.216 + { wth += wt[pos[i]];
248.217 + sub(csa, i, pos, 0, 0, wth);
248.218 + clique[pos[i]] = record;
248.219 + if (xdifftime(xtime(), timer) >= 5.0 - 0.001)
248.220 + { /* print current record and reset timer */
248.221 + xprintf("level = %d (%d); best = %d\n", i+1, n, record);
248.222 + timer = xtime();
248.223 + }
248.224 + }
248.225 + xfree(clique);
248.226 + xfree(set);
248.227 + xfree(used);
248.228 + xfree(nwt);
248.229 + xfree(pos);
248.230 + /* return the solution found */
248.231 + for (i = 1; i <= rec_level; i++) ind[i]++;
248.232 + return rec_level;
248.233 +}
248.234 +
248.235 +#undef n
248.236 +#undef wt
248.237 +#undef a
248.238 +#undef record
248.239 +#undef rec_level
248.240 +#undef rec
248.241 +#undef clique
248.242 +#undef set
248.243 +
248.244 +/* eof */
249.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
249.2 +++ b/src/glpnet09.c Mon Dec 06 13:09:21 2010 +0100
249.3 @@ -0,0 +1,235 @@
249.4 +/* glpnet09.c */
249.5 +
249.6 +/***********************************************************************
249.7 +* This code is part of GLPK (GNU Linear Programming Kit).
249.8 +*
249.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
249.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
249.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
249.12 +* E-mail: <mao@gnu.org>.
249.13 +*
249.14 +* GLPK is free software: you can redistribute it and/or modify it
249.15 +* under the terms of the GNU General Public License as published by
249.16 +* the Free Software Foundation, either version 3 of the License, or
249.17 +* (at your option) any later version.
249.18 +*
249.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
249.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
249.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
249.22 +* License for more details.
249.23 +*
249.24 +* You should have received a copy of the GNU General Public License
249.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
249.26 +***********************************************************************/
249.27 +
249.28 +#include "glpapi.h"
249.29 +#include "glpnet.h"
249.30 +
249.31 +/***********************************************************************
249.32 +* NAME
249.33 +*
249.34 +* kellerman - cover edges by cliques with Kellerman's heuristic
249.35 +*
249.36 +* SYNOPSIS
249.37 +*
249.38 +* #include "glpnet.h"
249.39 +* int kellerman(int n, int (*func)(void *info, int i, int ind[]),
249.40 +* void *info, glp_graph *H);
249.41 +*
249.42 +* DESCRIPTION
249.43 +*
249.44 +* The routine kellerman implements Kellerman's heuristic algorithm
249.45 +* to find a minimal set of cliques which cover all edges of specified
249.46 +* graph G = (V, E).
249.47 +*
249.48 +* The parameter n specifies the number of vertices |V|, n >= 0.
249.49 +*
249.50 +* Formal routine func specifies the set of edges E in the following
249.51 +* way. Running the routine kellerman calls the routine func and passes
249.52 +* to it parameter i, which is the number of some vertex, 1 <= i <= n.
249.53 +* In response the routine func should store numbers of all vertices
249.54 +* adjacent to vertex i to locations ind[1], ind[2], ..., ind[len] and
249.55 +* return the value of len, which is the number of adjacent vertices,
249.56 +* 0 <= len <= n. Self-loops are allowed, but ignored. Multiple edges
249.57 +* are not allowed.
249.58 +*
249.59 +* The parameter info is a transit pointer (magic cookie) passed to the
249.60 +* formal routine func as its first parameter.
249.61 +*
249.62 +* The result provided by the routine kellerman is the bipartite graph
249.63 +* H = (V union C, F), which defines the covering found. (The program
249.64 +* object of type glp_graph specified by the parameter H should be
249.65 +* previously created with the routine glp_create_graph. On entry the
249.66 +* routine kellerman erases the content of this object with the routine
249.67 +* glp_erase_graph.) Vertices of first part V correspond to vertices of
249.68 +* the graph G and have the same ordinal numbers 1, 2, ..., n. Vertices
249.69 +* of second part C correspond to cliques and have ordinal numbers
249.70 +* n+1, n+2, ..., n+k, where k is the total number of cliques in the
249.71 +* edge covering found. Every edge f in F in the program object H is
249.72 +* represented as arc f = (i->j), where i in V and j in C, which means
249.73 +* that vertex i of the graph G is in clique C[j], 1 <= j <= k. (Thus,
249.74 +* if two vertices of the graph G are in the same clique, these vertices
249.75 +* are adjacent in G, and corresponding edge is covered by that clique.)
249.76 +*
249.77 +* RETURNS
249.78 +*
249.79 +* The routine Kellerman returns k, the total number of cliques in the
249.80 +* edge covering found.
249.81 +*
249.82 +* REFERENCE
249.83 +*
249.84 +* For more details see: glpk/doc/notes/keller.pdf (in Russian). */
249.85 +
249.86 +struct set
249.87 +{ /* set of vertices */
249.88 + int size;
249.89 + /* size (cardinality) of the set, 0 <= card <= n */
249.90 + int *list; /* int list[1+n]; */
249.91 + /* the set contains vertices list[1,...,size] */
249.92 + int *pos; /* int pos[1+n]; */
249.93 + /* pos[i] > 0 means that vertex i is in the set and
249.94 + list[pos[i]] = i; pos[i] = 0 means that vertex i is not in
249.95 + the set */
249.96 +};
249.97 +
249.98 +int kellerman(int n, int (*func)(void *info, int i, int ind[]),
249.99 + void *info, void /* glp_graph */ *H_)
249.100 +{ glp_graph *H = H_;
249.101 + struct set W_, *W = &W_, V_, *V = &V_;
249.102 + glp_arc *a;
249.103 + int i, j, k, m, t, len, card, best;
249.104 + xassert(n >= 0);
249.105 + /* H := (V, 0; 0), where V is the set of vertices of graph G */
249.106 + glp_erase_graph(H, H->v_size, H->a_size);
249.107 + glp_add_vertices(H, n);
249.108 + /* W := 0 */
249.109 + W->size = 0;
249.110 + W->list = xcalloc(1+n, sizeof(int));
249.111 + W->pos = xcalloc(1+n, sizeof(int));
249.112 + memset(&W->pos[1], 0, sizeof(int) * n);
249.113 + /* V := 0 */
249.114 + V->size = 0;
249.115 + V->list = xcalloc(1+n, sizeof(int));
249.116 + V->pos = xcalloc(1+n, sizeof(int));
249.117 + memset(&V->pos[1], 0, sizeof(int) * n);
249.118 + /* main loop */
249.119 + for (i = 1; i <= n; i++)
249.120 + { /* W must be empty */
249.121 + xassert(W->size == 0);
249.122 + /* W := { j : i > j and (i,j) in E } */
249.123 + len = func(info, i, W->list);
249.124 + xassert(0 <= len && len <= n);
249.125 + for (t = 1; t <= len; t++)
249.126 + { j = W->list[t];
249.127 + xassert(1 <= j && j <= n);
249.128 + if (j >= i) continue;
249.129 + xassert(W->pos[j] == 0);
249.130 + W->list[++W->size] = j, W->pos[j] = W->size;
249.131 + }
249.132 + /* on i-th iteration we need to cover edges (i,j) for all
249.133 + j in W */
249.134 + /* if W is empty, it is a special case */
249.135 + if (W->size == 0)
249.136 + { /* set k := k + 1 and create new clique C[k] = { i } */
249.137 + k = glp_add_vertices(H, 1) - n;
249.138 + glp_add_arc(H, i, n + k);
249.139 + continue;
249.140 + }
249.141 + /* try to include vertex i into existing cliques */
249.142 + /* V must be empty */
249.143 + xassert(V->size == 0);
249.144 + /* k is the number of cliques found so far */
249.145 + k = H->nv - n;
249.146 + for (m = 1; m <= k; m++)
249.147 + { /* do while V != W; since here V is within W, we can use
249.148 + equivalent condition: do while |V| < |W| */
249.149 + if (V->size == W->size) break;
249.150 + /* check if C[m] is within W */
249.151 + for (a = H->v[n + m]->in; a != NULL; a = a->h_next)
249.152 + { j = a->tail->i;
249.153 + if (W->pos[j] == 0) break;
249.154 + }
249.155 + if (a != NULL) continue;
249.156 + /* C[m] is within W, expand clique C[m] with vertex i */
249.157 + /* C[m] := C[m] union {i} */
249.158 + glp_add_arc(H, i, n + m);
249.159 + /* V is a set of vertices whose incident edges are already
249.160 + covered by existing cliques */
249.161 + /* V := V union C[m] */
249.162 + for (a = H->v[n + m]->in; a != NULL; a = a->h_next)
249.163 + { j = a->tail->i;
249.164 + if (V->pos[j] == 0)
249.165 + V->list[++V->size] = j, V->pos[j] = V->size;
249.166 + }
249.167 + }
249.168 + /* remove from set W the vertices whose incident edges are
249.169 + already covered by existing cliques */
249.170 + /* W := W \ V, V := 0 */
249.171 + for (t = 1; t <= V->size; t++)
249.172 + { j = V->list[t], V->pos[j] = 0;
249.173 + if (W->pos[j] != 0)
249.174 + { /* remove vertex j from W */
249.175 + if (W->pos[j] != W->size)
249.176 + { int jj = W->list[W->size];
249.177 + W->list[W->pos[j]] = jj;
249.178 + W->pos[jj] = W->pos[j];
249.179 + }
249.180 + W->size--, W->pos[j] = 0;
249.181 + }
249.182 + }
249.183 + V->size = 0;
249.184 + /* now set W contains only vertices whose incident edges are
249.185 + still not covered by existing cliques; create new cliques
249.186 + to cover remaining edges until set W becomes empty */
249.187 + while (W->size > 0)
249.188 + { /* find clique C[m], 1 <= m <= k, which shares maximal
249.189 + number of vertices with W; to break ties choose clique
249.190 + having smallest number m */
249.191 + m = 0, best = -1;
249.192 + k = H->nv - n;
249.193 + for (t = 1; t <= k; t++)
249.194 + { /* compute cardinality of intersection of W and C[t] */
249.195 + card = 0;
249.196 + for (a = H->v[n + t]->in; a != NULL; a = a->h_next)
249.197 + { j = a->tail->i;
249.198 + if (W->pos[j] != 0) card++;
249.199 + }
249.200 + if (best < card)
249.201 + m = t, best = card;
249.202 + }
249.203 + xassert(m > 0);
249.204 + /* set k := k + 1 and create new clique:
249.205 + C[k] := (W intersect C[m]) union { i }, which covers all
249.206 + edges incident to vertices from (W intersect C[m]) */
249.207 + k = glp_add_vertices(H, 1) - n;
249.208 + for (a = H->v[n + m]->in; a != NULL; a = a->h_next)
249.209 + { j = a->tail->i;
249.210 + if (W->pos[j] != 0)
249.211 + { /* vertex j is in both W and C[m]; include it in new
249.212 + clique C[k] */
249.213 + glp_add_arc(H, j, n + k);
249.214 + /* remove vertex j from W, since edge (i,j) will be
249.215 + covered by new clique C[k] */
249.216 + if (W->pos[j] != W->size)
249.217 + { int jj = W->list[W->size];
249.218 + W->list[W->pos[j]] = jj;
249.219 + W->pos[jj] = W->pos[j];
249.220 + }
249.221 + W->size--, W->pos[j] = 0;
249.222 + }
249.223 + }
249.224 + /* include vertex i to new clique C[k] to cover edges (i,j)
249.225 + incident to all vertices j just removed from W */
249.226 + glp_add_arc(H, i, n + k);
249.227 + }
249.228 + }
249.229 + /* free working arrays */
249.230 + xfree(W->list);
249.231 + xfree(W->pos);
249.232 + xfree(V->list);
249.233 + xfree(V->pos);
249.234 + /* return the number of cliques in the edge covering found */
249.235 + return H->nv - n;
249.236 +}
249.237 +
249.238 +/* eof */
250.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
250.2 +++ b/src/glpnpp.h Mon Dec 06 13:09:21 2010 +0100
250.3 @@ -0,0 +1,520 @@
250.4 +/* glpnpp.h (LP/MIP preprocessor) */
250.5 +
250.6 +/***********************************************************************
250.7 +* This code is part of GLPK (GNU Linear Programming Kit).
250.8 +*
250.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
250.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
250.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
250.12 +* E-mail: <mao@gnu.org>.
250.13 +*
250.14 +* GLPK is free software: you can redistribute it and/or modify it
250.15 +* under the terms of the GNU General Public License as published by
250.16 +* the Free Software Foundation, either version 3 of the License, or
250.17 +* (at your option) any later version.
250.18 +*
250.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
250.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
250.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
250.22 +* License for more details.
250.23 +*
250.24 +* You should have received a copy of the GNU General Public License
250.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
250.26 +***********************************************************************/
250.27 +
250.28 +#ifndef GLPNPP_H
250.29 +#define GLPNPP_H
250.30 +
250.31 +#include "glpapi.h"
250.32 +
250.33 +typedef struct NPP NPP;
250.34 +typedef struct NPPROW NPPROW;
250.35 +typedef struct NPPCOL NPPCOL;
250.36 +typedef struct NPPAIJ NPPAIJ;
250.37 +typedef struct NPPTSE NPPTSE;
250.38 +typedef struct NPPLFE NPPLFE;
250.39 +
250.40 +struct NPP
250.41 +{ /* LP/MIP preprocessor workspace */
250.42 + /*--------------------------------------------------------------*/
250.43 + /* original problem segment */
250.44 + int orig_dir;
250.45 + /* optimization direction flag:
250.46 + GLP_MIN - minimization
250.47 + GLP_MAX - maximization */
250.48 + int orig_m;
250.49 + /* number of rows */
250.50 + int orig_n;
250.51 + /* number of columns */
250.52 + int orig_nnz;
250.53 + /* number of non-zero constraint coefficients */
250.54 + /*--------------------------------------------------------------*/
250.55 + /* transformed problem segment (always minimization) */
250.56 + DMP *pool;
250.57 + /* memory pool to store problem components */
250.58 + char *name;
250.59 + /* problem name (1 to 255 chars); NULL means no name is assigned
250.60 + to the problem */
250.61 + char *obj;
250.62 + /* objective function name (1 to 255 chars); NULL means no name
250.63 + is assigned to the objective function */
250.64 + double c0;
250.65 + /* constant term of the objective function */
250.66 + int nrows;
250.67 + /* number of rows introduced into the problem; this count
250.68 + increases by one every time a new row is added and never
250.69 + decreases; thus, actual number of rows may be less than nrows
250.70 + due to row deletions */
250.71 + int ncols;
250.72 + /* number of columns introduced into the problem; this count
250.73 + increases by one every time a new column is added and never
250.74 + decreases; thus, actual number of column may be less than
250.75 + ncols due to column deletions */
250.76 + NPPROW *r_head;
250.77 + /* pointer to the beginning of the row list */
250.78 + NPPROW *r_tail;
250.79 + /* pointer to the end of the row list */
250.80 + NPPCOL *c_head;
250.81 + /* pointer to the beginning of the column list */
250.82 + NPPCOL *c_tail;
250.83 + /* pointer to the end of the column list */
250.84 + /*--------------------------------------------------------------*/
250.85 + /* transformation history */
250.86 + DMP *stack;
250.87 + /* memory pool to store transformation entries */
250.88 + NPPTSE *top;
250.89 + /* pointer to most recent transformation entry */
250.90 +#if 0 /* 16/XII-2009 */
250.91 + int count[1+25];
250.92 + /* transformation statistics */
250.93 +#endif
250.94 + /*--------------------------------------------------------------*/
250.95 + /* resultant (preprocessed) problem segment */
250.96 + int m;
250.97 + /* number of rows */
250.98 + int n;
250.99 + /* number of columns */
250.100 + int nnz;
250.101 + /* number of non-zero constraint coefficients */
250.102 + int *row_ref; /* int row_ref[1+m]; */
250.103 + /* row_ref[i], 1 <= i <= m, is the reference number assigned to
250.104 + a row, which is i-th row of the resultant problem */
250.105 + int *col_ref; /* int col_ref[1+n]; */
250.106 + /* col_ref[j], 1 <= j <= n, is the reference number assigned to
250.107 + a column, which is j-th column of the resultant problem */
250.108 + /*--------------------------------------------------------------*/
250.109 + /* recovered solution segment */
250.110 + int sol;
250.111 + /* solution indicator:
250.112 + GLP_SOL - basic solution
250.113 + GLP_IPT - interior-point solution
250.114 + GLP_MIP - mixed integer solution */
250.115 + int scaling;
250.116 + /* scaling option:
250.117 + GLP_OFF - scaling is disabled
250.118 + GLP_ON - scaling is enabled */
250.119 + int p_stat;
250.120 + /* status of primal basic solution:
250.121 + GLP_UNDEF - primal solution is undefined
250.122 + GLP_FEAS - primal solution is feasible
250.123 + GLP_INFEAS - primal solution is infeasible
250.124 + GLP_NOFEAS - no primal feasible solution exists */
250.125 + int d_stat;
250.126 + /* status of dual basic solution:
250.127 + GLP_UNDEF - dual solution is undefined
250.128 + GLP_FEAS - dual solution is feasible
250.129 + GLP_INFEAS - dual solution is infeasible
250.130 + GLP_NOFEAS - no dual feasible solution exists */
250.131 + int t_stat;
250.132 + /* status of interior-point solution:
250.133 + GLP_UNDEF - interior solution is undefined
250.134 + GLP_OPT - interior solution is optimal */
250.135 + int i_stat;
250.136 + /* status of mixed integer solution:
250.137 + GLP_UNDEF - integer solution is undefined
250.138 + GLP_OPT - integer solution is optimal
250.139 + GLP_FEAS - integer solution is feasible
250.140 + GLP_NOFEAS - no integer solution exists */
250.141 + char *r_stat; /* char r_stat[1+nrows]; */
250.142 + /* r_stat[i], 1 <= i <= nrows, is status of i-th row:
250.143 + GLP_BS - inactive constraint
250.144 + GLP_NL - active constraint on lower bound
250.145 + GLP_NU - active constraint on upper bound
250.146 + GLP_NF - active free row
250.147 + GLP_NS - active equality constraint */
250.148 + char *c_stat; /* char c_stat[1+nrows]; */
250.149 + /* c_stat[j], 1 <= j <= nrows, is status of j-th column:
250.150 + GLP_BS - basic variable
250.151 + GLP_NL - non-basic variable on lower bound
250.152 + GLP_NU - non-basic variable on upper bound
250.153 + GLP_NF - non-basic free variable
250.154 + GLP_NS - non-basic fixed variable */
250.155 + double *r_pi; /* double r_pi[1+nrows]; */
250.156 + /* r_pi[i], 1 <= i <= nrows, is Lagrange multiplier (dual value)
250.157 + for i-th row (constraint) */
250.158 + double *c_value; /* double c_value[1+ncols]; */
250.159 + /* c_value[j], 1 <= j <= ncols, is primal value of j-th column
250.160 + (structural variable) */
250.161 +};
250.162 +
250.163 +struct NPPROW
250.164 +{ /* row (constraint) */
250.165 + int i;
250.166 + /* reference number assigned to the row, 1 <= i <= nrows */
250.167 + char *name;
250.168 + /* row name (1 to 255 chars); NULL means no name is assigned to
250.169 + the row */
250.170 + double lb;
250.171 + /* lower bound; -DBL_MAX means the row has no lower bound */
250.172 + double ub;
250.173 + /* upper bound; +DBL_MAX means the row has no upper bound */
250.174 + NPPAIJ *ptr;
250.175 + /* pointer to the linked list of constraint coefficients */
250.176 + int temp;
250.177 + /* working field used by preprocessor routines */
250.178 + NPPROW *prev;
250.179 + /* pointer to previous row in the row list */
250.180 + NPPROW *next;
250.181 + /* pointer to next row in the row list */
250.182 +};
250.183 +
250.184 +struct NPPCOL
250.185 +{ /* column (variable) */
250.186 + int j;
250.187 + /* reference number assigned to the column, 1 <= j <= ncols */
250.188 + char *name;
250.189 + /* column name (1 to 255 chars); NULL means no name is assigned
250.190 + to the column */
250.191 + char is_int;
250.192 + /* 0 means continuous variable; 1 means integer variable */
250.193 + double lb;
250.194 + /* lower bound; -DBL_MAX means the column has no lower bound */
250.195 + double ub;
250.196 + /* upper bound; +DBL_MAX means the column has no upper bound */
250.197 + double coef;
250.198 + /* objective coefficient */
250.199 + NPPAIJ *ptr;
250.200 + /* pointer to the linked list of constraint coefficients */
250.201 + int temp;
250.202 + /* working field used by preprocessor routines */
250.203 +#if 1 /* 28/XII-2009 */
250.204 + union
250.205 + { double ll;
250.206 + /* implied column lower bound */
250.207 + int pos;
250.208 + /* vertex ordinal number corresponding to this binary column
250.209 + in the conflict graph (0, if the vertex does not exist) */
250.210 + } ll;
250.211 + union
250.212 + { double uu;
250.213 + /* implied column upper bound */
250.214 + int neg;
250.215 + /* vertex ordinal number corresponding to complement of this
250.216 + binary column in the conflict graph (0, if the vertex does
250.217 + not exist) */
250.218 + } uu;
250.219 +#endif
250.220 + NPPCOL *prev;
250.221 + /* pointer to previous column in the column list */
250.222 + NPPCOL *next;
250.223 + /* pointer to next column in the column list */
250.224 +};
250.225 +
250.226 +struct NPPAIJ
250.227 +{ /* constraint coefficient */
250.228 + NPPROW *row;
250.229 + /* pointer to corresponding row */
250.230 + NPPCOL *col;
250.231 + /* pointer to corresponding column */
250.232 + double val;
250.233 + /* (non-zero) coefficient value */
250.234 + NPPAIJ *r_prev;
250.235 + /* pointer to previous coefficient in the same row */
250.236 + NPPAIJ *r_next;
250.237 + /* pointer to next coefficient in the same row */
250.238 + NPPAIJ *c_prev;
250.239 + /* pointer to previous coefficient in the same column */
250.240 + NPPAIJ *c_next;
250.241 + /* pointer to next coefficient in the same column */
250.242 +};
250.243 +
250.244 +struct NPPTSE
250.245 +{ /* transformation stack entry */
250.246 + int (*func)(NPP *npp, void *info);
250.247 + /* pointer to routine performing back transformation */
250.248 + void *info;
250.249 + /* pointer to specific info (depends on the transformation) */
250.250 + NPPTSE *link;
250.251 + /* pointer to another entry created *before* this entry */
250.252 +};
250.253 +
250.254 +struct NPPLFE
250.255 +{ /* linear form element */
250.256 + int ref;
250.257 + /* row/column reference number */
250.258 + double val;
250.259 + /* (non-zero) coefficient value */
250.260 + NPPLFE *next;
250.261 + /* pointer to another element */
250.262 +};
250.263 +
250.264 +#define npp_create_wksp _glp_npp_create_wksp
250.265 +NPP *npp_create_wksp(void);
250.266 +/* create LP/MIP preprocessor workspace */
250.267 +
250.268 +#define npp_insert_row _glp_npp_insert_row
250.269 +void npp_insert_row(NPP *npp, NPPROW *row, int where);
250.270 +/* insert row to the row list */
250.271 +
250.272 +#define npp_remove_row _glp_npp_remove_row
250.273 +void npp_remove_row(NPP *npp, NPPROW *row);
250.274 +/* remove row from the row list */
250.275 +
250.276 +#define npp_activate_row _glp_npp_activate_row
250.277 +void npp_activate_row(NPP *npp, NPPROW *row);
250.278 +/* make row active */
250.279 +
250.280 +#define npp_deactivate_row _glp_npp_deactivate_row
250.281 +void npp_deactivate_row(NPP *npp, NPPROW *row);
250.282 +/* make row inactive */
250.283 +
250.284 +#define npp_insert_col _glp_npp_insert_col
250.285 +void npp_insert_col(NPP *npp, NPPCOL *col, int where);
250.286 +/* insert column to the column list */
250.287 +
250.288 +#define npp_remove_col _glp_npp_remove_col
250.289 +void npp_remove_col(NPP *npp, NPPCOL *col);
250.290 +/* remove column from the column list */
250.291 +
250.292 +#define npp_activate_col _glp_npp_activate_col
250.293 +void npp_activate_col(NPP *npp, NPPCOL *col);
250.294 +/* make column active */
250.295 +
250.296 +#define npp_deactivate_col _glp_npp_deactivate_col
250.297 +void npp_deactivate_col(NPP *npp, NPPCOL *col);
250.298 +/* make column inactive */
250.299 +
250.300 +#define npp_add_row _glp_npp_add_row
250.301 +NPPROW *npp_add_row(NPP *npp);
250.302 +/* add new row to the current problem */
250.303 +
250.304 +#define npp_add_col _glp_npp_add_col
250.305 +NPPCOL *npp_add_col(NPP *npp);
250.306 +/* add new column to the current problem */
250.307 +
250.308 +#define npp_add_aij _glp_npp_add_aij
250.309 +NPPAIJ *npp_add_aij(NPP *npp, NPPROW *row, NPPCOL *col, double val);
250.310 +/* add new element to the constraint matrix */
250.311 +
250.312 +#define npp_row_nnz _glp_npp_row_nnz
250.313 +int npp_row_nnz(NPP *npp, NPPROW *row);
250.314 +/* count number of non-zero coefficients in row */
250.315 +
250.316 +#define npp_col_nnz _glp_npp_col_nnz
250.317 +int npp_col_nnz(NPP *npp, NPPCOL *col);
250.318 +/* count number of non-zero coefficients in column */
250.319 +
250.320 +#define npp_push_tse _glp_npp_push_tse
250.321 +void *npp_push_tse(NPP *npp, int (*func)(NPP *npp, void *info),
250.322 + int size);
250.323 +/* push new entry to the transformation stack */
250.324 +
250.325 +#define npp_erase_row _glp_npp_erase_row
250.326 +void npp_erase_row(NPP *npp, NPPROW *row);
250.327 +/* erase row content to make it empty */
250.328 +
250.329 +#define npp_del_row _glp_npp_del_row
250.330 +void npp_del_row(NPP *npp, NPPROW *row);
250.331 +/* remove row from the current problem */
250.332 +
250.333 +#define npp_del_col _glp_npp_del_col
250.334 +void npp_del_col(NPP *npp, NPPCOL *col);
250.335 +/* remove column from the current problem */
250.336 +
250.337 +#define npp_del_aij _glp_npp_del_aij
250.338 +void npp_del_aij(NPP *npp, NPPAIJ *aij);
250.339 +/* remove element from the constraint matrix */
250.340 +
250.341 +#define npp_load_prob _glp_npp_load_prob
250.342 +void npp_load_prob(NPP *npp, glp_prob *orig, int names, int sol,
250.343 + int scaling);
250.344 +/* load original problem into the preprocessor workspace */
250.345 +
250.346 +#define npp_build_prob _glp_npp_build_prob
250.347 +void npp_build_prob(NPP *npp, glp_prob *prob);
250.348 +/* build resultant (preprocessed) problem */
250.349 +
250.350 +#define npp_postprocess _glp_npp_postprocess
250.351 +void npp_postprocess(NPP *npp, glp_prob *prob);
250.352 +/* postprocess solution from the resultant problem */
250.353 +
250.354 +#define npp_unload_sol _glp_npp_unload_sol
250.355 +void npp_unload_sol(NPP *npp, glp_prob *orig);
250.356 +/* store solution to the original problem */
250.357 +
250.358 +#define npp_delete_wksp _glp_npp_delete_wksp
250.359 +void npp_delete_wksp(NPP *npp);
250.360 +/* delete LP/MIP preprocessor workspace */
250.361 +
250.362 +#define npp_error()
250.363 +
250.364 +#define npp_free_row _glp_npp_free_row
250.365 +void npp_free_row(NPP *npp, NPPROW *p);
250.366 +/* process free (unbounded) row */
250.367 +
250.368 +#define npp_geq_row _glp_npp_geq_row
250.369 +void npp_geq_row(NPP *npp, NPPROW *p);
250.370 +/* process row of 'not less than' type */
250.371 +
250.372 +#define npp_leq_row _glp_npp_leq_row
250.373 +void npp_leq_row(NPP *npp, NPPROW *p);
250.374 +/* process row of 'not greater than' type */
250.375 +
250.376 +#define npp_free_col _glp_npp_free_col
250.377 +void npp_free_col(NPP *npp, NPPCOL *q);
250.378 +/* process free (unbounded) column */
250.379 +
250.380 +#define npp_lbnd_col _glp_npp_lbnd_col
250.381 +void npp_lbnd_col(NPP *npp, NPPCOL *q);
250.382 +/* process column with (non-zero) lower bound */
250.383 +
250.384 +#define npp_ubnd_col _glp_npp_ubnd_col
250.385 +void npp_ubnd_col(NPP *npp, NPPCOL *q);
250.386 +/* process column with upper bound */
250.387 +
250.388 +#define npp_dbnd_col _glp_npp_dbnd_col
250.389 +void npp_dbnd_col(NPP *npp, NPPCOL *q);
250.390 +/* process non-negative column with upper bound */
250.391 +
250.392 +#define npp_fixed_col _glp_npp_fixed_col
250.393 +void npp_fixed_col(NPP *npp, NPPCOL *q);
250.394 +/* process fixed column */
250.395 +
250.396 +#define npp_make_equality _glp_npp_make_equality
250.397 +int npp_make_equality(NPP *npp, NPPROW *p);
250.398 +/* process row with almost identical bounds */
250.399 +
250.400 +#define npp_make_fixed _glp_npp_make_fixed
250.401 +int npp_make_fixed(NPP *npp, NPPCOL *q);
250.402 +/* process column with almost identical bounds */
250.403 +
250.404 +#define npp_empty_row _glp_npp_empty_row
250.405 +int npp_empty_row(NPP *npp, NPPROW *p);
250.406 +/* process empty row */
250.407 +
250.408 +#define npp_empty_col _glp_npp_empty_col
250.409 +int npp_empty_col(NPP *npp, NPPCOL *q);
250.410 +/* process empty column */
250.411 +
250.412 +#define npp_implied_value _glp_npp_implied_value
250.413 +int npp_implied_value(NPP *npp, NPPCOL *q, double s);
250.414 +/* process implied column value */
250.415 +
250.416 +#define npp_eq_singlet _glp_npp_eq_singlet
250.417 +int npp_eq_singlet(NPP *npp, NPPROW *p);
250.418 +/* process row singleton (equality constraint) */
250.419 +
250.420 +#define npp_implied_lower _glp_npp_implied_lower
250.421 +int npp_implied_lower(NPP *npp, NPPCOL *q, double l);
250.422 +/* process implied column lower bound */
250.423 +
250.424 +#define npp_implied_upper _glp_npp_implied_upper
250.425 +int npp_implied_upper(NPP *npp, NPPCOL *q, double u);
250.426 +/* process implied upper bound of column */
250.427 +
250.428 +#define npp_ineq_singlet _glp_npp_ineq_singlet
250.429 +int npp_ineq_singlet(NPP *npp, NPPROW *p);
250.430 +/* process row singleton (inequality constraint) */
250.431 +
250.432 +#define npp_implied_slack _glp_npp_implied_slack
250.433 +void npp_implied_slack(NPP *npp, NPPCOL *q);
250.434 +/* process column singleton (implied slack variable) */
250.435 +
250.436 +#define npp_implied_free _glp_npp_implied_free
250.437 +int npp_implied_free(NPP *npp, NPPCOL *q);
250.438 +/* process column singleton (implied free variable) */
250.439 +
250.440 +#define npp_eq_doublet _glp_npp_eq_doublet
250.441 +NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p);
250.442 +/* process row doubleton (equality constraint) */
250.443 +
250.444 +#define npp_forcing_row _glp_npp_forcing_row
250.445 +int npp_forcing_row(NPP *npp, NPPROW *p, int at);
250.446 +/* process forcing row */
250.447 +
250.448 +#define npp_analyze_row _glp_npp_analyze_row
250.449 +int npp_analyze_row(NPP *npp, NPPROW *p);
250.450 +/* perform general row analysis */
250.451 +
250.452 +#define npp_inactive_bound _glp_npp_inactive_bound
250.453 +void npp_inactive_bound(NPP *npp, NPPROW *p, int which);
250.454 +/* remove row lower/upper inactive bound */
250.455 +
250.456 +#define npp_implied_bounds _glp_npp_implied_bounds
250.457 +void npp_implied_bounds(NPP *npp, NPPROW *p);
250.458 +/* determine implied column bounds */
250.459 +
250.460 +#define npp_binarize_prob _glp_npp_binarize_prob
250.461 +int npp_binarize_prob(NPP *npp);
250.462 +/* binarize MIP problem */
250.463 +
250.464 +#define npp_is_packing _glp_npp_is_packing
250.465 +int npp_is_packing(NPP *npp, NPPROW *row);
250.466 +/* test if constraint is packing inequality */
250.467 +
250.468 +#define npp_hidden_packing _glp_npp_hidden_packing
250.469 +int npp_hidden_packing(NPP *npp, NPPROW *row);
250.470 +/* identify hidden packing inequality */
250.471 +
250.472 +#define npp_implied_packing _glp_npp_implied_packing
250.473 +int npp_implied_packing(NPP *npp, NPPROW *row, int which,
250.474 + NPPCOL *var[], char set[]);
250.475 +/* identify implied packing inequality */
250.476 +
250.477 +#define npp_is_covering _glp_npp_is_covering
250.478 +int npp_is_covering(NPP *npp, NPPROW *row);
250.479 +/* test if constraint is covering inequality */
250.480 +
250.481 +#define npp_hidden_covering _glp_npp_hidden_covering
250.482 +int npp_hidden_covering(NPP *npp, NPPROW *row);
250.483 +/* identify hidden covering inequality */
250.484 +
250.485 +#define npp_is_partitioning _glp_npp_is_partitioning
250.486 +int npp_is_partitioning(NPP *npp, NPPROW *row);
250.487 +/* test if constraint is partitioning equality */
250.488 +
250.489 +#define npp_reduce_ineq_coef _glp_npp_reduce_ineq_coef
250.490 +int npp_reduce_ineq_coef(NPP *npp, NPPROW *row);
250.491 +/* reduce inequality constraint coefficients */
250.492 +
250.493 +#define npp_clean_prob _glp_npp_clean_prob
250.494 +void npp_clean_prob(NPP *npp);
250.495 +/* perform initial LP/MIP processing */
250.496 +
250.497 +#define npp_process_row _glp_npp_process_row
250.498 +int npp_process_row(NPP *npp, NPPROW *row, int hard);
250.499 +/* perform basic row processing */
250.500 +
250.501 +#define npp_improve_bounds _glp_npp_improve_bounds
250.502 +int npp_improve_bounds(NPP *npp, NPPROW *row, int flag);
250.503 +/* improve current column bounds */
250.504 +
250.505 +#define npp_process_col _glp_npp_process_col
250.506 +int npp_process_col(NPP *npp, NPPCOL *col);
250.507 +/* perform basic column processing */
250.508 +
250.509 +#define npp_process_prob _glp_npp_process_prob
250.510 +int npp_process_prob(NPP *npp, int hard);
250.511 +/* perform basic LP/MIP processing */
250.512 +
250.513 +#define npp_simplex _glp_npp_simplex
250.514 +int npp_simplex(NPP *npp, const glp_smcp *parm);
250.515 +/* process LP prior to applying primal/dual simplex method */
250.516 +
250.517 +#define npp_integer _glp_npp_integer
250.518 +int npp_integer(NPP *npp, const glp_iocp *parm);
250.519 +/* process MIP prior to applying branch-and-bound method */
250.520 +
250.521 +#endif
250.522 +
250.523 +/* eof */
251.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
251.2 +++ b/src/glpnpp01.c Mon Dec 06 13:09:21 2010 +0100
251.3 @@ -0,0 +1,927 @@
251.4 +/* glpnpp01.c */
251.5 +
251.6 +/***********************************************************************
251.7 +* This code is part of GLPK (GNU Linear Programming Kit).
251.8 +*
251.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
251.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
251.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
251.12 +* E-mail: <mao@gnu.org>.
251.13 +*
251.14 +* GLPK is free software: you can redistribute it and/or modify it
251.15 +* under the terms of the GNU General Public License as published by
251.16 +* the Free Software Foundation, either version 3 of the License, or
251.17 +* (at your option) any later version.
251.18 +*
251.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
251.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
251.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
251.22 +* License for more details.
251.23 +*
251.24 +* You should have received a copy of the GNU General Public License
251.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
251.26 +***********************************************************************/
251.27 +
251.28 +#include "glpnpp.h"
251.29 +
251.30 +NPP *npp_create_wksp(void)
251.31 +{ /* create LP/MIP preprocessor workspace */
251.32 + NPP *npp;
251.33 + npp = xmalloc(sizeof(NPP));
251.34 + npp->orig_dir = 0;
251.35 + npp->orig_m = npp->orig_n = npp->orig_nnz = 0;
251.36 + npp->pool = dmp_create_pool();
251.37 + npp->name = npp->obj = NULL;
251.38 + npp->c0 = 0.0;
251.39 + npp->nrows = npp->ncols = 0;
251.40 + npp->r_head = npp->r_tail = NULL;
251.41 + npp->c_head = npp->c_tail = NULL;
251.42 + npp->stack = dmp_create_pool();
251.43 + npp->top = NULL;
251.44 +#if 0 /* 16/XII-2009 */
251.45 + memset(&npp->count, 0, sizeof(npp->count));
251.46 +#endif
251.47 + npp->m = npp->n = npp->nnz = 0;
251.48 + npp->row_ref = npp->col_ref = NULL;
251.49 + npp->sol = npp->scaling = 0;
251.50 + npp->p_stat = npp->d_stat = npp->t_stat = npp->i_stat = 0;
251.51 + npp->r_stat = NULL;
251.52 + /*npp->r_prim =*/ npp->r_pi = NULL;
251.53 + npp->c_stat = NULL;
251.54 + npp->c_value = /*npp->c_dual =*/ NULL;
251.55 + return npp;
251.56 +}
251.57 +
251.58 +void npp_insert_row(NPP *npp, NPPROW *row, int where)
251.59 +{ /* insert row to the row list */
251.60 + if (where == 0)
251.61 + { /* insert row to the beginning of the row list */
251.62 + row->prev = NULL;
251.63 + row->next = npp->r_head;
251.64 + if (row->next == NULL)
251.65 + npp->r_tail = row;
251.66 + else
251.67 + row->next->prev = row;
251.68 + npp->r_head = row;
251.69 + }
251.70 + else
251.71 + { /* insert row to the end of the row list */
251.72 + row->prev = npp->r_tail;
251.73 + row->next = NULL;
251.74 + if (row->prev == NULL)
251.75 + npp->r_head = row;
251.76 + else
251.77 + row->prev->next = row;
251.78 + npp->r_tail = row;
251.79 + }
251.80 + return;
251.81 +}
251.82 +
251.83 +void npp_remove_row(NPP *npp, NPPROW *row)
251.84 +{ /* remove row from the row list */
251.85 + if (row->prev == NULL)
251.86 + npp->r_head = row->next;
251.87 + else
251.88 + row->prev->next = row->next;
251.89 + if (row->next == NULL)
251.90 + npp->r_tail = row->prev;
251.91 + else
251.92 + row->next->prev = row->prev;
251.93 + return;
251.94 +}
251.95 +
251.96 +void npp_activate_row(NPP *npp, NPPROW *row)
251.97 +{ /* make row active */
251.98 + if (!row->temp)
251.99 + { row->temp = 1;
251.100 + /* move the row to the beginning of the row list */
251.101 + npp_remove_row(npp, row);
251.102 + npp_insert_row(npp, row, 0);
251.103 + }
251.104 + return;
251.105 +}
251.106 +
251.107 +void npp_deactivate_row(NPP *npp, NPPROW *row)
251.108 +{ /* make row inactive */
251.109 + if (row->temp)
251.110 + { row->temp = 0;
251.111 + /* move the row to the end of the row list */
251.112 + npp_remove_row(npp, row);
251.113 + npp_insert_row(npp, row, 1);
251.114 + }
251.115 + return;
251.116 +}
251.117 +
251.118 +void npp_insert_col(NPP *npp, NPPCOL *col, int where)
251.119 +{ /* insert column to the column list */
251.120 + if (where == 0)
251.121 + { /* insert column to the beginning of the column list */
251.122 + col->prev = NULL;
251.123 + col->next = npp->c_head;
251.124 + if (col->next == NULL)
251.125 + npp->c_tail = col;
251.126 + else
251.127 + col->next->prev = col;
251.128 + npp->c_head = col;
251.129 + }
251.130 + else
251.131 + { /* insert column to the end of the column list */
251.132 + col->prev = npp->c_tail;
251.133 + col->next = NULL;
251.134 + if (col->prev == NULL)
251.135 + npp->c_head = col;
251.136 + else
251.137 + col->prev->next = col;
251.138 + npp->c_tail = col;
251.139 + }
251.140 + return;
251.141 +}
251.142 +
251.143 +void npp_remove_col(NPP *npp, NPPCOL *col)
251.144 +{ /* remove column from the column list */
251.145 + if (col->prev == NULL)
251.146 + npp->c_head = col->next;
251.147 + else
251.148 + col->prev->next = col->next;
251.149 + if (col->next == NULL)
251.150 + npp->c_tail = col->prev;
251.151 + else
251.152 + col->next->prev = col->prev;
251.153 + return;
251.154 +}
251.155 +
251.156 +void npp_activate_col(NPP *npp, NPPCOL *col)
251.157 +{ /* make column active */
251.158 + if (!col->temp)
251.159 + { col->temp = 1;
251.160 + /* move the column to the beginning of the column list */
251.161 + npp_remove_col(npp, col);
251.162 + npp_insert_col(npp, col, 0);
251.163 + }
251.164 + return;
251.165 +}
251.166 +
251.167 +void npp_deactivate_col(NPP *npp, NPPCOL *col)
251.168 +{ /* make column inactive */
251.169 + if (col->temp)
251.170 + { col->temp = 0;
251.171 + /* move the column to the end of the column list */
251.172 + npp_remove_col(npp, col);
251.173 + npp_insert_col(npp, col, 1);
251.174 + }
251.175 + return;
251.176 +}
251.177 +
251.178 +NPPROW *npp_add_row(NPP *npp)
251.179 +{ /* add new row to the current problem */
251.180 + NPPROW *row;
251.181 + row = dmp_get_atom(npp->pool, sizeof(NPPROW));
251.182 + row->i = ++(npp->nrows);
251.183 + row->name = NULL;
251.184 + row->lb = -DBL_MAX, row->ub = +DBL_MAX;
251.185 + row->ptr = NULL;
251.186 + row->temp = 0;
251.187 + npp_insert_row(npp, row, 1);
251.188 + return row;
251.189 +}
251.190 +
251.191 +NPPCOL *npp_add_col(NPP *npp)
251.192 +{ /* add new column to the current problem */
251.193 + NPPCOL *col;
251.194 + col = dmp_get_atom(npp->pool, sizeof(NPPCOL));
251.195 + col->j = ++(npp->ncols);
251.196 + col->name = NULL;
251.197 +#if 0
251.198 + col->kind = GLP_CV;
251.199 +#else
251.200 + col->is_int = 0;
251.201 +#endif
251.202 + col->lb = col->ub = col->coef = 0.0;
251.203 + col->ptr = NULL;
251.204 + col->temp = 0;
251.205 + npp_insert_col(npp, col, 1);
251.206 + return col;
251.207 +}
251.208 +
251.209 +NPPAIJ *npp_add_aij(NPP *npp, NPPROW *row, NPPCOL *col, double val)
251.210 +{ /* add new element to the constraint matrix */
251.211 + NPPAIJ *aij;
251.212 + aij = dmp_get_atom(npp->pool, sizeof(NPPAIJ));
251.213 + aij->row = row;
251.214 + aij->col = col;
251.215 + aij->val = val;
251.216 + aij->r_prev = NULL;
251.217 + aij->r_next = row->ptr;
251.218 + aij->c_prev = NULL;
251.219 + aij->c_next = col->ptr;
251.220 + if (aij->r_next != NULL)
251.221 + aij->r_next->r_prev = aij;
251.222 + if (aij->c_next != NULL)
251.223 + aij->c_next->c_prev = aij;
251.224 + row->ptr = col->ptr = aij;
251.225 + return aij;
251.226 +}
251.227 +
251.228 +int npp_row_nnz(NPP *npp, NPPROW *row)
251.229 +{ /* count number of non-zero coefficients in row */
251.230 + NPPAIJ *aij;
251.231 + int nnz;
251.232 + xassert(npp == npp);
251.233 + nnz = 0;
251.234 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
251.235 + nnz++;
251.236 + return nnz;
251.237 +}
251.238 +
251.239 +int npp_col_nnz(NPP *npp, NPPCOL *col)
251.240 +{ /* count number of non-zero coefficients in column */
251.241 + NPPAIJ *aij;
251.242 + int nnz;
251.243 + xassert(npp == npp);
251.244 + nnz = 0;
251.245 + for (aij = col->ptr; aij != NULL; aij = aij->c_next)
251.246 + nnz++;
251.247 + return nnz;
251.248 +}
251.249 +
251.250 +void *npp_push_tse(NPP *npp, int (*func)(NPP *npp, void *info),
251.251 + int size)
251.252 +{ /* push new entry to the transformation stack */
251.253 + NPPTSE *tse;
251.254 + tse = dmp_get_atom(npp->stack, sizeof(NPPTSE));
251.255 + tse->func = func;
251.256 + tse->info = dmp_get_atom(npp->stack, size);
251.257 + tse->link = npp->top;
251.258 + npp->top = tse;
251.259 + return tse->info;
251.260 +}
251.261 +
251.262 +#if 1 /* 23/XII-2009 */
251.263 +void npp_erase_row(NPP *npp, NPPROW *row)
251.264 +{ /* erase row content to make it empty */
251.265 + NPPAIJ *aij;
251.266 + while (row->ptr != NULL)
251.267 + { aij = row->ptr;
251.268 + row->ptr = aij->r_next;
251.269 + if (aij->c_prev == NULL)
251.270 + aij->col->ptr = aij->c_next;
251.271 + else
251.272 + aij->c_prev->c_next = aij->c_next;
251.273 + if (aij->c_next == NULL)
251.274 + ;
251.275 + else
251.276 + aij->c_next->c_prev = aij->c_prev;
251.277 + dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
251.278 + }
251.279 + return;
251.280 +}
251.281 +#endif
251.282 +
251.283 +void npp_del_row(NPP *npp, NPPROW *row)
251.284 +{ /* remove row from the current problem */
251.285 +#if 0 /* 23/XII-2009 */
251.286 + NPPAIJ *aij;
251.287 +#endif
251.288 + if (row->name != NULL)
251.289 + dmp_free_atom(npp->pool, row->name, strlen(row->name)+1);
251.290 +#if 0 /* 23/XII-2009 */
251.291 + while (row->ptr != NULL)
251.292 + { aij = row->ptr;
251.293 + row->ptr = aij->r_next;
251.294 + if (aij->c_prev == NULL)
251.295 + aij->col->ptr = aij->c_next;
251.296 + else
251.297 + aij->c_prev->c_next = aij->c_next;
251.298 + if (aij->c_next == NULL)
251.299 + ;
251.300 + else
251.301 + aij->c_next->c_prev = aij->c_prev;
251.302 + dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
251.303 + }
251.304 +#else
251.305 + npp_erase_row(npp, row);
251.306 +#endif
251.307 + npp_remove_row(npp, row);
251.308 + dmp_free_atom(npp->pool, row, sizeof(NPPROW));
251.309 + return;
251.310 +}
251.311 +
251.312 +void npp_del_col(NPP *npp, NPPCOL *col)
251.313 +{ /* remove column from the current problem */
251.314 + NPPAIJ *aij;
251.315 + if (col->name != NULL)
251.316 + dmp_free_atom(npp->pool, col->name, strlen(col->name)+1);
251.317 + while (col->ptr != NULL)
251.318 + { aij = col->ptr;
251.319 + col->ptr = aij->c_next;
251.320 + if (aij->r_prev == NULL)
251.321 + aij->row->ptr = aij->r_next;
251.322 + else
251.323 + aij->r_prev->r_next = aij->r_next;
251.324 + if (aij->r_next == NULL)
251.325 + ;
251.326 + else
251.327 + aij->r_next->r_prev = aij->r_prev;
251.328 + dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
251.329 + }
251.330 + npp_remove_col(npp, col);
251.331 + dmp_free_atom(npp->pool, col, sizeof(NPPCOL));
251.332 + return;
251.333 +}
251.334 +
251.335 +void npp_del_aij(NPP *npp, NPPAIJ *aij)
251.336 +{ /* remove element from the constraint matrix */
251.337 + if (aij->r_prev == NULL)
251.338 + aij->row->ptr = aij->r_next;
251.339 + else
251.340 + aij->r_prev->r_next = aij->r_next;
251.341 + if (aij->r_next == NULL)
251.342 + ;
251.343 + else
251.344 + aij->r_next->r_prev = aij->r_prev;
251.345 + if (aij->c_prev == NULL)
251.346 + aij->col->ptr = aij->c_next;
251.347 + else
251.348 + aij->c_prev->c_next = aij->c_next;
251.349 + if (aij->c_next == NULL)
251.350 + ;
251.351 + else
251.352 + aij->c_next->c_prev = aij->c_prev;
251.353 + dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
251.354 + return;
251.355 +}
251.356 +
251.357 +void npp_load_prob(NPP *npp, glp_prob *orig, int names, int sol,
251.358 + int scaling)
251.359 +{ /* load original problem into the preprocessor workspace */
251.360 + int m = orig->m;
251.361 + int n = orig->n;
251.362 + NPPROW **link;
251.363 + int i, j;
251.364 + double dir;
251.365 + xassert(names == GLP_OFF || names == GLP_ON);
251.366 + xassert(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP);
251.367 + xassert(scaling == GLP_OFF || scaling == GLP_ON);
251.368 + if (sol == GLP_MIP) xassert(!scaling);
251.369 + npp->orig_dir = orig->dir;
251.370 + if (npp->orig_dir == GLP_MIN)
251.371 + dir = +1.0;
251.372 + else if (npp->orig_dir == GLP_MAX)
251.373 + dir = -1.0;
251.374 + else
251.375 + xassert(npp != npp);
251.376 + npp->orig_m = m;
251.377 + npp->orig_n = n;
251.378 + npp->orig_nnz = orig->nnz;
251.379 + if (names && orig->name != NULL)
251.380 + { npp->name = dmp_get_atom(npp->pool, strlen(orig->name)+1);
251.381 + strcpy(npp->name, orig->name);
251.382 + }
251.383 + if (names && orig->obj != NULL)
251.384 + { npp->obj = dmp_get_atom(npp->pool, strlen(orig->obj)+1);
251.385 + strcpy(npp->obj, orig->obj);
251.386 + }
251.387 + npp->c0 = dir * orig->c0;
251.388 + /* load rows */
251.389 + link = xcalloc(1+m, sizeof(NPPROW *));
251.390 + for (i = 1; i <= m; i++)
251.391 + { GLPROW *rrr = orig->row[i];
251.392 + NPPROW *row;
251.393 + link[i] = row = npp_add_row(npp);
251.394 + xassert(row->i == i);
251.395 + if (names && rrr->name != NULL)
251.396 + { row->name = dmp_get_atom(npp->pool, strlen(rrr->name)+1);
251.397 + strcpy(row->name, rrr->name);
251.398 + }
251.399 + if (!scaling)
251.400 + { if (rrr->type == GLP_FR)
251.401 + row->lb = -DBL_MAX, row->ub = +DBL_MAX;
251.402 + else if (rrr->type == GLP_LO)
251.403 + row->lb = rrr->lb, row->ub = +DBL_MAX;
251.404 + else if (rrr->type == GLP_UP)
251.405 + row->lb = -DBL_MAX, row->ub = rrr->ub;
251.406 + else if (rrr->type == GLP_DB)
251.407 + row->lb = rrr->lb, row->ub = rrr->ub;
251.408 + else if (rrr->type == GLP_FX)
251.409 + row->lb = row->ub = rrr->lb;
251.410 + else
251.411 + xassert(rrr != rrr);
251.412 + }
251.413 + else
251.414 + { double rii = rrr->rii;
251.415 + if (rrr->type == GLP_FR)
251.416 + row->lb = -DBL_MAX, row->ub = +DBL_MAX;
251.417 + else if (rrr->type == GLP_LO)
251.418 + row->lb = rrr->lb * rii, row->ub = +DBL_MAX;
251.419 + else if (rrr->type == GLP_UP)
251.420 + row->lb = -DBL_MAX, row->ub = rrr->ub * rii;
251.421 + else if (rrr->type == GLP_DB)
251.422 + row->lb = rrr->lb * rii, row->ub = rrr->ub * rii;
251.423 + else if (rrr->type == GLP_FX)
251.424 + row->lb = row->ub = rrr->lb * rii;
251.425 + else
251.426 + xassert(rrr != rrr);
251.427 + }
251.428 + }
251.429 + /* load columns and constraint coefficients */
251.430 + for (j = 1; j <= n; j++)
251.431 + { GLPCOL *ccc = orig->col[j];
251.432 + GLPAIJ *aaa;
251.433 + NPPCOL *col;
251.434 + col = npp_add_col(npp);
251.435 + xassert(col->j == j);
251.436 + if (names && ccc->name != NULL)
251.437 + { col->name = dmp_get_atom(npp->pool, strlen(ccc->name)+1);
251.438 + strcpy(col->name, ccc->name);
251.439 + }
251.440 + if (sol == GLP_MIP)
251.441 +#if 0
251.442 + col->kind = ccc->kind;
251.443 +#else
251.444 + col->is_int = (char)(ccc->kind == GLP_IV);
251.445 +#endif
251.446 + if (!scaling)
251.447 + { if (ccc->type == GLP_FR)
251.448 + col->lb = -DBL_MAX, col->ub = +DBL_MAX;
251.449 + else if (ccc->type == GLP_LO)
251.450 + col->lb = ccc->lb, col->ub = +DBL_MAX;
251.451 + else if (ccc->type == GLP_UP)
251.452 + col->lb = -DBL_MAX, col->ub = ccc->ub;
251.453 + else if (ccc->type == GLP_DB)
251.454 + col->lb = ccc->lb, col->ub = ccc->ub;
251.455 + else if (ccc->type == GLP_FX)
251.456 + col->lb = col->ub = ccc->lb;
251.457 + else
251.458 + xassert(ccc != ccc);
251.459 + col->coef = dir * ccc->coef;
251.460 + for (aaa = ccc->ptr; aaa != NULL; aaa = aaa->c_next)
251.461 + npp_add_aij(npp, link[aaa->row->i], col, aaa->val);
251.462 + }
251.463 + else
251.464 + { double sjj = ccc->sjj;
251.465 + if (ccc->type == GLP_FR)
251.466 + col->lb = -DBL_MAX, col->ub = +DBL_MAX;
251.467 + else if (ccc->type == GLP_LO)
251.468 + col->lb = ccc->lb / sjj, col->ub = +DBL_MAX;
251.469 + else if (ccc->type == GLP_UP)
251.470 + col->lb = -DBL_MAX, col->ub = ccc->ub / sjj;
251.471 + else if (ccc->type == GLP_DB)
251.472 + col->lb = ccc->lb / sjj, col->ub = ccc->ub / sjj;
251.473 + else if (ccc->type == GLP_FX)
251.474 + col->lb = col->ub = ccc->lb / sjj;
251.475 + else
251.476 + xassert(ccc != ccc);
251.477 + col->coef = dir * ccc->coef * sjj;
251.478 + for (aaa = ccc->ptr; aaa != NULL; aaa = aaa->c_next)
251.479 + npp_add_aij(npp, link[aaa->row->i], col,
251.480 + aaa->row->rii * aaa->val * sjj);
251.481 + }
251.482 + }
251.483 + xfree(link);
251.484 + /* keep solution indicator and scaling option */
251.485 + npp->sol = sol;
251.486 + npp->scaling = scaling;
251.487 + return;
251.488 +}
251.489 +
251.490 +void npp_build_prob(NPP *npp, glp_prob *prob)
251.491 +{ /* build resultant (preprocessed) problem */
251.492 + NPPROW *row;
251.493 + NPPCOL *col;
251.494 + NPPAIJ *aij;
251.495 + int i, j, type, len, *ind;
251.496 + double dir, *val;
251.497 + glp_erase_prob(prob);
251.498 + glp_set_prob_name(prob, npp->name);
251.499 + glp_set_obj_name(prob, npp->obj);
251.500 + glp_set_obj_dir(prob, npp->orig_dir);
251.501 + if (npp->orig_dir == GLP_MIN)
251.502 + dir = +1.0;
251.503 + else if (npp->orig_dir == GLP_MAX)
251.504 + dir = -1.0;
251.505 + else
251.506 + xassert(npp != npp);
251.507 + glp_set_obj_coef(prob, 0, dir * npp->c0);
251.508 + /* build rows */
251.509 + for (row = npp->r_head; row != NULL; row = row->next)
251.510 + { row->temp = i = glp_add_rows(prob, 1);
251.511 + glp_set_row_name(prob, i, row->name);
251.512 + if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
251.513 + type = GLP_FR;
251.514 + else if (row->ub == +DBL_MAX)
251.515 + type = GLP_LO;
251.516 + else if (row->lb == -DBL_MAX)
251.517 + type = GLP_UP;
251.518 + else if (row->lb != row->ub)
251.519 + type = GLP_DB;
251.520 + else
251.521 + type = GLP_FX;
251.522 + glp_set_row_bnds(prob, i, type, row->lb, row->ub);
251.523 + }
251.524 + /* build columns and the constraint matrix */
251.525 + ind = xcalloc(1+prob->m, sizeof(int));
251.526 + val = xcalloc(1+prob->m, sizeof(double));
251.527 + for (col = npp->c_head; col != NULL; col = col->next)
251.528 + { j = glp_add_cols(prob, 1);
251.529 + glp_set_col_name(prob, j, col->name);
251.530 +#if 0
251.531 + glp_set_col_kind(prob, j, col->kind);
251.532 +#else
251.533 + glp_set_col_kind(prob, j, col->is_int ? GLP_IV : GLP_CV);
251.534 +#endif
251.535 + if (col->lb == -DBL_MAX && col->ub == +DBL_MAX)
251.536 + type = GLP_FR;
251.537 + else if (col->ub == +DBL_MAX)
251.538 + type = GLP_LO;
251.539 + else if (col->lb == -DBL_MAX)
251.540 + type = GLP_UP;
251.541 + else if (col->lb != col->ub)
251.542 + type = GLP_DB;
251.543 + else
251.544 + type = GLP_FX;
251.545 + glp_set_col_bnds(prob, j, type, col->lb, col->ub);
251.546 + glp_set_obj_coef(prob, j, dir * col->coef);
251.547 + len = 0;
251.548 + for (aij = col->ptr; aij != NULL; aij = aij->c_next)
251.549 + { len++;
251.550 + ind[len] = aij->row->temp;
251.551 + val[len] = aij->val;
251.552 + }
251.553 + glp_set_mat_col(prob, j, len, ind, val);
251.554 + }
251.555 + xfree(ind);
251.556 + xfree(val);
251.557 + /* resultant problem has been built */
251.558 + npp->m = prob->m;
251.559 + npp->n = prob->n;
251.560 + npp->nnz = prob->nnz;
251.561 + npp->row_ref = xcalloc(1+npp->m, sizeof(int));
251.562 + npp->col_ref = xcalloc(1+npp->n, sizeof(int));
251.563 + for (row = npp->r_head, i = 0; row != NULL; row = row->next)
251.564 + npp->row_ref[++i] = row->i;
251.565 + for (col = npp->c_head, j = 0; col != NULL; col = col->next)
251.566 + npp->col_ref[++j] = col->j;
251.567 + /* transformed problem segment is no longer needed */
251.568 + dmp_delete_pool(npp->pool), npp->pool = NULL;
251.569 + npp->name = npp->obj = NULL;
251.570 + npp->c0 = 0.0;
251.571 + npp->r_head = npp->r_tail = NULL;
251.572 + npp->c_head = npp->c_tail = NULL;
251.573 + return;
251.574 +}
251.575 +
251.576 +void npp_postprocess(NPP *npp, glp_prob *prob)
251.577 +{ /* postprocess solution from the resultant problem */
251.578 + GLPROW *row;
251.579 + GLPCOL *col;
251.580 + NPPTSE *tse;
251.581 + int i, j, k;
251.582 + double dir;
251.583 + xassert(npp->orig_dir == prob->dir);
251.584 + if (npp->orig_dir == GLP_MIN)
251.585 + dir = +1.0;
251.586 + else if (npp->orig_dir == GLP_MAX)
251.587 + dir = -1.0;
251.588 + else
251.589 + xassert(npp != npp);
251.590 + xassert(npp->m == prob->m);
251.591 + xassert(npp->n == prob->n);
251.592 + xassert(npp->nnz == prob->nnz);
251.593 + /* copy solution status */
251.594 + if (npp->sol == GLP_SOL)
251.595 + { npp->p_stat = prob->pbs_stat;
251.596 + npp->d_stat = prob->dbs_stat;
251.597 + }
251.598 + else if (npp->sol == GLP_IPT)
251.599 + npp->t_stat = prob->ipt_stat;
251.600 + else if (npp->sol == GLP_MIP)
251.601 + npp->i_stat = prob->mip_stat;
251.602 + else
251.603 + xassert(npp != npp);
251.604 + /* allocate solution arrays */
251.605 + if (npp->sol == GLP_SOL)
251.606 + { if (npp->r_stat == NULL)
251.607 + npp->r_stat = xcalloc(1+npp->nrows, sizeof(char));
251.608 + for (i = 1; i <= npp->nrows; i++)
251.609 + npp->r_stat[i] = 0;
251.610 + if (npp->c_stat == NULL)
251.611 + npp->c_stat = xcalloc(1+npp->ncols, sizeof(char));
251.612 + for (j = 1; j <= npp->ncols; j++)
251.613 + npp->c_stat[j] = 0;
251.614 + }
251.615 +#if 0
251.616 + if (npp->r_prim == NULL)
251.617 + npp->r_prim = xcalloc(1+npp->nrows, sizeof(double));
251.618 + for (i = 1; i <= npp->nrows; i++)
251.619 + npp->r_prim[i] = DBL_MAX;
251.620 +#endif
251.621 + if (npp->c_value == NULL)
251.622 + npp->c_value = xcalloc(1+npp->ncols, sizeof(double));
251.623 + for (j = 1; j <= npp->ncols; j++)
251.624 + npp->c_value[j] = DBL_MAX;
251.625 + if (npp->sol != GLP_MIP)
251.626 + { if (npp->r_pi == NULL)
251.627 + npp->r_pi = xcalloc(1+npp->nrows, sizeof(double));
251.628 + for (i = 1; i <= npp->nrows; i++)
251.629 + npp->r_pi[i] = DBL_MAX;
251.630 +#if 0
251.631 + if (npp->c_dual == NULL)
251.632 + npp->c_dual = xcalloc(1+npp->ncols, sizeof(double));
251.633 + for (j = 1; j <= npp->ncols; j++)
251.634 + npp->c_dual[j] = DBL_MAX;
251.635 +#endif
251.636 + }
251.637 + /* copy solution components from the resultant problem */
251.638 + if (npp->sol == GLP_SOL)
251.639 + { for (i = 1; i <= npp->m; i++)
251.640 + { row = prob->row[i];
251.641 + k = npp->row_ref[i];
251.642 + npp->r_stat[k] = (char)row->stat;
251.643 + /*npp->r_prim[k] = row->prim;*/
251.644 + npp->r_pi[k] = dir * row->dual;
251.645 + }
251.646 + for (j = 1; j <= npp->n; j++)
251.647 + { col = prob->col[j];
251.648 + k = npp->col_ref[j];
251.649 + npp->c_stat[k] = (char)col->stat;
251.650 + npp->c_value[k] = col->prim;
251.651 + /*npp->c_dual[k] = dir * col->dual;*/
251.652 + }
251.653 + }
251.654 + else if (npp->sol == GLP_IPT)
251.655 + { for (i = 1; i <= npp->m; i++)
251.656 + { row = prob->row[i];
251.657 + k = npp->row_ref[i];
251.658 + /*npp->r_prim[k] = row->pval;*/
251.659 + npp->r_pi[k] = dir * row->dval;
251.660 + }
251.661 + for (j = 1; j <= npp->n; j++)
251.662 + { col = prob->col[j];
251.663 + k = npp->col_ref[j];
251.664 + npp->c_value[k] = col->pval;
251.665 + /*npp->c_dual[k] = dir * col->dval;*/
251.666 + }
251.667 + }
251.668 + else if (npp->sol == GLP_MIP)
251.669 + {
251.670 +#if 0
251.671 + for (i = 1; i <= npp->m; i++)
251.672 + { row = prob->row[i];
251.673 + k = npp->row_ref[i];
251.674 + /*npp->r_prim[k] = row->mipx;*/
251.675 + }
251.676 +#endif
251.677 + for (j = 1; j <= npp->n; j++)
251.678 + { col = prob->col[j];
251.679 + k = npp->col_ref[j];
251.680 + npp->c_value[k] = col->mipx;
251.681 + }
251.682 + }
251.683 + else
251.684 + xassert(npp != npp);
251.685 + /* perform postprocessing to construct solution to the original
251.686 + problem */
251.687 + for (tse = npp->top; tse != NULL; tse = tse->link)
251.688 + { xassert(tse->func != NULL);
251.689 + xassert(tse->func(npp, tse->info) == 0);
251.690 + }
251.691 + return;
251.692 +}
251.693 +
251.694 +void npp_unload_sol(NPP *npp, glp_prob *orig)
251.695 +{ /* store solution to the original problem */
251.696 + GLPROW *row;
251.697 + GLPCOL *col;
251.698 + int i, j;
251.699 + double dir;
251.700 + xassert(npp->orig_dir == orig->dir);
251.701 + if (npp->orig_dir == GLP_MIN)
251.702 + dir = +1.0;
251.703 + else if (npp->orig_dir == GLP_MAX)
251.704 + dir = -1.0;
251.705 + else
251.706 + xassert(npp != npp);
251.707 + xassert(npp->orig_m == orig->m);
251.708 + xassert(npp->orig_n == orig->n);
251.709 + xassert(npp->orig_nnz == orig->nnz);
251.710 + if (npp->sol == GLP_SOL)
251.711 + { /* store basic solution */
251.712 + orig->valid = 0;
251.713 + orig->pbs_stat = npp->p_stat;
251.714 + orig->dbs_stat = npp->d_stat;
251.715 + orig->obj_val = orig->c0;
251.716 + orig->some = 0;
251.717 + for (i = 1; i <= orig->m; i++)
251.718 + { row = orig->row[i];
251.719 + row->stat = npp->r_stat[i];
251.720 + if (!npp->scaling)
251.721 + { /*row->prim = npp->r_prim[i];*/
251.722 + row->dual = dir * npp->r_pi[i];
251.723 + }
251.724 + else
251.725 + { /*row->prim = npp->r_prim[i] / row->rii;*/
251.726 + row->dual = dir * npp->r_pi[i] * row->rii;
251.727 + }
251.728 + if (row->stat == GLP_BS)
251.729 + row->dual = 0.0;
251.730 + else if (row->stat == GLP_NL)
251.731 + { xassert(row->type == GLP_LO || row->type == GLP_DB);
251.732 + row->prim = row->lb;
251.733 + }
251.734 + else if (row->stat == GLP_NU)
251.735 + { xassert(row->type == GLP_UP || row->type == GLP_DB);
251.736 + row->prim = row->ub;
251.737 + }
251.738 + else if (row->stat == GLP_NF)
251.739 + { xassert(row->type == GLP_FR);
251.740 + row->prim = 0.0;
251.741 + }
251.742 + else if (row->stat == GLP_NS)
251.743 + { xassert(row->type == GLP_FX);
251.744 + row->prim = row->lb;
251.745 + }
251.746 + else
251.747 + xassert(row != row);
251.748 + }
251.749 + for (j = 1; j <= orig->n; j++)
251.750 + { col = orig->col[j];
251.751 + col->stat = npp->c_stat[j];
251.752 + if (!npp->scaling)
251.753 + { col->prim = npp->c_value[j];
251.754 + /*col->dual = dir * npp->c_dual[j];*/
251.755 + }
251.756 + else
251.757 + { col->prim = npp->c_value[j] * col->sjj;
251.758 + /*col->dual = dir * npp->c_dual[j] / col->sjj;*/
251.759 + }
251.760 + if (col->stat == GLP_BS)
251.761 + col->dual = 0.0;
251.762 +#if 1
251.763 + else if (col->stat == GLP_NL)
251.764 + { xassert(col->type == GLP_LO || col->type == GLP_DB);
251.765 + col->prim = col->lb;
251.766 + }
251.767 + else if (col->stat == GLP_NU)
251.768 + { xassert(col->type == GLP_UP || col->type == GLP_DB);
251.769 + col->prim = col->ub;
251.770 + }
251.771 + else if (col->stat == GLP_NF)
251.772 + { xassert(col->type == GLP_FR);
251.773 + col->prim = 0.0;
251.774 + }
251.775 + else if (col->stat == GLP_NS)
251.776 + { xassert(col->type == GLP_FX);
251.777 + col->prim = col->lb;
251.778 + }
251.779 + else
251.780 + xassert(col != col);
251.781 +#endif
251.782 + orig->obj_val += col->coef * col->prim;
251.783 + }
251.784 +#if 1
251.785 + /* compute primal values of inactive rows */
251.786 + for (i = 1; i <= orig->m; i++)
251.787 + { row = orig->row[i];
251.788 + if (row->stat == GLP_BS)
251.789 + { GLPAIJ *aij;
251.790 + double temp;
251.791 + temp = 0.0;
251.792 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
251.793 + temp += aij->val * aij->col->prim;
251.794 + row->prim = temp;
251.795 + }
251.796 + }
251.797 + /* compute reduced costs of active columns */
251.798 + for (j = 1; j <= orig->n; j++)
251.799 + { col = orig->col[j];
251.800 + if (col->stat != GLP_BS)
251.801 + { GLPAIJ *aij;
251.802 + double temp;
251.803 + temp = col->coef;
251.804 + for (aij = col->ptr; aij != NULL; aij = aij->c_next)
251.805 + temp -= aij->val * aij->row->dual;
251.806 + col->dual = temp;
251.807 + }
251.808 + }
251.809 +#endif
251.810 + }
251.811 + else if (npp->sol == GLP_IPT)
251.812 + { /* store interior-point solution */
251.813 + orig->ipt_stat = npp->t_stat;
251.814 + orig->ipt_obj = orig->c0;
251.815 + for (i = 1; i <= orig->m; i++)
251.816 + { row = orig->row[i];
251.817 + if (!npp->scaling)
251.818 + { /*row->pval = npp->r_prim[i];*/
251.819 + row->dval = dir * npp->r_pi[i];
251.820 + }
251.821 + else
251.822 + { /*row->pval = npp->r_prim[i] / row->rii;*/
251.823 + row->dval = dir * npp->r_pi[i] * row->rii;
251.824 + }
251.825 + }
251.826 + for (j = 1; j <= orig->n; j++)
251.827 + { col = orig->col[j];
251.828 + if (!npp->scaling)
251.829 + { col->pval = npp->c_value[j];
251.830 + /*col->dval = dir * npp->c_dual[j];*/
251.831 + }
251.832 + else
251.833 + { col->pval = npp->c_value[j] * col->sjj;
251.834 + /*col->dval = dir * npp->c_dual[j] / col->sjj;*/
251.835 + }
251.836 + orig->ipt_obj += col->coef * col->pval;
251.837 + }
251.838 +#if 1
251.839 + /* compute row primal values */
251.840 + for (i = 1; i <= orig->m; i++)
251.841 + { row = orig->row[i];
251.842 + { GLPAIJ *aij;
251.843 + double temp;
251.844 + temp = 0.0;
251.845 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
251.846 + temp += aij->val * aij->col->pval;
251.847 + row->pval = temp;
251.848 + }
251.849 + }
251.850 + /* compute column dual values */
251.851 + for (j = 1; j <= orig->n; j++)
251.852 + { col = orig->col[j];
251.853 + { GLPAIJ *aij;
251.854 + double temp;
251.855 + temp = col->coef;
251.856 + for (aij = col->ptr; aij != NULL; aij = aij->c_next)
251.857 + temp -= aij->val * aij->row->dval;
251.858 + col->dval = temp;
251.859 + }
251.860 + }
251.861 +#endif
251.862 + }
251.863 + else if (npp->sol == GLP_MIP)
251.864 + { /* store MIP solution */
251.865 + xassert(!npp->scaling);
251.866 + orig->mip_stat = npp->i_stat;
251.867 + orig->mip_obj = orig->c0;
251.868 +#if 0
251.869 + for (i = 1; i <= orig->m; i++)
251.870 + { row = orig->row[i];
251.871 + /*row->mipx = npp->r_prim[i];*/
251.872 + }
251.873 +#endif
251.874 + for (j = 1; j <= orig->n; j++)
251.875 + { col = orig->col[j];
251.876 + col->mipx = npp->c_value[j];
251.877 + if (col->kind == GLP_IV)
251.878 + xassert(col->mipx == floor(col->mipx));
251.879 + orig->mip_obj += col->coef * col->mipx;
251.880 + }
251.881 +#if 1
251.882 + /* compute row primal values */
251.883 + for (i = 1; i <= orig->m; i++)
251.884 + { row = orig->row[i];
251.885 + { GLPAIJ *aij;
251.886 + double temp;
251.887 + temp = 0.0;
251.888 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
251.889 + temp += aij->val * aij->col->mipx;
251.890 + row->mipx = temp;
251.891 + }
251.892 + }
251.893 +#endif
251.894 + }
251.895 + else
251.896 + xassert(npp != npp);
251.897 + return;
251.898 +}
251.899 +
251.900 +void npp_delete_wksp(NPP *npp)
251.901 +{ /* delete LP/MIP preprocessor workspace */
251.902 + if (npp->pool != NULL)
251.903 + dmp_delete_pool(npp->pool);
251.904 + if (npp->stack != NULL)
251.905 + dmp_delete_pool(npp->stack);
251.906 + if (npp->row_ref != NULL)
251.907 + xfree(npp->row_ref);
251.908 + if (npp->col_ref != NULL)
251.909 + xfree(npp->col_ref);
251.910 + if (npp->r_stat != NULL)
251.911 + xfree(npp->r_stat);
251.912 +#if 0
251.913 + if (npp->r_prim != NULL)
251.914 + xfree(npp->r_prim);
251.915 +#endif
251.916 + if (npp->r_pi != NULL)
251.917 + xfree(npp->r_pi);
251.918 + if (npp->c_stat != NULL)
251.919 + xfree(npp->c_stat);
251.920 + if (npp->c_value != NULL)
251.921 + xfree(npp->c_value);
251.922 +#if 0
251.923 + if (npp->c_dual != NULL)
251.924 + xfree(npp->c_dual);
251.925 +#endif
251.926 + xfree(npp);
251.927 + return;
251.928 +}
251.929 +
251.930 +/* eof */
252.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
252.2 +++ b/src/glpnpp02.c Mon Dec 06 13:09:21 2010 +0100
252.3 @@ -0,0 +1,1433 @@
252.4 +/* glpnpp02.c */
252.5 +
252.6 +/***********************************************************************
252.7 +* This code is part of GLPK (GNU Linear Programming Kit).
252.8 +*
252.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
252.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
252.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
252.12 +* E-mail: <mao@gnu.org>.
252.13 +*
252.14 +* GLPK is free software: you can redistribute it and/or modify it
252.15 +* under the terms of the GNU General Public License as published by
252.16 +* the Free Software Foundation, either version 3 of the License, or
252.17 +* (at your option) any later version.
252.18 +*
252.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
252.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
252.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
252.22 +* License for more details.
252.23 +*
252.24 +* You should have received a copy of the GNU General Public License
252.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
252.26 +***********************************************************************/
252.27 +
252.28 +#include "glpnpp.h"
252.29 +
252.30 +/***********************************************************************
252.31 +* NAME
252.32 +*
252.33 +* npp_free_row - process free (unbounded) row
252.34 +*
252.35 +* SYNOPSIS
252.36 +*
252.37 +* #include "glpnpp.h"
252.38 +* void npp_free_row(NPP *npp, NPPROW *p);
252.39 +*
252.40 +* DESCRIPTION
252.41 +*
252.42 +* The routine npp_free_row processes row p, which is free (i.e. has
252.43 +* no finite bounds):
252.44 +*
252.45 +* -inf < sum a[p,j] x[j] < +inf. (1)
252.46 +* j
252.47 +*
252.48 +* PROBLEM TRANSFORMATION
252.49 +*
252.50 +* Constraint (1) cannot be active, so it is redundant and can be
252.51 +* removed from the original problem.
252.52 +*
252.53 +* Removing row p leads to removing a column of multiplier pi[p] for
252.54 +* this row in the dual system. Since row p has no bounds, pi[p] = 0,
252.55 +* so removing the column does not affect the dual solution.
252.56 +*
252.57 +* RECOVERING BASIC SOLUTION
252.58 +*
252.59 +* In solution to the original problem row p is inactive constraint,
252.60 +* so it is assigned status GLP_BS, and multiplier pi[p] is assigned
252.61 +* zero value.
252.62 +*
252.63 +* RECOVERING INTERIOR-POINT SOLUTION
252.64 +*
252.65 +* In solution to the original problem row p is inactive constraint,
252.66 +* so its multiplier pi[p] is assigned zero value.
252.67 +*
252.68 +* RECOVERING MIP SOLUTION
252.69 +*
252.70 +* None needed. */
252.71 +
252.72 +struct free_row
252.73 +{ /* free (unbounded) row */
252.74 + int p;
252.75 + /* row reference number */
252.76 +};
252.77 +
252.78 +static int rcv_free_row(NPP *npp, void *info);
252.79 +
252.80 +void npp_free_row(NPP *npp, NPPROW *p)
252.81 +{ /* process free (unbounded) row */
252.82 + struct free_row *info;
252.83 + /* the row must be free */
252.84 + xassert(p->lb == -DBL_MAX && p->ub == +DBL_MAX);
252.85 + /* create transformation stack entry */
252.86 + info = npp_push_tse(npp,
252.87 + rcv_free_row, sizeof(struct free_row));
252.88 + info->p = p->i;
252.89 + /* remove the row from the problem */
252.90 + npp_del_row(npp, p);
252.91 + return;
252.92 +}
252.93 +
252.94 +static int rcv_free_row(NPP *npp, void *_info)
252.95 +{ /* recover free (unbounded) row */
252.96 + struct free_row *info = _info;
252.97 + if (npp->sol == GLP_SOL)
252.98 + npp->r_stat[info->p] = GLP_BS;
252.99 + if (npp->sol != GLP_MIP)
252.100 + npp->r_pi[info->p] = 0.0;
252.101 + return 0;
252.102 +}
252.103 +
252.104 +/***********************************************************************
252.105 +* NAME
252.106 +*
252.107 +* npp_geq_row - process row of 'not less than' type
252.108 +*
252.109 +* SYNOPSIS
252.110 +*
252.111 +* #include "glpnpp.h"
252.112 +* void npp_geq_row(NPP *npp, NPPROW *p);
252.113 +*
252.114 +* DESCRIPTION
252.115 +*
252.116 +* The routine npp_geq_row processes row p, which is 'not less than'
252.117 +* inequality constraint:
252.118 +*
252.119 +* L[p] <= sum a[p,j] x[j] (<= U[p]), (1)
252.120 +* j
252.121 +*
252.122 +* where L[p] < U[p], and upper bound may not exist (U[p] = +oo).
252.123 +*
252.124 +* PROBLEM TRANSFORMATION
252.125 +*
252.126 +* Constraint (1) can be replaced by equality constraint:
252.127 +*
252.128 +* sum a[p,j] x[j] - s = L[p], (2)
252.129 +* j
252.130 +*
252.131 +* where
252.132 +*
252.133 +* 0 <= s (<= U[p] - L[p]) (3)
252.134 +*
252.135 +* is a non-negative surplus variable.
252.136 +*
252.137 +* Since in the primal system there appears column s having the only
252.138 +* non-zero coefficient in row p, in the dual system there appears a
252.139 +* new row:
252.140 +*
252.141 +* (-1) pi[p] + lambda = 0, (4)
252.142 +*
252.143 +* where (-1) is coefficient of column s in row p, pi[p] is multiplier
252.144 +* of row p, lambda is multiplier of column q, 0 is coefficient of
252.145 +* column s in the objective row.
252.146 +*
252.147 +* RECOVERING BASIC SOLUTION
252.148 +*
252.149 +* Status of row p in solution to the original problem is determined
252.150 +* by its status and status of column q in solution to the transformed
252.151 +* problem as follows:
252.152 +*
252.153 +* +--------------------------------------+------------------+
252.154 +* | Transformed problem | Original problem |
252.155 +* +-----------------+--------------------+------------------+
252.156 +* | Status of row p | Status of column s | Status of row p |
252.157 +* +-----------------+--------------------+------------------+
252.158 +* | GLP_BS | GLP_BS | N/A |
252.159 +* | GLP_BS | GLP_NL | GLP_BS |
252.160 +* | GLP_BS | GLP_NU | GLP_BS |
252.161 +* | GLP_NS | GLP_BS | GLP_BS |
252.162 +* | GLP_NS | GLP_NL | GLP_NL |
252.163 +* | GLP_NS | GLP_NU | GLP_NU |
252.164 +* +-----------------+--------------------+------------------+
252.165 +*
252.166 +* Value of row multiplier pi[p] in solution to the original problem
252.167 +* is the same as in solution to the transformed problem.
252.168 +*
252.169 +* 1. In solution to the transformed problem row p and column q cannot
252.170 +* be basic at the same time; otherwise the basis matrix would have
252.171 +* two linear dependent columns: unity column of auxiliary variable
252.172 +* of row p and unity column of variable s.
252.173 +*
252.174 +* 2. Though in the transformed problem row p is equality constraint,
252.175 +* it may be basic due to primal degenerate solution.
252.176 +*
252.177 +* RECOVERING INTERIOR-POINT SOLUTION
252.178 +*
252.179 +* Value of row multiplier pi[p] in solution to the original problem
252.180 +* is the same as in solution to the transformed problem.
252.181 +*
252.182 +* RECOVERING MIP SOLUTION
252.183 +*
252.184 +* None needed. */
252.185 +
252.186 +struct ineq_row
252.187 +{ /* inequality constraint row */
252.188 + int p;
252.189 + /* row reference number */
252.190 + int s;
252.191 + /* column reference number for slack/surplus variable */
252.192 +};
252.193 +
252.194 +static int rcv_geq_row(NPP *npp, void *info);
252.195 +
252.196 +void npp_geq_row(NPP *npp, NPPROW *p)
252.197 +{ /* process row of 'not less than' type */
252.198 + struct ineq_row *info;
252.199 + NPPCOL *s;
252.200 + /* the row must have lower bound */
252.201 + xassert(p->lb != -DBL_MAX);
252.202 + xassert(p->lb < p->ub);
252.203 + /* create column for surplus variable */
252.204 + s = npp_add_col(npp);
252.205 + s->lb = 0.0;
252.206 + s->ub = (p->ub == +DBL_MAX ? +DBL_MAX : p->ub - p->lb);
252.207 + /* and add it to the transformed problem */
252.208 + npp_add_aij(npp, p, s, -1.0);
252.209 + /* create transformation stack entry */
252.210 + info = npp_push_tse(npp,
252.211 + rcv_geq_row, sizeof(struct ineq_row));
252.212 + info->p = p->i;
252.213 + info->s = s->j;
252.214 + /* replace the row by equality constraint */
252.215 + p->ub = p->lb;
252.216 + return;
252.217 +}
252.218 +
252.219 +static int rcv_geq_row(NPP *npp, void *_info)
252.220 +{ /* recover row of 'not less than' type */
252.221 + struct ineq_row *info = _info;
252.222 + if (npp->sol == GLP_SOL)
252.223 + { if (npp->r_stat[info->p] == GLP_BS)
252.224 + { if (npp->c_stat[info->s] == GLP_BS)
252.225 + { npp_error();
252.226 + return 1;
252.227 + }
252.228 + else if (npp->c_stat[info->s] == GLP_NL ||
252.229 + npp->c_stat[info->s] == GLP_NU)
252.230 + npp->r_stat[info->p] = GLP_BS;
252.231 + else
252.232 + { npp_error();
252.233 + return 1;
252.234 + }
252.235 + }
252.236 + else if (npp->r_stat[info->p] == GLP_NS)
252.237 + { if (npp->c_stat[info->s] == GLP_BS)
252.238 + npp->r_stat[info->p] = GLP_BS;
252.239 + else if (npp->c_stat[info->s] == GLP_NL)
252.240 + npp->r_stat[info->p] = GLP_NL;
252.241 + else if (npp->c_stat[info->s] == GLP_NU)
252.242 + npp->r_stat[info->p] = GLP_NU;
252.243 + else
252.244 + { npp_error();
252.245 + return 1;
252.246 + }
252.247 + }
252.248 + else
252.249 + { npp_error();
252.250 + return 1;
252.251 + }
252.252 + }
252.253 + return 0;
252.254 +}
252.255 +
252.256 +/***********************************************************************
252.257 +* NAME
252.258 +*
252.259 +* npp_leq_row - process row of 'not greater than' type
252.260 +*
252.261 +* SYNOPSIS
252.262 +*
252.263 +* #include "glpnpp.h"
252.264 +* void npp_leq_row(NPP *npp, NPPROW *p);
252.265 +*
252.266 +* DESCRIPTION
252.267 +*
252.268 +* The routine npp_leq_row processes row p, which is 'not greater than'
252.269 +* inequality constraint:
252.270 +*
252.271 +* (L[p] <=) sum a[p,j] x[j] <= U[p], (1)
252.272 +* j
252.273 +*
252.274 +* where L[p] < U[p], and lower bound may not exist (L[p] = +oo).
252.275 +*
252.276 +* PROBLEM TRANSFORMATION
252.277 +*
252.278 +* Constraint (1) can be replaced by equality constraint:
252.279 +*
252.280 +* sum a[p,j] x[j] + s = L[p], (2)
252.281 +* j
252.282 +*
252.283 +* where
252.284 +*
252.285 +* 0 <= s (<= U[p] - L[p]) (3)
252.286 +*
252.287 +* is a non-negative slack variable.
252.288 +*
252.289 +* Since in the primal system there appears column s having the only
252.290 +* non-zero coefficient in row p, in the dual system there appears a
252.291 +* new row:
252.292 +*
252.293 +* (+1) pi[p] + lambda = 0, (4)
252.294 +*
252.295 +* where (+1) is coefficient of column s in row p, pi[p] is multiplier
252.296 +* of row p, lambda is multiplier of column q, 0 is coefficient of
252.297 +* column s in the objective row.
252.298 +*
252.299 +* RECOVERING BASIC SOLUTION
252.300 +*
252.301 +* Status of row p in solution to the original problem is determined
252.302 +* by its status and status of column q in solution to the transformed
252.303 +* problem as follows:
252.304 +*
252.305 +* +--------------------------------------+------------------+
252.306 +* | Transformed problem | Original problem |
252.307 +* +-----------------+--------------------+------------------+
252.308 +* | Status of row p | Status of column s | Status of row p |
252.309 +* +-----------------+--------------------+------------------+
252.310 +* | GLP_BS | GLP_BS | N/A |
252.311 +* | GLP_BS | GLP_NL | GLP_BS |
252.312 +* | GLP_BS | GLP_NU | GLP_BS |
252.313 +* | GLP_NS | GLP_BS | GLP_BS |
252.314 +* | GLP_NS | GLP_NL | GLP_NU |
252.315 +* | GLP_NS | GLP_NU | GLP_NL |
252.316 +* +-----------------+--------------------+------------------+
252.317 +*
252.318 +* Value of row multiplier pi[p] in solution to the original problem
252.319 +* is the same as in solution to the transformed problem.
252.320 +*
252.321 +* 1. In solution to the transformed problem row p and column q cannot
252.322 +* be basic at the same time; otherwise the basis matrix would have
252.323 +* two linear dependent columns: unity column of auxiliary variable
252.324 +* of row p and unity column of variable s.
252.325 +*
252.326 +* 2. Though in the transformed problem row p is equality constraint,
252.327 +* it may be basic due to primal degeneracy.
252.328 +*
252.329 +* RECOVERING INTERIOR-POINT SOLUTION
252.330 +*
252.331 +* Value of row multiplier pi[p] in solution to the original problem
252.332 +* is the same as in solution to the transformed problem.
252.333 +*
252.334 +* RECOVERING MIP SOLUTION
252.335 +*
252.336 +* None needed. */
252.337 +
252.338 +static int rcv_leq_row(NPP *npp, void *info);
252.339 +
252.340 +void npp_leq_row(NPP *npp, NPPROW *p)
252.341 +{ /* process row of 'not greater than' type */
252.342 + struct ineq_row *info;
252.343 + NPPCOL *s;
252.344 + /* the row must have upper bound */
252.345 + xassert(p->ub != +DBL_MAX);
252.346 + xassert(p->lb < p->ub);
252.347 + /* create column for slack variable */
252.348 + s = npp_add_col(npp);
252.349 + s->lb = 0.0;
252.350 + s->ub = (p->lb == -DBL_MAX ? +DBL_MAX : p->ub - p->lb);
252.351 + /* and add it to the transformed problem */
252.352 + npp_add_aij(npp, p, s, +1.0);
252.353 + /* create transformation stack entry */
252.354 + info = npp_push_tse(npp,
252.355 + rcv_leq_row, sizeof(struct ineq_row));
252.356 + info->p = p->i;
252.357 + info->s = s->j;
252.358 + /* replace the row by equality constraint */
252.359 + p->lb = p->ub;
252.360 + return;
252.361 +}
252.362 +
252.363 +static int rcv_leq_row(NPP *npp, void *_info)
252.364 +{ /* recover row of 'not greater than' type */
252.365 + struct ineq_row *info = _info;
252.366 + if (npp->sol == GLP_SOL)
252.367 + { if (npp->r_stat[info->p] == GLP_BS)
252.368 + { if (npp->c_stat[info->s] == GLP_BS)
252.369 + { npp_error();
252.370 + return 1;
252.371 + }
252.372 + else if (npp->c_stat[info->s] == GLP_NL ||
252.373 + npp->c_stat[info->s] == GLP_NU)
252.374 + npp->r_stat[info->p] = GLP_BS;
252.375 + else
252.376 + { npp_error();
252.377 + return 1;
252.378 + }
252.379 + }
252.380 + else if (npp->r_stat[info->p] == GLP_NS)
252.381 + { if (npp->c_stat[info->s] == GLP_BS)
252.382 + npp->r_stat[info->p] = GLP_BS;
252.383 + else if (npp->c_stat[info->s] == GLP_NL)
252.384 + npp->r_stat[info->p] = GLP_NU;
252.385 + else if (npp->c_stat[info->s] == GLP_NU)
252.386 + npp->r_stat[info->p] = GLP_NL;
252.387 + else
252.388 + { npp_error();
252.389 + return 1;
252.390 + }
252.391 + }
252.392 + else
252.393 + { npp_error();
252.394 + return 1;
252.395 + }
252.396 + }
252.397 + return 0;
252.398 +}
252.399 +
252.400 +/***********************************************************************
252.401 +* NAME
252.402 +*
252.403 +* npp_free_col - process free (unbounded) column
252.404 +*
252.405 +* SYNOPSIS
252.406 +*
252.407 +* #include "glpnpp.h"
252.408 +* void npp_free_col(NPP *npp, NPPCOL *q);
252.409 +*
252.410 +* DESCRIPTION
252.411 +*
252.412 +* The routine npp_free_col processes column q, which is free (i.e. has
252.413 +* no finite bounds):
252.414 +*
252.415 +* -oo < x[q] < +oo. (1)
252.416 +*
252.417 +* PROBLEM TRANSFORMATION
252.418 +*
252.419 +* Free (unbounded) variable can be replaced by the difference of two
252.420 +* non-negative variables:
252.421 +*
252.422 +* x[q] = s' - s'', s', s'' >= 0. (2)
252.423 +*
252.424 +* Assuming that in the transformed problem x[q] becomes s',
252.425 +* transformation (2) causes new column s'' to appear, which differs
252.426 +* from column s' only in the sign of coefficients in constraint and
252.427 +* objective rows. Thus, if in the dual system the following row
252.428 +* corresponds to column s':
252.429 +*
252.430 +* sum a[i,q] pi[i] + lambda' = c[q], (3)
252.431 +* i
252.432 +*
252.433 +* the row which corresponds to column s'' is the following:
252.434 +*
252.435 +* sum (-a[i,q]) pi[i] + lambda'' = -c[q]. (4)
252.436 +* i
252.437 +*
252.438 +* Then from (3) and (4) it follows that:
252.439 +*
252.440 +* lambda' + lambda'' = 0 => lambda' = lmabda'' = 0, (5)
252.441 +*
252.442 +* where lambda' and lambda'' are multipliers for columns s' and s'',
252.443 +* resp.
252.444 +*
252.445 +* RECOVERING BASIC SOLUTION
252.446 +*
252.447 +* With respect to (5) status of column q in solution to the original
252.448 +* problem is determined by statuses of columns s' and s'' in solution
252.449 +* to the transformed problem as follows:
252.450 +*
252.451 +* +--------------------------------------+------------------+
252.452 +* | Transformed problem | Original problem |
252.453 +* +------------------+-------------------+------------------+
252.454 +* | Status of col s' | Status of col s'' | Status of col q |
252.455 +* +------------------+-------------------+------------------+
252.456 +* | GLP_BS | GLP_BS | N/A |
252.457 +* | GLP_BS | GLP_NL | GLP_BS |
252.458 +* | GLP_NL | GLP_BS | GLP_BS |
252.459 +* | GLP_NL | GLP_NL | GLP_NF |
252.460 +* +------------------+-------------------+------------------+
252.461 +*
252.462 +* Value of column q is computed with formula (2).
252.463 +*
252.464 +* 1. In solution to the transformed problem columns s' and s'' cannot
252.465 +* be basic at the same time, because they differ only in the sign,
252.466 +* hence, are linear dependent.
252.467 +*
252.468 +* 2. Though column q is free, it can be non-basic due to dual
252.469 +* degeneracy.
252.470 +*
252.471 +* 3. If column q is integral, columns s' and s'' are also integral.
252.472 +*
252.473 +* RECOVERING INTERIOR-POINT SOLUTION
252.474 +*
252.475 +* Value of column q is computed with formula (2).
252.476 +*
252.477 +* RECOVERING MIP SOLUTION
252.478 +*
252.479 +* Value of column q is computed with formula (2). */
252.480 +
252.481 +struct free_col
252.482 +{ /* free (unbounded) column */
252.483 + int q;
252.484 + /* column reference number for variables x[q] and s' */
252.485 + int s;
252.486 + /* column reference number for variable s'' */
252.487 +};
252.488 +
252.489 +static int rcv_free_col(NPP *npp, void *info);
252.490 +
252.491 +void npp_free_col(NPP *npp, NPPCOL *q)
252.492 +{ /* process free (unbounded) column */
252.493 + struct free_col *info;
252.494 + NPPCOL *s;
252.495 + NPPAIJ *aij;
252.496 + /* the column must be free */
252.497 + xassert(q->lb == -DBL_MAX && q->ub == +DBL_MAX);
252.498 + /* variable x[q] becomes s' */
252.499 + q->lb = 0.0, q->ub = +DBL_MAX;
252.500 + /* create variable s'' */
252.501 + s = npp_add_col(npp);
252.502 + s->is_int = q->is_int;
252.503 + s->lb = 0.0, s->ub = +DBL_MAX;
252.504 + /* duplicate objective coefficient */
252.505 + s->coef = -q->coef;
252.506 + /* duplicate column of the constraint matrix */
252.507 + for (aij = q->ptr; aij != NULL; aij = aij->c_next)
252.508 + npp_add_aij(npp, aij->row, s, -aij->val);
252.509 + /* create transformation stack entry */
252.510 + info = npp_push_tse(npp,
252.511 + rcv_free_col, sizeof(struct free_col));
252.512 + info->q = q->j;
252.513 + info->s = s->j;
252.514 + return;
252.515 +}
252.516 +
252.517 +static int rcv_free_col(NPP *npp, void *_info)
252.518 +{ /* recover free (unbounded) column */
252.519 + struct free_col *info = _info;
252.520 + if (npp->sol == GLP_SOL)
252.521 + { if (npp->c_stat[info->q] == GLP_BS)
252.522 + { if (npp->c_stat[info->s] == GLP_BS)
252.523 + { npp_error();
252.524 + return 1;
252.525 + }
252.526 + else if (npp->c_stat[info->s] == GLP_NL)
252.527 + npp->c_stat[info->q] = GLP_BS;
252.528 + else
252.529 + { npp_error();
252.530 + return -1;
252.531 + }
252.532 + }
252.533 + else if (npp->c_stat[info->q] == GLP_NL)
252.534 + { if (npp->c_stat[info->s] == GLP_BS)
252.535 + npp->c_stat[info->q] = GLP_BS;
252.536 + else if (npp->c_stat[info->s] == GLP_NL)
252.537 + npp->c_stat[info->q] = GLP_NF;
252.538 + else
252.539 + { npp_error();
252.540 + return -1;
252.541 + }
252.542 + }
252.543 + else
252.544 + { npp_error();
252.545 + return -1;
252.546 + }
252.547 + }
252.548 + /* compute value of x[q] with formula (2) */
252.549 + npp->c_value[info->q] -= npp->c_value[info->s];
252.550 + return 0;
252.551 +}
252.552 +
252.553 +/***********************************************************************
252.554 +* NAME
252.555 +*
252.556 +* npp_lbnd_col - process column with (non-zero) lower bound
252.557 +*
252.558 +* SYNOPSIS
252.559 +*
252.560 +* #include "glpnpp.h"
252.561 +* void npp_lbnd_col(NPP *npp, NPPCOL *q);
252.562 +*
252.563 +* DESCRIPTION
252.564 +*
252.565 +* The routine npp_lbnd_col processes column q, which has (non-zero)
252.566 +* lower bound:
252.567 +*
252.568 +* l[q] <= x[q] (<= u[q]), (1)
252.569 +*
252.570 +* where l[q] < u[q], and upper bound may not exist (u[q] = +oo).
252.571 +*
252.572 +* PROBLEM TRANSFORMATION
252.573 +*
252.574 +* Column q can be replaced as follows:
252.575 +*
252.576 +* x[q] = l[q] + s, (2)
252.577 +*
252.578 +* where
252.579 +*
252.580 +* 0 <= s (<= u[q] - l[q]) (3)
252.581 +*
252.582 +* is a non-negative variable.
252.583 +*
252.584 +* Substituting x[q] from (2) into the objective row, we have:
252.585 +*
252.586 +* z = sum c[j] x[j] + c0 =
252.587 +* j
252.588 +*
252.589 +* = sum c[j] x[j] + c[q] x[q] + c0 =
252.590 +* j!=q
252.591 +*
252.592 +* = sum c[j] x[j] + c[q] (l[q] + s) + c0 =
252.593 +* j!=q
252.594 +*
252.595 +* = sum c[j] x[j] + c[q] s + c~0,
252.596 +*
252.597 +* where
252.598 +*
252.599 +* c~0 = c0 + c[q] l[q] (4)
252.600 +*
252.601 +* is the constant term of the objective in the transformed problem.
252.602 +* Similarly, substituting x[q] into constraint row i, we have:
252.603 +*
252.604 +* L[i] <= sum a[i,j] x[j] <= U[i] ==>
252.605 +* j
252.606 +*
252.607 +* L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
252.608 +* j!=q
252.609 +*
252.610 +* L[i] <= sum a[i,j] x[j] + a[i,q] (l[q] + s) <= U[i] ==>
252.611 +* j!=q
252.612 +*
252.613 +* L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
252.614 +* j!=q
252.615 +*
252.616 +* where
252.617 +*
252.618 +* L~[i] = L[i] - a[i,q] l[q], U~[i] = U[i] - a[i,q] l[q] (5)
252.619 +*
252.620 +* are lower and upper bounds of row i in the transformed problem,
252.621 +* resp.
252.622 +*
252.623 +* Transformation (2) does not affect the dual system.
252.624 +*
252.625 +* RECOVERING BASIC SOLUTION
252.626 +*
252.627 +* Status of column q in solution to the original problem is the same
252.628 +* as in solution to the transformed problem (GLP_BS, GLP_NL or GLP_NU).
252.629 +* Value of column q is computed with formula (2).
252.630 +*
252.631 +* RECOVERING INTERIOR-POINT SOLUTION
252.632 +*
252.633 +* Value of column q is computed with formula (2).
252.634 +*
252.635 +* RECOVERING MIP SOLUTION
252.636 +*
252.637 +* Value of column q is computed with formula (2). */
252.638 +
252.639 +struct bnd_col
252.640 +{ /* bounded column */
252.641 + int q;
252.642 + /* column reference number for variables x[q] and s */
252.643 + double bnd;
252.644 + /* lower/upper bound l[q] or u[q] */
252.645 +};
252.646 +
252.647 +static int rcv_lbnd_col(NPP *npp, void *info);
252.648 +
252.649 +void npp_lbnd_col(NPP *npp, NPPCOL *q)
252.650 +{ /* process column with (non-zero) lower bound */
252.651 + struct bnd_col *info;
252.652 + NPPROW *i;
252.653 + NPPAIJ *aij;
252.654 + /* the column must have non-zero lower bound */
252.655 + xassert(q->lb != 0.0);
252.656 + xassert(q->lb != -DBL_MAX);
252.657 + xassert(q->lb < q->ub);
252.658 + /* create transformation stack entry */
252.659 + info = npp_push_tse(npp,
252.660 + rcv_lbnd_col, sizeof(struct bnd_col));
252.661 + info->q = q->j;
252.662 + info->bnd = q->lb;
252.663 + /* substitute x[q] into objective row */
252.664 + npp->c0 += q->coef * q->lb;
252.665 + /* substitute x[q] into constraint rows */
252.666 + for (aij = q->ptr; aij != NULL; aij = aij->c_next)
252.667 + { i = aij->row;
252.668 + if (i->lb == i->ub)
252.669 + i->ub = (i->lb -= aij->val * q->lb);
252.670 + else
252.671 + { if (i->lb != -DBL_MAX)
252.672 + i->lb -= aij->val * q->lb;
252.673 + if (i->ub != +DBL_MAX)
252.674 + i->ub -= aij->val * q->lb;
252.675 + }
252.676 + }
252.677 + /* column x[q] becomes column s */
252.678 + if (q->ub != +DBL_MAX)
252.679 + q->ub -= q->lb;
252.680 + q->lb = 0.0;
252.681 + return;
252.682 +}
252.683 +
252.684 +static int rcv_lbnd_col(NPP *npp, void *_info)
252.685 +{ /* recover column with (non-zero) lower bound */
252.686 + struct bnd_col *info = _info;
252.687 + if (npp->sol == GLP_SOL)
252.688 + { if (npp->c_stat[info->q] == GLP_BS ||
252.689 + npp->c_stat[info->q] == GLP_NL ||
252.690 + npp->c_stat[info->q] == GLP_NU)
252.691 + npp->c_stat[info->q] = npp->c_stat[info->q];
252.692 + else
252.693 + { npp_error();
252.694 + return 1;
252.695 + }
252.696 + }
252.697 + /* compute value of x[q] with formula (2) */
252.698 + npp->c_value[info->q] = info->bnd + npp->c_value[info->q];
252.699 + return 0;
252.700 +}
252.701 +
252.702 +/***********************************************************************
252.703 +* NAME
252.704 +*
252.705 +* npp_ubnd_col - process column with upper bound
252.706 +*
252.707 +* SYNOPSIS
252.708 +*
252.709 +* #include "glpnpp.h"
252.710 +* void npp_ubnd_col(NPP *npp, NPPCOL *q);
252.711 +*
252.712 +* DESCRIPTION
252.713 +*
252.714 +* The routine npp_ubnd_col processes column q, which has upper bound:
252.715 +*
252.716 +* (l[q] <=) x[q] <= u[q], (1)
252.717 +*
252.718 +* where l[q] < u[q], and lower bound may not exist (l[q] = -oo).
252.719 +*
252.720 +* PROBLEM TRANSFORMATION
252.721 +*
252.722 +* Column q can be replaced as follows:
252.723 +*
252.724 +* x[q] = u[q] - s, (2)
252.725 +*
252.726 +* where
252.727 +*
252.728 +* 0 <= s (<= u[q] - l[q]) (3)
252.729 +*
252.730 +* is a non-negative variable.
252.731 +*
252.732 +* Substituting x[q] from (2) into the objective row, we have:
252.733 +*
252.734 +* z = sum c[j] x[j] + c0 =
252.735 +* j
252.736 +*
252.737 +* = sum c[j] x[j] + c[q] x[q] + c0 =
252.738 +* j!=q
252.739 +*
252.740 +* = sum c[j] x[j] + c[q] (u[q] - s) + c0 =
252.741 +* j!=q
252.742 +*
252.743 +* = sum c[j] x[j] - c[q] s + c~0,
252.744 +*
252.745 +* where
252.746 +*
252.747 +* c~0 = c0 + c[q] u[q] (4)
252.748 +*
252.749 +* is the constant term of the objective in the transformed problem.
252.750 +* Similarly, substituting x[q] into constraint row i, we have:
252.751 +*
252.752 +* L[i] <= sum a[i,j] x[j] <= U[i] ==>
252.753 +* j
252.754 +*
252.755 +* L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
252.756 +* j!=q
252.757 +*
252.758 +* L[i] <= sum a[i,j] x[j] + a[i,q] (u[q] - s) <= U[i] ==>
252.759 +* j!=q
252.760 +*
252.761 +* L~[i] <= sum a[i,j] x[j] - a[i,q] s <= U~[i],
252.762 +* j!=q
252.763 +*
252.764 +* where
252.765 +*
252.766 +* L~[i] = L[i] - a[i,q] u[q], U~[i] = U[i] - a[i,q] u[q] (5)
252.767 +*
252.768 +* are lower and upper bounds of row i in the transformed problem,
252.769 +* resp.
252.770 +*
252.771 +* Note that in the transformed problem coefficients c[q] and a[i,q]
252.772 +* change their sign. Thus, the row of the dual system corresponding to
252.773 +* column q:
252.774 +*
252.775 +* sum a[i,q] pi[i] + lambda[q] = c[q] (6)
252.776 +* i
252.777 +*
252.778 +* in the transformed problem becomes the following:
252.779 +*
252.780 +* sum (-a[i,q]) pi[i] + lambda[s] = -c[q]. (7)
252.781 +* i
252.782 +*
252.783 +* Therefore:
252.784 +*
252.785 +* lambda[q] = - lambda[s], (8)
252.786 +*
252.787 +* where lambda[q] is multiplier for column q, lambda[s] is multiplier
252.788 +* for column s.
252.789 +*
252.790 +* RECOVERING BASIC SOLUTION
252.791 +*
252.792 +* With respect to (8) status of column q in solution to the original
252.793 +* problem is determined by status of column s in solution to the
252.794 +* transformed problem as follows:
252.795 +*
252.796 +* +-----------------------+--------------------+
252.797 +* | Status of column s | Status of column q |
252.798 +* | (transformed problem) | (original problem) |
252.799 +* +-----------------------+--------------------+
252.800 +* | GLP_BS | GLP_BS |
252.801 +* | GLP_NL | GLP_NU |
252.802 +* | GLP_NU | GLP_NL |
252.803 +* +-----------------------+--------------------+
252.804 +*
252.805 +* Value of column q is computed with formula (2).
252.806 +*
252.807 +* RECOVERING INTERIOR-POINT SOLUTION
252.808 +*
252.809 +* Value of column q is computed with formula (2).
252.810 +*
252.811 +* RECOVERING MIP SOLUTION
252.812 +*
252.813 +* Value of column q is computed with formula (2). */
252.814 +
252.815 +static int rcv_ubnd_col(NPP *npp, void *info);
252.816 +
252.817 +void npp_ubnd_col(NPP *npp, NPPCOL *q)
252.818 +{ /* process column with upper bound */
252.819 + struct bnd_col *info;
252.820 + NPPROW *i;
252.821 + NPPAIJ *aij;
252.822 + /* the column must have upper bound */
252.823 + xassert(q->ub != +DBL_MAX);
252.824 + xassert(q->lb < q->ub);
252.825 + /* create transformation stack entry */
252.826 + info = npp_push_tse(npp,
252.827 + rcv_ubnd_col, sizeof(struct bnd_col));
252.828 + info->q = q->j;
252.829 + info->bnd = q->ub;
252.830 + /* substitute x[q] into objective row */
252.831 + npp->c0 += q->coef * q->ub;
252.832 + q->coef = -q->coef;
252.833 + /* substitute x[q] into constraint rows */
252.834 + for (aij = q->ptr; aij != NULL; aij = aij->c_next)
252.835 + { i = aij->row;
252.836 + if (i->lb == i->ub)
252.837 + i->ub = (i->lb -= aij->val * q->ub);
252.838 + else
252.839 + { if (i->lb != -DBL_MAX)
252.840 + i->lb -= aij->val * q->ub;
252.841 + if (i->ub != +DBL_MAX)
252.842 + i->ub -= aij->val * q->ub;
252.843 + }
252.844 + aij->val = -aij->val;
252.845 + }
252.846 + /* column x[q] becomes column s */
252.847 + if (q->lb != -DBL_MAX)
252.848 + q->ub -= q->lb;
252.849 + else
252.850 + q->ub = +DBL_MAX;
252.851 + q->lb = 0.0;
252.852 + return;
252.853 +}
252.854 +
252.855 +static int rcv_ubnd_col(NPP *npp, void *_info)
252.856 +{ /* recover column with upper bound */
252.857 + struct bnd_col *info = _info;
252.858 + if (npp->sol == GLP_BS)
252.859 + { if (npp->c_stat[info->q] == GLP_BS)
252.860 + npp->c_stat[info->q] = GLP_BS;
252.861 + else if (npp->c_stat[info->q] == GLP_NL)
252.862 + npp->c_stat[info->q] = GLP_NU;
252.863 + else if (npp->c_stat[info->q] == GLP_NU)
252.864 + npp->c_stat[info->q] = GLP_NL;
252.865 + else
252.866 + { npp_error();
252.867 + return 1;
252.868 + }
252.869 + }
252.870 + /* compute value of x[q] with formula (2) */
252.871 + npp->c_value[info->q] = info->bnd - npp->c_value[info->q];
252.872 + return 0;
252.873 +}
252.874 +
252.875 +/***********************************************************************
252.876 +* NAME
252.877 +*
252.878 +* npp_dbnd_col - process non-negative column with upper bound
252.879 +*
252.880 +* SYNOPSIS
252.881 +*
252.882 +* #include "glpnpp.h"
252.883 +* void npp_dbnd_col(NPP *npp, NPPCOL *q);
252.884 +*
252.885 +* DESCRIPTION
252.886 +*
252.887 +* The routine npp_dbnd_col processes column q, which is non-negative
252.888 +* and has upper bound:
252.889 +*
252.890 +* 0 <= x[q] <= u[q], (1)
252.891 +*
252.892 +* where u[q] > 0.
252.893 +*
252.894 +* PROBLEM TRANSFORMATION
252.895 +*
252.896 +* Upper bound of column q can be replaced by the following equality
252.897 +* constraint:
252.898 +*
252.899 +* x[q] + s = u[q], (2)
252.900 +*
252.901 +* where s >= 0 is a non-negative complement variable.
252.902 +*
252.903 +* Since in the primal system along with new row (2) there appears a
252.904 +* new column s having the only non-zero coefficient in this row, in
252.905 +* the dual system there appears a new row:
252.906 +*
252.907 +* (+1)pi + lambda[s] = 0, (3)
252.908 +*
252.909 +* where (+1) is coefficient at column s in row (2), pi is multiplier
252.910 +* for row (2), lambda[s] is multiplier for column s, 0 is coefficient
252.911 +* at column s in the objective row.
252.912 +*
252.913 +* RECOVERING BASIC SOLUTION
252.914 +*
252.915 +* Status of column q in solution to the original problem is determined
252.916 +* by its status and status of column s in solution to the transformed
252.917 +* problem as follows:
252.918 +*
252.919 +* +-----------------------------------+------------------+
252.920 +* | Transformed problem | Original problem |
252.921 +* +-----------------+-----------------+------------------+
252.922 +* | Status of col q | Status of col s | Status of col q |
252.923 +* +-----------------+-----------------+------------------+
252.924 +* | GLP_BS | GLP_BS | GLP_BS |
252.925 +* | GLP_BS | GLP_NL | GLP_NU |
252.926 +* | GLP_NL | GLP_BS | GLP_NL |
252.927 +* | GLP_NL | GLP_NL | GLP_NL (*) |
252.928 +* +-----------------+-----------------+------------------+
252.929 +*
252.930 +* Value of column q in solution to the original problem is the same as
252.931 +* in solution to the transformed problem.
252.932 +*
252.933 +* 1. Formally, in solution to the transformed problem columns q and s
252.934 +* cannot be non-basic at the same time, since the constraint (2)
252.935 +* would be violated. However, if u[q] is close to zero, violation
252.936 +* may be less than a working precision even if both columns q and s
252.937 +* are non-basic. In this degenerate case row (2) can be only basic,
252.938 +* i.e. non-active constraint (otherwise corresponding row of the
252.939 +* basis matrix would be zero). This allows to pivot out auxiliary
252.940 +* variable and pivot in column s, in which case the row becomes
252.941 +* active while column s becomes basic.
252.942 +*
252.943 +* 2. If column q is integral, column s is also integral.
252.944 +*
252.945 +* RECOVERING INTERIOR-POINT SOLUTION
252.946 +*
252.947 +* Value of column q in solution to the original problem is the same as
252.948 +* in solution to the transformed problem.
252.949 +*
252.950 +* RECOVERING MIP SOLUTION
252.951 +*
252.952 +* Value of column q in solution to the original problem is the same as
252.953 +* in solution to the transformed problem. */
252.954 +
252.955 +struct dbnd_col
252.956 +{ /* double-bounded column */
252.957 + int q;
252.958 + /* column reference number for variable x[q] */
252.959 + int s;
252.960 + /* column reference number for complement variable s */
252.961 +};
252.962 +
252.963 +static int rcv_dbnd_col(NPP *npp, void *info);
252.964 +
252.965 +void npp_dbnd_col(NPP *npp, NPPCOL *q)
252.966 +{ /* process non-negative column with upper bound */
252.967 + struct dbnd_col *info;
252.968 + NPPROW *p;
252.969 + NPPCOL *s;
252.970 + /* the column must be non-negative with upper bound */
252.971 + xassert(q->lb == 0.0);
252.972 + xassert(q->ub > 0.0);
252.973 + xassert(q->ub != +DBL_MAX);
252.974 + /* create variable s */
252.975 + s = npp_add_col(npp);
252.976 + s->is_int = q->is_int;
252.977 + s->lb = 0.0, s->ub = +DBL_MAX;
252.978 + /* create equality constraint (2) */
252.979 + p = npp_add_row(npp);
252.980 + p->lb = p->ub = q->ub;
252.981 + npp_add_aij(npp, p, q, +1.0);
252.982 + npp_add_aij(npp, p, s, +1.0);
252.983 + /* create transformation stack entry */
252.984 + info = npp_push_tse(npp,
252.985 + rcv_dbnd_col, sizeof(struct dbnd_col));
252.986 + info->q = q->j;
252.987 + info->s = s->j;
252.988 + /* remove upper bound of x[q] */
252.989 + q->ub = +DBL_MAX;
252.990 + return;
252.991 +}
252.992 +
252.993 +static int rcv_dbnd_col(NPP *npp, void *_info)
252.994 +{ /* recover non-negative column with upper bound */
252.995 + struct dbnd_col *info = _info;
252.996 + if (npp->sol == GLP_BS)
252.997 + { if (npp->c_stat[info->q] == GLP_BS)
252.998 + { if (npp->c_stat[info->s] == GLP_BS)
252.999 + npp->c_stat[info->q] = GLP_BS;
252.1000 + else if (npp->c_stat[info->s] == GLP_NL)
252.1001 + npp->c_stat[info->q] = GLP_NU;
252.1002 + else
252.1003 + { npp_error();
252.1004 + return 1;
252.1005 + }
252.1006 + }
252.1007 + else if (npp->c_stat[info->q] == GLP_NL)
252.1008 + { if (npp->c_stat[info->s] == GLP_BS ||
252.1009 + npp->c_stat[info->s] == GLP_NL)
252.1010 + npp->c_stat[info->q] = GLP_NL;
252.1011 + else
252.1012 + { npp_error();
252.1013 + return 1;
252.1014 + }
252.1015 + }
252.1016 + else
252.1017 + { npp_error();
252.1018 + return 1;
252.1019 + }
252.1020 + }
252.1021 + return 0;
252.1022 +}
252.1023 +
252.1024 +/***********************************************************************
252.1025 +* NAME
252.1026 +*
252.1027 +* npp_fixed_col - process fixed column
252.1028 +*
252.1029 +* SYNOPSIS
252.1030 +*
252.1031 +* #include "glpnpp.h"
252.1032 +* void npp_fixed_col(NPP *npp, NPPCOL *q);
252.1033 +*
252.1034 +* DESCRIPTION
252.1035 +*
252.1036 +* The routine npp_fixed_col processes column q, which is fixed:
252.1037 +*
252.1038 +* x[q] = s[q], (1)
252.1039 +*
252.1040 +* where s[q] is a fixed column value.
252.1041 +*
252.1042 +* PROBLEM TRANSFORMATION
252.1043 +*
252.1044 +* The value of a fixed column can be substituted into the objective
252.1045 +* and constraint rows that allows removing the column from the problem.
252.1046 +*
252.1047 +* Substituting x[q] = s[q] into the objective row, we have:
252.1048 +*
252.1049 +* z = sum c[j] x[j] + c0 =
252.1050 +* j
252.1051 +*
252.1052 +* = sum c[j] x[j] + c[q] x[q] + c0 =
252.1053 +* j!=q
252.1054 +*
252.1055 +* = sum c[j] x[j] + c[q] s[q] + c0 =
252.1056 +* j!=q
252.1057 +*
252.1058 +* = sum c[j] x[j] + c~0,
252.1059 +* j!=q
252.1060 +*
252.1061 +* where
252.1062 +*
252.1063 +* c~0 = c0 + c[q] s[q] (2)
252.1064 +*
252.1065 +* is the constant term of the objective in the transformed problem.
252.1066 +* Similarly, substituting x[q] = s[q] into constraint row i, we have:
252.1067 +*
252.1068 +* L[i] <= sum a[i,j] x[j] <= U[i] ==>
252.1069 +* j
252.1070 +*
252.1071 +* L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
252.1072 +* j!=q
252.1073 +*
252.1074 +* L[i] <= sum a[i,j] x[j] + a[i,q] s[q] <= U[i] ==>
252.1075 +* j!=q
252.1076 +*
252.1077 +* L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
252.1078 +* j!=q
252.1079 +*
252.1080 +* where
252.1081 +*
252.1082 +* L~[i] = L[i] - a[i,q] s[q], U~[i] = U[i] - a[i,q] s[q] (3)
252.1083 +*
252.1084 +* are lower and upper bounds of row i in the transformed problem,
252.1085 +* resp.
252.1086 +*
252.1087 +* RECOVERING BASIC SOLUTION
252.1088 +*
252.1089 +* Column q is assigned status GLP_NS and its value is assigned s[q].
252.1090 +*
252.1091 +* RECOVERING INTERIOR-POINT SOLUTION
252.1092 +*
252.1093 +* Value of column q is assigned s[q].
252.1094 +*
252.1095 +* RECOVERING MIP SOLUTION
252.1096 +*
252.1097 +* Value of column q is assigned s[q]. */
252.1098 +
252.1099 +struct fixed_col
252.1100 +{ /* fixed column */
252.1101 + int q;
252.1102 + /* column reference number for variable x[q] */
252.1103 + double s;
252.1104 + /* value, at which x[q] is fixed */
252.1105 +};
252.1106 +
252.1107 +static int rcv_fixed_col(NPP *npp, void *info);
252.1108 +
252.1109 +void npp_fixed_col(NPP *npp, NPPCOL *q)
252.1110 +{ /* process fixed column */
252.1111 + struct fixed_col *info;
252.1112 + NPPROW *i;
252.1113 + NPPAIJ *aij;
252.1114 + /* the column must be fixed */
252.1115 + xassert(q->lb == q->ub);
252.1116 + /* create transformation stack entry */
252.1117 + info = npp_push_tse(npp,
252.1118 + rcv_fixed_col, sizeof(struct fixed_col));
252.1119 + info->q = q->j;
252.1120 + info->s = q->lb;
252.1121 + /* substitute x[q] = s[q] into objective row */
252.1122 + npp->c0 += q->coef * q->lb;
252.1123 + /* substitute x[q] = s[q] into constraint rows */
252.1124 + for (aij = q->ptr; aij != NULL; aij = aij->c_next)
252.1125 + { i = aij->row;
252.1126 + if (i->lb == i->ub)
252.1127 + i->ub = (i->lb -= aij->val * q->lb);
252.1128 + else
252.1129 + { if (i->lb != -DBL_MAX)
252.1130 + i->lb -= aij->val * q->lb;
252.1131 + if (i->ub != +DBL_MAX)
252.1132 + i->ub -= aij->val * q->lb;
252.1133 + }
252.1134 + }
252.1135 + /* remove the column from the problem */
252.1136 + npp_del_col(npp, q);
252.1137 + return;
252.1138 +}
252.1139 +
252.1140 +static int rcv_fixed_col(NPP *npp, void *_info)
252.1141 +{ /* recover fixed column */
252.1142 + struct fixed_col *info = _info;
252.1143 + if (npp->sol == GLP_SOL)
252.1144 + npp->c_stat[info->q] = GLP_NS;
252.1145 + npp->c_value[info->q] = info->s;
252.1146 + return 0;
252.1147 +}
252.1148 +
252.1149 +/***********************************************************************
252.1150 +* NAME
252.1151 +*
252.1152 +* npp_make_equality - process row with almost identical bounds
252.1153 +*
252.1154 +* SYNOPSIS
252.1155 +*
252.1156 +* #include "glpnpp.h"
252.1157 +* int npp_make_equality(NPP *npp, NPPROW *p);
252.1158 +*
252.1159 +* DESCRIPTION
252.1160 +*
252.1161 +* The routine npp_make_equality processes row p:
252.1162 +*
252.1163 +* L[p] <= sum a[p,j] x[j] <= U[p], (1)
252.1164 +* j
252.1165 +*
252.1166 +* where -oo < L[p] < U[p] < +oo, i.e. which is double-sided inequality
252.1167 +* constraint.
252.1168 +*
252.1169 +* RETURNS
252.1170 +*
252.1171 +* 0 - row bounds have not been changed;
252.1172 +*
252.1173 +* 1 - row has been replaced by equality constraint.
252.1174 +*
252.1175 +* PROBLEM TRANSFORMATION
252.1176 +*
252.1177 +* If bounds of row (1) are very close to each other:
252.1178 +*
252.1179 +* U[p] - L[p] <= eps, (2)
252.1180 +*
252.1181 +* where eps is an absolute tolerance for row value, the row can be
252.1182 +* replaced by the following almost equivalent equiality constraint:
252.1183 +*
252.1184 +* sum a[p,j] x[j] = b, (3)
252.1185 +* j
252.1186 +*
252.1187 +* where b = (L[p] + U[p]) / 2. If the right-hand side in (3) happens
252.1188 +* to be very close to its nearest integer:
252.1189 +*
252.1190 +* |b - floor(b + 0.5)| <= eps, (4)
252.1191 +*
252.1192 +* it is reasonable to use this nearest integer as the right-hand side.
252.1193 +*
252.1194 +* RECOVERING BASIC SOLUTION
252.1195 +*
252.1196 +* Status of row p in solution to the original problem is determined
252.1197 +* by its status and the sign of its multiplier pi[p] in solution to
252.1198 +* the transformed problem as follows:
252.1199 +*
252.1200 +* +-----------------------+---------+--------------------+
252.1201 +* | Status of row p | Sign of | Status of row p |
252.1202 +* | (transformed problem) | pi[p] | (original problem) |
252.1203 +* +-----------------------+---------+--------------------+
252.1204 +* | GLP_BS | + / - | GLP_BS |
252.1205 +* | GLP_NS | + | GLP_NL |
252.1206 +* | GLP_NS | - | GLP_NU |
252.1207 +* +-----------------------+---------+--------------------+
252.1208 +*
252.1209 +* Value of row multiplier pi[p] in solution to the original problem is
252.1210 +* the same as in solution to the transformed problem.
252.1211 +*
252.1212 +* RECOVERING INTERIOR POINT SOLUTION
252.1213 +*
252.1214 +* Value of row multiplier pi[p] in solution to the original problem is
252.1215 +* the same as in solution to the transformed problem.
252.1216 +*
252.1217 +* RECOVERING MIP SOLUTION
252.1218 +*
252.1219 +* None needed. */
252.1220 +
252.1221 +struct make_equality
252.1222 +{ /* row with almost identical bounds */
252.1223 + int p;
252.1224 + /* row reference number */
252.1225 +};
252.1226 +
252.1227 +static int rcv_make_equality(NPP *npp, void *info);
252.1228 +
252.1229 +int npp_make_equality(NPP *npp, NPPROW *p)
252.1230 +{ /* process row with almost identical bounds */
252.1231 + struct make_equality *info;
252.1232 + double b, eps, nint;
252.1233 + /* the row must be double-sided inequality */
252.1234 + xassert(p->lb != -DBL_MAX);
252.1235 + xassert(p->ub != +DBL_MAX);
252.1236 + xassert(p->lb < p->ub);
252.1237 + /* check row bounds */
252.1238 + eps = 1e-9 + 1e-12 * fabs(p->lb);
252.1239 + if (p->ub - p->lb > eps) return 0;
252.1240 + /* row bounds are very close to each other */
252.1241 + /* create transformation stack entry */
252.1242 + info = npp_push_tse(npp,
252.1243 + rcv_make_equality, sizeof(struct make_equality));
252.1244 + info->p = p->i;
252.1245 + /* compute right-hand side */
252.1246 + b = 0.5 * (p->ub + p->lb);
252.1247 + nint = floor(b + 0.5);
252.1248 + if (fabs(b - nint) <= eps) b = nint;
252.1249 + /* replace row p by almost equivalent equality constraint */
252.1250 + p->lb = p->ub = b;
252.1251 + return 1;
252.1252 +}
252.1253 +
252.1254 +int rcv_make_equality(NPP *npp, void *_info)
252.1255 +{ /* recover row with almost identical bounds */
252.1256 + struct make_equality *info = _info;
252.1257 + if (npp->sol == GLP_SOL)
252.1258 + { if (npp->r_stat[info->p] == GLP_BS)
252.1259 + npp->r_stat[info->p] = GLP_BS;
252.1260 + else if (npp->r_stat[info->p] == GLP_NS)
252.1261 + { if (npp->r_pi[info->p] >= 0.0)
252.1262 + npp->r_stat[info->p] = GLP_NL;
252.1263 + else
252.1264 + npp->r_stat[info->p] = GLP_NU;
252.1265 + }
252.1266 + else
252.1267 + { npp_error();
252.1268 + return 1;
252.1269 + }
252.1270 + }
252.1271 + return 0;
252.1272 +}
252.1273 +
252.1274 +/***********************************************************************
252.1275 +* NAME
252.1276 +*
252.1277 +* npp_make_fixed - process column with almost identical bounds
252.1278 +*
252.1279 +* SYNOPSIS
252.1280 +*
252.1281 +* #include "glpnpp.h"
252.1282 +* int npp_make_fixed(NPP *npp, NPPCOL *q);
252.1283 +*
252.1284 +* DESCRIPTION
252.1285 +*
252.1286 +* The routine npp_make_fixed processes column q:
252.1287 +*
252.1288 +* l[q] <= x[q] <= u[q], (1)
252.1289 +*
252.1290 +* where -oo < l[q] < u[q] < +oo, i.e. which has both lower and upper
252.1291 +* bounds.
252.1292 +*
252.1293 +* RETURNS
252.1294 +*
252.1295 +* 0 - column bounds have not been changed;
252.1296 +*
252.1297 +* 1 - column has been fixed.
252.1298 +*
252.1299 +* PROBLEM TRANSFORMATION
252.1300 +*
252.1301 +* If bounds of column (1) are very close to each other:
252.1302 +*
252.1303 +* u[q] - l[q] <= eps, (2)
252.1304 +*
252.1305 +* where eps is an absolute tolerance for column value, the column can
252.1306 +* be fixed:
252.1307 +*
252.1308 +* x[q] = s[q], (3)
252.1309 +*
252.1310 +* where s[q] = (l[q] + u[q]) / 2. And if the fixed column value s[q]
252.1311 +* happens to be very close to its nearest integer:
252.1312 +*
252.1313 +* |s[q] - floor(s[q] + 0.5)| <= eps, (4)
252.1314 +*
252.1315 +* it is reasonable to use this nearest integer as the fixed value.
252.1316 +*
252.1317 +* RECOVERING BASIC SOLUTION
252.1318 +*
252.1319 +* In the dual system of the original (as well as transformed) problem
252.1320 +* column q corresponds to the following row:
252.1321 +*
252.1322 +* sum a[i,q] pi[i] + lambda[q] = c[q]. (5)
252.1323 +* i
252.1324 +*
252.1325 +* Since multipliers pi[i] are known for all rows from solution to the
252.1326 +* transformed problem, formula (5) allows computing value of multiplier
252.1327 +* (reduced cost) for column q:
252.1328 +*
252.1329 +* lambda[q] = c[q] - sum a[i,q] pi[i]. (6)
252.1330 +* i
252.1331 +*
252.1332 +* Status of column q in solution to the original problem is determined
252.1333 +* by its status and the sign of its multiplier lambda[q] in solution to
252.1334 +* the transformed problem as follows:
252.1335 +*
252.1336 +* +-----------------------+-----------+--------------------+
252.1337 +* | Status of column q | Sign of | Status of column q |
252.1338 +* | (transformed problem) | lambda[q] | (original problem) |
252.1339 +* +-----------------------+-----------+--------------------+
252.1340 +* | GLP_BS | + / - | GLP_BS |
252.1341 +* | GLP_NS | + | GLP_NL |
252.1342 +* | GLP_NS | - | GLP_NU |
252.1343 +* +-----------------------+-----------+--------------------+
252.1344 +*
252.1345 +* Value of column q in solution to the original problem is the same as
252.1346 +* in solution to the transformed problem.
252.1347 +*
252.1348 +* RECOVERING INTERIOR POINT SOLUTION
252.1349 +*
252.1350 +* Value of column q in solution to the original problem is the same as
252.1351 +* in solution to the transformed problem.
252.1352 +*
252.1353 +* RECOVERING MIP SOLUTION
252.1354 +*
252.1355 +* None needed. */
252.1356 +
252.1357 +struct make_fixed
252.1358 +{ /* column with almost identical bounds */
252.1359 + int q;
252.1360 + /* column reference number */
252.1361 + double c;
252.1362 + /* objective coefficient at x[q] */
252.1363 + NPPLFE *ptr;
252.1364 + /* list of non-zero coefficients a[i,q] */
252.1365 +};
252.1366 +
252.1367 +static int rcv_make_fixed(NPP *npp, void *info);
252.1368 +
252.1369 +int npp_make_fixed(NPP *npp, NPPCOL *q)
252.1370 +{ /* process column with almost identical bounds */
252.1371 + struct make_fixed *info;
252.1372 + NPPAIJ *aij;
252.1373 + NPPLFE *lfe;
252.1374 + double s, eps, nint;
252.1375 + /* the column must be double-bounded */
252.1376 + xassert(q->lb != -DBL_MAX);
252.1377 + xassert(q->ub != +DBL_MAX);
252.1378 + xassert(q->lb < q->ub);
252.1379 + /* check column bounds */
252.1380 + eps = 1e-9 + 1e-12 * fabs(q->lb);
252.1381 + if (q->ub - q->lb > eps) return 0;
252.1382 + /* column bounds are very close to each other */
252.1383 + /* create transformation stack entry */
252.1384 + info = npp_push_tse(npp,
252.1385 + rcv_make_fixed, sizeof(struct make_fixed));
252.1386 + info->q = q->j;
252.1387 + info->c = q->coef;
252.1388 + info->ptr = NULL;
252.1389 + /* save column coefficients a[i,q] (needed for basic solution
252.1390 + only) */
252.1391 + if (npp->sol == GLP_SOL)
252.1392 + { for (aij = q->ptr; aij != NULL; aij = aij->c_next)
252.1393 + { lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
252.1394 + lfe->ref = aij->row->i;
252.1395 + lfe->val = aij->val;
252.1396 + lfe->next = info->ptr;
252.1397 + info->ptr = lfe;
252.1398 + }
252.1399 + }
252.1400 + /* compute column fixed value */
252.1401 + s = 0.5 * (q->ub + q->lb);
252.1402 + nint = floor(s + 0.5);
252.1403 + if (fabs(s - nint) <= eps) s = nint;
252.1404 + /* make column q fixed */
252.1405 + q->lb = q->ub = s;
252.1406 + return 1;
252.1407 +}
252.1408 +
252.1409 +static int rcv_make_fixed(NPP *npp, void *_info)
252.1410 +{ /* recover column with almost identical bounds */
252.1411 + struct make_fixed *info = _info;
252.1412 + NPPLFE *lfe;
252.1413 + double lambda;
252.1414 + if (npp->sol == GLP_SOL)
252.1415 + { if (npp->c_stat[info->q] == GLP_BS)
252.1416 + npp->c_stat[info->q] = GLP_BS;
252.1417 + else if (npp->c_stat[info->q] == GLP_NS)
252.1418 + { /* compute multiplier for column q with formula (6) */
252.1419 + lambda = info->c;
252.1420 + for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
252.1421 + lambda -= lfe->val * npp->r_pi[lfe->ref];
252.1422 + /* assign status to non-basic column */
252.1423 + if (lambda >= 0.0)
252.1424 + npp->c_stat[info->q] = GLP_NL;
252.1425 + else
252.1426 + npp->c_stat[info->q] = GLP_NU;
252.1427 + }
252.1428 + else
252.1429 + { npp_error();
252.1430 + return 1;
252.1431 + }
252.1432 + }
252.1433 + return 0;
252.1434 +}
252.1435 +
252.1436 +/* eof */
253.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
253.2 +++ b/src/glpnpp03.c Mon Dec 06 13:09:21 2010 +0100
253.3 @@ -0,0 +1,2861 @@
253.4 +/* glpnpp03.c */
253.5 +
253.6 +/***********************************************************************
253.7 +* This code is part of GLPK (GNU Linear Programming Kit).
253.8 +*
253.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
253.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
253.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
253.12 +* E-mail: <mao@gnu.org>.
253.13 +*
253.14 +* GLPK is free software: you can redistribute it and/or modify it
253.15 +* under the terms of the GNU General Public License as published by
253.16 +* the Free Software Foundation, either version 3 of the License, or
253.17 +* (at your option) any later version.
253.18 +*
253.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
253.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
253.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
253.22 +* License for more details.
253.23 +*
253.24 +* You should have received a copy of the GNU General Public License
253.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
253.26 +***********************************************************************/
253.27 +
253.28 +#include "glpnpp.h"
253.29 +
253.30 +/***********************************************************************
253.31 +* NAME
253.32 +*
253.33 +* npp_empty_row - process empty row
253.34 +*
253.35 +* SYNOPSIS
253.36 +*
253.37 +* #include "glpnpp.h"
253.38 +* int npp_empty_row(NPP *npp, NPPROW *p);
253.39 +*
253.40 +* DESCRIPTION
253.41 +*
253.42 +* The routine npp_empty_row processes row p, which is empty, i.e.
253.43 +* coefficients at all columns in this row are zero:
253.44 +*
253.45 +* L[p] <= sum 0 x[j] <= U[p], (1)
253.46 +*
253.47 +* where L[p] <= U[p].
253.48 +*
253.49 +* RETURNS
253.50 +*
253.51 +* 0 - success;
253.52 +*
253.53 +* 1 - problem has no primal feasible solution.
253.54 +*
253.55 +* PROBLEM TRANSFORMATION
253.56 +*
253.57 +* If the following conditions hold:
253.58 +*
253.59 +* L[p] <= +eps, U[p] >= -eps, (2)
253.60 +*
253.61 +* where eps is an absolute tolerance for row value, the row p is
253.62 +* redundant. In this case it can be replaced by equivalent redundant
253.63 +* row, which is free (unbounded), and then removed from the problem.
253.64 +* Otherwise, the row p is infeasible and, thus, the problem has no
253.65 +* primal feasible solution.
253.66 +*
253.67 +* RECOVERING BASIC SOLUTION
253.68 +*
253.69 +* See the routine npp_free_row.
253.70 +*
253.71 +* RECOVERING INTERIOR-POINT SOLUTION
253.72 +*
253.73 +* See the routine npp_free_row.
253.74 +*
253.75 +* RECOVERING MIP SOLUTION
253.76 +*
253.77 +* None needed. */
253.78 +
253.79 +int npp_empty_row(NPP *npp, NPPROW *p)
253.80 +{ /* process empty row */
253.81 + double eps = 1e-3;
253.82 + /* the row must be empty */
253.83 + xassert(p->ptr == NULL);
253.84 + /* check primal feasibility */
253.85 + if (p->lb > +eps || p->ub < -eps)
253.86 + return 1;
253.87 + /* replace the row by equivalent free (unbounded) row */
253.88 + p->lb = -DBL_MAX, p->ub = +DBL_MAX;
253.89 + /* and process it */
253.90 + npp_free_row(npp, p);
253.91 + return 0;
253.92 +}
253.93 +
253.94 +/***********************************************************************
253.95 +* NAME
253.96 +*
253.97 +* npp_empty_col - process empty column
253.98 +*
253.99 +* SYNOPSIS
253.100 +*
253.101 +* #include "glpnpp.h"
253.102 +* int npp_empty_col(NPP *npp, NPPCOL *q);
253.103 +*
253.104 +* DESCRIPTION
253.105 +*
253.106 +* The routine npp_empty_col processes column q:
253.107 +*
253.108 +* l[q] <= x[q] <= u[q], (1)
253.109 +*
253.110 +* where l[q] <= u[q], which is empty, i.e. has zero coefficients in
253.111 +* all constraint rows.
253.112 +*
253.113 +* RETURNS
253.114 +*
253.115 +* 0 - success;
253.116 +*
253.117 +* 1 - problem has no dual feasible solution.
253.118 +*
253.119 +* PROBLEM TRANSFORMATION
253.120 +*
253.121 +* The row of the dual system corresponding to the empty column is the
253.122 +* following:
253.123 +*
253.124 +* sum 0 pi[i] + lambda[q] = c[q], (2)
253.125 +* i
253.126 +*
253.127 +* from which it follows that:
253.128 +*
253.129 +* lambda[q] = c[q]. (3)
253.130 +*
253.131 +* If the following condition holds:
253.132 +*
253.133 +* c[q] < - eps, (4)
253.134 +*
253.135 +* where eps is an absolute tolerance for column multiplier, the lower
253.136 +* column bound l[q] must be active to provide dual feasibility (note
253.137 +* that being preprocessed the problem is always minimization). In this
253.138 +* case the column can be fixed on its lower bound and removed from the
253.139 +* problem (if the column is integral, its bounds are also assumed to
253.140 +* be integral). And if the column has no lower bound (l[q] = -oo), the
253.141 +* problem has no dual feasible solution.
253.142 +*
253.143 +* If the following condition holds:
253.144 +*
253.145 +* c[q] > + eps, (5)
253.146 +*
253.147 +* the upper column bound u[q] must be active to provide dual
253.148 +* feasibility. In this case the column can be fixed on its upper bound
253.149 +* and removed from the problem. And if the column has no upper bound
253.150 +* (u[q] = +oo), the problem has no dual feasible solution.
253.151 +*
253.152 +* Finally, if the following condition holds:
253.153 +*
253.154 +* - eps <= c[q] <= +eps, (6)
253.155 +*
253.156 +* dual feasibility does not depend on a particular value of column q.
253.157 +* In this case the column can be fixed either on its lower bound (if
253.158 +* l[q] > -oo) or on its upper bound (if u[q] < +oo) or at zero (if the
253.159 +* column is unbounded) and then removed from the problem.
253.160 +*
253.161 +* RECOVERING BASIC SOLUTION
253.162 +*
253.163 +* See the routine npp_fixed_col. Having been recovered the column
253.164 +* is assigned status GLP_NS. However, if actually it is not fixed
253.165 +* (l[q] < u[q]), its status should be changed to GLP_NL, GLP_NU, or
253.166 +* GLP_NF depending on which bound it was fixed on transformation stage.
253.167 +*
253.168 +* RECOVERING INTERIOR-POINT SOLUTION
253.169 +*
253.170 +* See the routine npp_fixed_col.
253.171 +*
253.172 +* RECOVERING MIP SOLUTION
253.173 +*
253.174 +* See the routine npp_fixed_col. */
253.175 +
253.176 +struct empty_col
253.177 +{ /* empty column */
253.178 + int q;
253.179 + /* column reference number */
253.180 + char stat;
253.181 + /* status in basic solution */
253.182 +};
253.183 +
253.184 +static int rcv_empty_col(NPP *npp, void *info);
253.185 +
253.186 +int npp_empty_col(NPP *npp, NPPCOL *q)
253.187 +{ /* process empty column */
253.188 + struct empty_col *info;
253.189 + double eps = 1e-3;
253.190 + /* the column must be empty */
253.191 + xassert(q->ptr == NULL);
253.192 + /* check dual feasibility */
253.193 + if (q->coef > +eps && q->lb == -DBL_MAX)
253.194 + return 1;
253.195 + if (q->coef < -eps && q->ub == +DBL_MAX)
253.196 + return 1;
253.197 + /* create transformation stack entry */
253.198 + info = npp_push_tse(npp,
253.199 + rcv_empty_col, sizeof(struct empty_col));
253.200 + info->q = q->j;
253.201 + /* fix the column */
253.202 + if (q->lb == -DBL_MAX && q->ub == +DBL_MAX)
253.203 + { /* free column */
253.204 + info->stat = GLP_NF;
253.205 + q->lb = q->ub = 0.0;
253.206 + }
253.207 + else if (q->ub == +DBL_MAX)
253.208 +lo: { /* column with lower bound */
253.209 + info->stat = GLP_NL;
253.210 + q->ub = q->lb;
253.211 + }
253.212 + else if (q->lb == -DBL_MAX)
253.213 +up: { /* column with upper bound */
253.214 + info->stat = GLP_NU;
253.215 + q->lb = q->ub;
253.216 + }
253.217 + else if (q->lb != q->ub)
253.218 + { /* double-bounded column */
253.219 + if (q->coef >= +DBL_EPSILON) goto lo;
253.220 + if (q->coef <= -DBL_EPSILON) goto up;
253.221 + if (fabs(q->lb) <= fabs(q->ub)) goto lo; else goto up;
253.222 + }
253.223 + else
253.224 + { /* fixed column */
253.225 + info->stat = GLP_NS;
253.226 + }
253.227 + /* process fixed column */
253.228 + npp_fixed_col(npp, q);
253.229 + return 0;
253.230 +}
253.231 +
253.232 +static int rcv_empty_col(NPP *npp, void *_info)
253.233 +{ /* recover empty column */
253.234 + struct empty_col *info = _info;
253.235 + if (npp->sol == GLP_SOL)
253.236 + npp->c_stat[info->q] = info->stat;
253.237 + return 0;
253.238 +}
253.239 +
253.240 +/***********************************************************************
253.241 +* NAME
253.242 +*
253.243 +* npp_implied_value - process implied column value
253.244 +*
253.245 +* SYNOPSIS
253.246 +*
253.247 +* #include "glpnpp.h"
253.248 +* int npp_implied_value(NPP *npp, NPPCOL *q, double s);
253.249 +*
253.250 +* DESCRIPTION
253.251 +*
253.252 +* For column q:
253.253 +*
253.254 +* l[q] <= x[q] <= u[q], (1)
253.255 +*
253.256 +* where l[q] < u[q], the routine npp_implied_value processes its
253.257 +* implied value s[q]. If this implied value satisfies to the current
253.258 +* column bounds and integrality condition, the routine fixes column q
253.259 +* at the given point. Note that the column is kept in the problem in
253.260 +* any case.
253.261 +*
253.262 +* RETURNS
253.263 +*
253.264 +* 0 - column has been fixed;
253.265 +*
253.266 +* 1 - implied value violates to current column bounds;
253.267 +*
253.268 +* 2 - implied value violates integrality condition.
253.269 +*
253.270 +* ALGORITHM
253.271 +*
253.272 +* Implied column value s[q] satisfies to the current column bounds if
253.273 +* the following condition holds:
253.274 +*
253.275 +* l[q] - eps <= s[q] <= u[q] + eps, (2)
253.276 +*
253.277 +* where eps is an absolute tolerance for column value. If the column
253.278 +* is integral, the following condition also must hold:
253.279 +*
253.280 +* |s[q] - floor(s[q]+0.5)| <= eps, (3)
253.281 +*
253.282 +* where floor(s[q]+0.5) is the nearest integer to s[q].
253.283 +*
253.284 +* If both condition (2) and (3) are satisfied, the column can be fixed
253.285 +* at the value s[q], or, if it is integral, at floor(s[q]+0.5).
253.286 +* Otherwise, if s[q] violates (2) or (3), the problem has no feasible
253.287 +* solution.
253.288 +*
253.289 +* Note: If s[q] is close to l[q] or u[q], it seems to be reasonable to
253.290 +* fix the column at its lower or upper bound, resp. rather than at the
253.291 +* implied value. */
253.292 +
253.293 +int npp_implied_value(NPP *npp, NPPCOL *q, double s)
253.294 +{ /* process implied column value */
253.295 + double eps, nint;
253.296 + xassert(npp == npp);
253.297 + /* column must not be fixed */
253.298 + xassert(q->lb < q->ub);
253.299 + /* check integrality */
253.300 + if (q->is_int)
253.301 + { nint = floor(s + 0.5);
253.302 + if (fabs(s - nint) <= 1e-5)
253.303 + s = nint;
253.304 + else
253.305 + return 2;
253.306 + }
253.307 + /* check current column lower bound */
253.308 + if (q->lb != -DBL_MAX)
253.309 + { eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->lb));
253.310 + if (s < q->lb - eps) return 1;
253.311 + /* if s[q] is close to l[q], fix column at its lower bound
253.312 + rather than at the implied value */
253.313 + if (s < q->lb + 1e-3 * eps)
253.314 + { q->ub = q->lb;
253.315 + return 0;
253.316 + }
253.317 + }
253.318 + /* check current column upper bound */
253.319 + if (q->ub != +DBL_MAX)
253.320 + { eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->ub));
253.321 + if (s > q->ub + eps) return 1;
253.322 + /* if s[q] is close to u[q], fix column at its upper bound
253.323 + rather than at the implied value */
253.324 + if (s > q->ub - 1e-3 * eps)
253.325 + { q->lb = q->ub;
253.326 + return 0;
253.327 + }
253.328 + }
253.329 + /* fix column at the implied value */
253.330 + q->lb = q->ub = s;
253.331 + return 0;
253.332 +}
253.333 +
253.334 +/***********************************************************************
253.335 +* NAME
253.336 +*
253.337 +* npp_eq_singlet - process row singleton (equality constraint)
253.338 +*
253.339 +* SYNOPSIS
253.340 +*
253.341 +* #include "glpnpp.h"
253.342 +* int npp_eq_singlet(NPP *npp, NPPROW *p);
253.343 +*
253.344 +* DESCRIPTION
253.345 +*
253.346 +* The routine npp_eq_singlet processes row p, which is equiality
253.347 +* constraint having the only non-zero coefficient:
253.348 +*
253.349 +* a[p,q] x[q] = b. (1)
253.350 +*
253.351 +* RETURNS
253.352 +*
253.353 +* 0 - success;
253.354 +*
253.355 +* 1 - problem has no primal feasible solution;
253.356 +*
253.357 +* 2 - problem has no integer feasible solution.
253.358 +*
253.359 +* PROBLEM TRANSFORMATION
253.360 +*
253.361 +* The equality constraint defines implied value of column q:
253.362 +*
253.363 +* x[q] = s[q] = b / a[p,q]. (2)
253.364 +*
253.365 +* If the implied value s[q] satisfies to the column bounds (see the
253.366 +* routine npp_implied_value), the column can be fixed at s[q] and
253.367 +* removed from the problem. In this case row p becomes redundant, so
253.368 +* it can be replaced by equivalent free row and also removed from the
253.369 +* problem.
253.370 +*
253.371 +* Note that the routine removes from the problem only row p. Column q
253.372 +* becomes fixed, however, it is kept in the problem.
253.373 +*
253.374 +* RECOVERING BASIC SOLUTION
253.375 +*
253.376 +* In solution to the original problem row p is assigned status GLP_NS
253.377 +* (active equality constraint), and column q is assigned status GLP_BS
253.378 +* (basic column).
253.379 +*
253.380 +* Multiplier for row p can be computed as follows. In the dual system
253.381 +* of the original problem column q corresponds to the following row:
253.382 +*
253.383 +* sum a[i,q] pi[i] + lambda[q] = c[q] ==>
253.384 +* i
253.385 +*
253.386 +* sum a[i,q] pi[i] + a[p,q] pi[p] + lambda[q] = c[q].
253.387 +* i!=p
253.388 +*
253.389 +* Therefore:
253.390 +*
253.391 +* 1
253.392 +* pi[p] = ------ (c[q] - lambda[q] - sum a[i,q] pi[i]), (3)
253.393 +* a[p,q] i!=q
253.394 +*
253.395 +* where lambda[q] = 0 (since column[q] is basic), and pi[i] for all
253.396 +* i != p are known in solution to the transformed problem.
253.397 +*
253.398 +* Value of column q in solution to the original problem is assigned
253.399 +* its implied value s[q].
253.400 +*
253.401 +* RECOVERING INTERIOR-POINT SOLUTION
253.402 +*
253.403 +* Multiplier for row p is computed with formula (3). Value of column
253.404 +* q is assigned its implied value s[q].
253.405 +*
253.406 +* RECOVERING MIP SOLUTION
253.407 +*
253.408 +* Value of column q is assigned its implied value s[q]. */
253.409 +
253.410 +struct eq_singlet
253.411 +{ /* row singleton (equality constraint) */
253.412 + int p;
253.413 + /* row reference number */
253.414 + int q;
253.415 + /* column reference number */
253.416 + double apq;
253.417 + /* constraint coefficient a[p,q] */
253.418 + double c;
253.419 + /* objective coefficient at x[q] */
253.420 + NPPLFE *ptr;
253.421 + /* list of non-zero coefficients a[i,q], i != p */
253.422 +};
253.423 +
253.424 +static int rcv_eq_singlet(NPP *npp, void *info);
253.425 +
253.426 +int npp_eq_singlet(NPP *npp, NPPROW *p)
253.427 +{ /* process row singleton (equality constraint) */
253.428 + struct eq_singlet *info;
253.429 + NPPCOL *q;
253.430 + NPPAIJ *aij;
253.431 + NPPLFE *lfe;
253.432 + int ret;
253.433 + double s;
253.434 + /* the row must be singleton equality constraint */
253.435 + xassert(p->lb == p->ub);
253.436 + xassert(p->ptr != NULL && p->ptr->r_next == NULL);
253.437 + /* compute and process implied column value */
253.438 + aij = p->ptr;
253.439 + q = aij->col;
253.440 + s = p->lb / aij->val;
253.441 + ret = npp_implied_value(npp, q, s);
253.442 + xassert(0 <= ret && ret <= 2);
253.443 + if (ret != 0) return ret;
253.444 + /* create transformation stack entry */
253.445 + info = npp_push_tse(npp,
253.446 + rcv_eq_singlet, sizeof(struct eq_singlet));
253.447 + info->p = p->i;
253.448 + info->q = q->j;
253.449 + info->apq = aij->val;
253.450 + info->c = q->coef;
253.451 + info->ptr = NULL;
253.452 + /* save column coefficients a[i,q], i != p (not needed for MIP
253.453 + solution) */
253.454 + if (npp->sol != GLP_MIP)
253.455 + { for (aij = q->ptr; aij != NULL; aij = aij->c_next)
253.456 + { if (aij->row == p) continue; /* skip a[p,q] */
253.457 + lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
253.458 + lfe->ref = aij->row->i;
253.459 + lfe->val = aij->val;
253.460 + lfe->next = info->ptr;
253.461 + info->ptr = lfe;
253.462 + }
253.463 + }
253.464 + /* remove the row from the problem */
253.465 + npp_del_row(npp, p);
253.466 + return 0;
253.467 +}
253.468 +
253.469 +static int rcv_eq_singlet(NPP *npp, void *_info)
253.470 +{ /* recover row singleton (equality constraint) */
253.471 + struct eq_singlet *info = _info;
253.472 + NPPLFE *lfe;
253.473 + double temp;
253.474 + if (npp->sol == GLP_SOL)
253.475 + { /* column q must be already recovered as GLP_NS */
253.476 + if (npp->c_stat[info->q] != GLP_NS)
253.477 + { npp_error();
253.478 + return 1;
253.479 + }
253.480 + npp->r_stat[info->p] = GLP_NS;
253.481 + npp->c_stat[info->q] = GLP_BS;
253.482 + }
253.483 + if (npp->sol != GLP_MIP)
253.484 + { /* compute multiplier for row p with formula (3) */
253.485 + temp = info->c;
253.486 + for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
253.487 + temp -= lfe->val * npp->r_pi[lfe->ref];
253.488 + npp->r_pi[info->p] = temp / info->apq;
253.489 + }
253.490 + return 0;
253.491 +}
253.492 +
253.493 +/***********************************************************************
253.494 +* NAME
253.495 +*
253.496 +* npp_implied_lower - process implied column lower bound
253.497 +*
253.498 +* SYNOPSIS
253.499 +*
253.500 +* #include "glpnpp.h"
253.501 +* int npp_implied_lower(NPP *npp, NPPCOL *q, double l);
253.502 +*
253.503 +* DESCRIPTION
253.504 +*
253.505 +* For column q:
253.506 +*
253.507 +* l[q] <= x[q] <= u[q], (1)
253.508 +*
253.509 +* where l[q] < u[q], the routine npp_implied_lower processes its
253.510 +* implied lower bound l'[q]. As the result the current column lower
253.511 +* bound may increase. Note that the column is kept in the problem in
253.512 +* any case.
253.513 +*
253.514 +* RETURNS
253.515 +*
253.516 +* 0 - current column lower bound has not changed;
253.517 +*
253.518 +* 1 - current column lower bound has changed, but not significantly;
253.519 +*
253.520 +* 2 - current column lower bound has significantly changed;
253.521 +*
253.522 +* 3 - column has been fixed on its upper bound;
253.523 +*
253.524 +* 4 - implied lower bound violates current column upper bound.
253.525 +*
253.526 +* ALGORITHM
253.527 +*
253.528 +* If column q is integral, before processing its implied lower bound
253.529 +* should be rounded up:
253.530 +*
253.531 +* ( floor(l'[q]+0.5), if |l'[q] - floor(l'[q]+0.5)| <= eps
253.532 +* l'[q] := < (2)
253.533 +* ( ceil(l'[q]), otherwise
253.534 +*
253.535 +* where floor(l'[q]+0.5) is the nearest integer to l'[q], ceil(l'[q])
253.536 +* is smallest integer not less than l'[q], and eps is an absolute
253.537 +* tolerance for column value.
253.538 +*
253.539 +* Processing implied column lower bound l'[q] includes the following
253.540 +* cases:
253.541 +*
253.542 +* 1) if l'[q] < l[q] + eps, implied lower bound is redundant;
253.543 +*
253.544 +* 2) if l[q] + eps <= l[q] <= u[q] + eps, current column lower bound
253.545 +* l[q] can be strengthened by replacing it with l'[q]. If in this
253.546 +* case new column lower bound becomes close to current column upper
253.547 +* bound u[q], the column can be fixed on its upper bound;
253.548 +*
253.549 +* 3) if l'[q] > u[q] + eps, implied lower bound violates current
253.550 +* column upper bound u[q], in which case the problem has no primal
253.551 +* feasible solution. */
253.552 +
253.553 +int npp_implied_lower(NPP *npp, NPPCOL *q, double l)
253.554 +{ /* process implied column lower bound */
253.555 + int ret;
253.556 + double eps, nint;
253.557 + xassert(npp == npp);
253.558 + /* column must not be fixed */
253.559 + xassert(q->lb < q->ub);
253.560 + /* implied lower bound must be finite */
253.561 + xassert(l != -DBL_MAX);
253.562 + /* if column is integral, round up l'[q] */
253.563 + if (q->is_int)
253.564 + { nint = floor(l + 0.5);
253.565 + if (fabs(l - nint) <= 1e-5)
253.566 + l = nint;
253.567 + else
253.568 + l = ceil(l);
253.569 + }
253.570 + /* check current column lower bound */
253.571 + if (q->lb != -DBL_MAX)
253.572 + { eps = (q->is_int ? 1e-3 : 1e-3 + 1e-6 * fabs(q->lb));
253.573 + if (l < q->lb + eps)
253.574 + { ret = 0; /* redundant */
253.575 + goto done;
253.576 + }
253.577 + }
253.578 + /* check current column upper bound */
253.579 + if (q->ub != +DBL_MAX)
253.580 + { eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->ub));
253.581 + if (l > q->ub + eps)
253.582 + { ret = 4; /* infeasible */
253.583 + goto done;
253.584 + }
253.585 + /* if l'[q] is close to u[q], fix column at its upper bound */
253.586 + if (l > q->ub - 1e-3 * eps)
253.587 + { q->lb = q->ub;
253.588 + ret = 3; /* fixed */
253.589 + goto done;
253.590 + }
253.591 + }
253.592 + /* check if column lower bound changes significantly */
253.593 + if (q->lb == -DBL_MAX)
253.594 + ret = 2; /* significantly */
253.595 + else if (q->is_int && l > q->lb + 0.5)
253.596 + ret = 2; /* significantly */
253.597 + else if (l > q->lb + 0.30 * (1.0 + fabs(q->lb)))
253.598 + ret = 2; /* significantly */
253.599 + else
253.600 + ret = 1; /* not significantly */
253.601 + /* set new column lower bound */
253.602 + q->lb = l;
253.603 +done: return ret;
253.604 +}
253.605 +
253.606 +/***********************************************************************
253.607 +* NAME
253.608 +*
253.609 +* npp_implied_upper - process implied column upper bound
253.610 +*
253.611 +* SYNOPSIS
253.612 +*
253.613 +* #include "glpnpp.h"
253.614 +* int npp_implied_upper(NPP *npp, NPPCOL *q, double u);
253.615 +*
253.616 +* DESCRIPTION
253.617 +*
253.618 +* For column q:
253.619 +*
253.620 +* l[q] <= x[q] <= u[q], (1)
253.621 +*
253.622 +* where l[q] < u[q], the routine npp_implied_upper processes its
253.623 +* implied upper bound u'[q]. As the result the current column upper
253.624 +* bound may decrease. Note that the column is kept in the problem in
253.625 +* any case.
253.626 +*
253.627 +* RETURNS
253.628 +*
253.629 +* 0 - current column upper bound has not changed;
253.630 +*
253.631 +* 1 - current column upper bound has changed, but not significantly;
253.632 +*
253.633 +* 2 - current column upper bound has significantly changed;
253.634 +*
253.635 +* 3 - column has been fixed on its lower bound;
253.636 +*
253.637 +* 4 - implied upper bound violates current column lower bound.
253.638 +*
253.639 +* ALGORITHM
253.640 +*
253.641 +* If column q is integral, before processing its implied upper bound
253.642 +* should be rounded down:
253.643 +*
253.644 +* ( floor(u'[q]+0.5), if |u'[q] - floor(l'[q]+0.5)| <= eps
253.645 +* u'[q] := < (2)
253.646 +* ( floor(l'[q]), otherwise
253.647 +*
253.648 +* where floor(u'[q]+0.5) is the nearest integer to u'[q],
253.649 +* floor(u'[q]) is largest integer not greater than u'[q], and eps is
253.650 +* an absolute tolerance for column value.
253.651 +*
253.652 +* Processing implied column upper bound u'[q] includes the following
253.653 +* cases:
253.654 +*
253.655 +* 1) if u'[q] > u[q] - eps, implied upper bound is redundant;
253.656 +*
253.657 +* 2) if l[q] - eps <= u[q] <= u[q] - eps, current column upper bound
253.658 +* u[q] can be strengthened by replacing it with u'[q]. If in this
253.659 +* case new column upper bound becomes close to current column lower
253.660 +* bound, the column can be fixed on its lower bound;
253.661 +*
253.662 +* 3) if u'[q] < l[q] - eps, implied upper bound violates current
253.663 +* column lower bound l[q], in which case the problem has no primal
253.664 +* feasible solution. */
253.665 +
253.666 +int npp_implied_upper(NPP *npp, NPPCOL *q, double u)
253.667 +{ int ret;
253.668 + double eps, nint;
253.669 + xassert(npp == npp);
253.670 + /* column must not be fixed */
253.671 + xassert(q->lb < q->ub);
253.672 + /* implied upper bound must be finite */
253.673 + xassert(u != +DBL_MAX);
253.674 + /* if column is integral, round down u'[q] */
253.675 + if (q->is_int)
253.676 + { nint = floor(u + 0.5);
253.677 + if (fabs(u - nint) <= 1e-5)
253.678 + u = nint;
253.679 + else
253.680 + u = floor(u);
253.681 + }
253.682 + /* check current column upper bound */
253.683 + if (q->ub != +DBL_MAX)
253.684 + { eps = (q->is_int ? 1e-3 : 1e-3 + 1e-6 * fabs(q->ub));
253.685 + if (u > q->ub - eps)
253.686 + { ret = 0; /* redundant */
253.687 + goto done;
253.688 + }
253.689 + }
253.690 + /* check current column lower bound */
253.691 + if (q->lb != -DBL_MAX)
253.692 + { eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->lb));
253.693 + if (u < q->lb - eps)
253.694 + { ret = 4; /* infeasible */
253.695 + goto done;
253.696 + }
253.697 + /* if u'[q] is close to l[q], fix column at its lower bound */
253.698 + if (u < q->lb + 1e-3 * eps)
253.699 + { q->ub = q->lb;
253.700 + ret = 3; /* fixed */
253.701 + goto done;
253.702 + }
253.703 + }
253.704 + /* check if column upper bound changes significantly */
253.705 + if (q->ub == +DBL_MAX)
253.706 + ret = 2; /* significantly */
253.707 + else if (q->is_int && u < q->ub - 0.5)
253.708 + ret = 2; /* significantly */
253.709 + else if (u < q->ub - 0.30 * (1.0 + fabs(q->ub)))
253.710 + ret = 2; /* significantly */
253.711 + else
253.712 + ret = 1; /* not significantly */
253.713 + /* set new column upper bound */
253.714 + q->ub = u;
253.715 +done: return ret;
253.716 +}
253.717 +
253.718 +/***********************************************************************
253.719 +* NAME
253.720 +*
253.721 +* npp_ineq_singlet - process row singleton (inequality constraint)
253.722 +*
253.723 +* SYNOPSIS
253.724 +*
253.725 +* #include "glpnpp.h"
253.726 +* int npp_ineq_singlet(NPP *npp, NPPROW *p);
253.727 +*
253.728 +* DESCRIPTION
253.729 +*
253.730 +* The routine npp_ineq_singlet processes row p, which is inequality
253.731 +* constraint having the only non-zero coefficient:
253.732 +*
253.733 +* L[p] <= a[p,q] * x[q] <= U[p], (1)
253.734 +*
253.735 +* where L[p] < U[p], L[p] > -oo and/or U[p] < +oo.
253.736 +*
253.737 +* RETURNS
253.738 +*
253.739 +* 0 - current column bounds have not changed;
253.740 +*
253.741 +* 1 - current column bounds have changed, but not significantly;
253.742 +*
253.743 +* 2 - current column bounds have significantly changed;
253.744 +*
253.745 +* 3 - column has been fixed on its lower or upper bound;
253.746 +*
253.747 +* 4 - problem has no primal feasible solution.
253.748 +*
253.749 +* PROBLEM TRANSFORMATION
253.750 +*
253.751 +* Inequality constraint (1) defines implied bounds of column q:
253.752 +*
253.753 +* ( L[p] / a[p,q], if a[p,q] > 0
253.754 +* l'[q] = < (2)
253.755 +* ( U[p] / a[p,q], if a[p,q] < 0
253.756 +*
253.757 +* ( U[p] / a[p,q], if a[p,q] > 0
253.758 +* u'[q] = < (3)
253.759 +* ( L[p] / a[p,q], if a[p,q] < 0
253.760 +*
253.761 +* If these implied bounds do not violate current bounds of column q:
253.762 +*
253.763 +* l[q] <= x[q] <= u[q], (4)
253.764 +*
253.765 +* they can be used to strengthen the current column bounds:
253.766 +*
253.767 +* l[q] := max(l[q], l'[q]), (5)
253.768 +*
253.769 +* u[q] := min(u[q], u'[q]). (6)
253.770 +*
253.771 +* (See the routines npp_implied_lower and npp_implied_upper.)
253.772 +*
253.773 +* Once bounds of row p (1) have been carried over column q, the row
253.774 +* becomes redundant, so it can be replaced by equivalent free row and
253.775 +* removed from the problem.
253.776 +*
253.777 +* Note that the routine removes from the problem only row p. Column q,
253.778 +* even it has been fixed, is kept in the problem.
253.779 +*
253.780 +* RECOVERING BASIC SOLUTION
253.781 +*
253.782 +* Note that the row in the dual system corresponding to column q is
253.783 +* the following:
253.784 +*
253.785 +* sum a[i,q] pi[i] + lambda[q] = c[q] ==>
253.786 +* i
253.787 +* (7)
253.788 +* sum a[i,q] pi[i] + a[p,q] pi[p] + lambda[q] = c[q],
253.789 +* i!=p
253.790 +*
253.791 +* where pi[i] for all i != p are known in solution to the transformed
253.792 +* problem. Row p does not exist in the transformed problem, so it has
253.793 +* zero multiplier there. This allows computing multiplier for column q
253.794 +* in solution to the transformed problem:
253.795 +*
253.796 +* lambda~[q] = c[q] - sum a[i,q] pi[i]. (8)
253.797 +* i!=p
253.798 +*
253.799 +* Let in solution to the transformed problem column q be non-basic
253.800 +* with lower bound active (GLP_NL, lambda~[q] >= 0), and this lower
253.801 +* bound be implied one l'[q]. From the original problem's standpoint
253.802 +* this then means that actually the original column lower bound l[q]
253.803 +* is inactive, and active is that row bound L[p] or U[p] that defines
253.804 +* the implied bound l'[q] (2). In this case in solution to the
253.805 +* original problem column q is assigned status GLP_BS while row p is
253.806 +* assigned status GLP_NL (if a[p,q] > 0) or GLP_NU (if a[p,q] < 0).
253.807 +* Since now column q is basic, its multiplier lambda[q] is zero. This
253.808 +* allows using (7) and (8) to find multiplier for row p in solution to
253.809 +* the original problem:
253.810 +*
253.811 +* 1
253.812 +* pi[p] = ------ (c[q] - sum a[i,q] pi[i]) = lambda~[q] / a[p,q] (9)
253.813 +* a[p,q] i!=p
253.814 +*
253.815 +* Now let in solution to the transformed problem column q be non-basic
253.816 +* with upper bound active (GLP_NU, lambda~[q] <= 0), and this upper
253.817 +* bound be implied one u'[q]. As in the previous case this then means
253.818 +* that from the original problem's standpoint actually the original
253.819 +* column upper bound u[q] is inactive, and active is that row bound
253.820 +* L[p] or U[p] that defines the implied bound u'[q] (3). In this case
253.821 +* in solution to the original problem column q is assigned status
253.822 +* GLP_BS, row p is assigned status GLP_NU (if a[p,q] > 0) or GLP_NL
253.823 +* (if a[p,q] < 0), and its multiplier is computed with formula (9).
253.824 +*
253.825 +* Strengthening bounds of column q according to (5) and (6) may make
253.826 +* it fixed. Thus, if in solution to the transformed problem column q is
253.827 +* non-basic and fixed (GLP_NS), we can suppose that if lambda~[q] > 0,
253.828 +* column q has active lower bound (GLP_NL), and if lambda~[q] < 0,
253.829 +* column q has active upper bound (GLP_NU), reducing this case to two
253.830 +* previous ones. If, however, lambda~[q] is close to zero or
253.831 +* corresponding bound of row p does not exist (this may happen if
253.832 +* lambda~[q] has wrong sign due to round-off errors, in which case it
253.833 +* is expected to be close to zero, since solution is assumed to be dual
253.834 +* feasible), column q can be assigned status GLP_BS (basic), and row p
253.835 +* can be made active on its existing bound. In the latter case row
253.836 +* multiplier pi[p] computed with formula (9) will be also close to
253.837 +* zero, and dual feasibility will be kept.
253.838 +*
253.839 +* In all other cases, namely, if in solution to the transformed
253.840 +* problem column q is basic (GLP_BS), or non-basic with original lower
253.841 +* bound l[q] active (GLP_NL), or non-basic with original upper bound
253.842 +* u[q] active (GLP_NU), constraint (1) is inactive. So in solution to
253.843 +* the original problem status of column q remains unchanged, row p is
253.844 +* assigned status GLP_BS, and its multiplier pi[p] is assigned zero
253.845 +* value.
253.846 +*
253.847 +* RECOVERING INTERIOR-POINT SOLUTION
253.848 +*
253.849 +* First, value of multiplier for column q in solution to the original
253.850 +* problem is computed with formula (8). If lambda~[q] > 0 and column q
253.851 +* has implied lower bound, or if lambda~[q] < 0 and column q has
253.852 +* implied upper bound, this means that from the original problem's
253.853 +* standpoint actually row p has corresponding active bound, in which
253.854 +* case its multiplier pi[p] is computed with formula (9). In other
253.855 +* cases, when the sign of lambda~[q] corresponds to original bound of
253.856 +* column q, or when lambda~[q] =~ 0, value of row multiplier pi[p] is
253.857 +* assigned zero value.
253.858 +*
253.859 +* RECOVERING MIP SOLUTION
253.860 +*
253.861 +* None needed. */
253.862 +
253.863 +struct ineq_singlet
253.864 +{ /* row singleton (inequality constraint) */
253.865 + int p;
253.866 + /* row reference number */
253.867 + int q;
253.868 + /* column reference number */
253.869 + double apq;
253.870 + /* constraint coefficient a[p,q] */
253.871 + double c;
253.872 + /* objective coefficient at x[q] */
253.873 + double lb;
253.874 + /* row lower bound */
253.875 + double ub;
253.876 + /* row upper bound */
253.877 + char lb_changed;
253.878 + /* this flag is set if column lower bound was changed */
253.879 + char ub_changed;
253.880 + /* this flag is set if column upper bound was changed */
253.881 + NPPLFE *ptr;
253.882 + /* list of non-zero coefficients a[i,q], i != p */
253.883 +};
253.884 +
253.885 +static int rcv_ineq_singlet(NPP *npp, void *info);
253.886 +
253.887 +int npp_ineq_singlet(NPP *npp, NPPROW *p)
253.888 +{ /* process row singleton (inequality constraint) */
253.889 + struct ineq_singlet *info;
253.890 + NPPCOL *q;
253.891 + NPPAIJ *apq, *aij;
253.892 + NPPLFE *lfe;
253.893 + int lb_changed, ub_changed;
253.894 + double ll, uu;
253.895 + /* the row must be singleton inequality constraint */
253.896 + xassert(p->lb != -DBL_MAX || p->ub != +DBL_MAX);
253.897 + xassert(p->lb < p->ub);
253.898 + xassert(p->ptr != NULL && p->ptr->r_next == NULL);
253.899 + /* compute implied column bounds */
253.900 + apq = p->ptr;
253.901 + q = apq->col;
253.902 + xassert(q->lb < q->ub);
253.903 + if (apq->val > 0.0)
253.904 + { ll = (p->lb == -DBL_MAX ? -DBL_MAX : p->lb / apq->val);
253.905 + uu = (p->ub == +DBL_MAX ? +DBL_MAX : p->ub / apq->val);
253.906 + }
253.907 + else
253.908 + { ll = (p->ub == +DBL_MAX ? -DBL_MAX : p->ub / apq->val);
253.909 + uu = (p->lb == -DBL_MAX ? +DBL_MAX : p->lb / apq->val);
253.910 + }
253.911 + /* process implied column lower bound */
253.912 + if (ll == -DBL_MAX)
253.913 + lb_changed = 0;
253.914 + else
253.915 + { lb_changed = npp_implied_lower(npp, q, ll);
253.916 + xassert(0 <= lb_changed && lb_changed <= 4);
253.917 + if (lb_changed == 4) return 4; /* infeasible */
253.918 + }
253.919 + /* process implied column upper bound */
253.920 + if (uu == +DBL_MAX)
253.921 + ub_changed = 0;
253.922 + else if (lb_changed == 3)
253.923 + { /* column was fixed on its upper bound due to l'[q] = u[q] */
253.924 + /* note that L[p] < U[p], so l'[q] = u[q] < u'[q] */
253.925 + ub_changed = 0;
253.926 + }
253.927 + else
253.928 + { ub_changed = npp_implied_upper(npp, q, uu);
253.929 + xassert(0 <= ub_changed && ub_changed <= 4);
253.930 + if (ub_changed == 4) return 4; /* infeasible */
253.931 + }
253.932 + /* if neither lower nor upper column bound was changed, the row
253.933 + is originally redundant and can be replaced by free row */
253.934 + if (!lb_changed && !ub_changed)
253.935 + { p->lb = -DBL_MAX, p->ub = +DBL_MAX;
253.936 + npp_free_row(npp, p);
253.937 + return 0;
253.938 + }
253.939 + /* create transformation stack entry */
253.940 + info = npp_push_tse(npp,
253.941 + rcv_ineq_singlet, sizeof(struct ineq_singlet));
253.942 + info->p = p->i;
253.943 + info->q = q->j;
253.944 + info->apq = apq->val;
253.945 + info->c = q->coef;
253.946 + info->lb = p->lb;
253.947 + info->ub = p->ub;
253.948 + info->lb_changed = (char)lb_changed;
253.949 + info->ub_changed = (char)ub_changed;
253.950 + info->ptr = NULL;
253.951 + /* save column coefficients a[i,q], i != p (not needed for MIP
253.952 + solution) */
253.953 + if (npp->sol != GLP_MIP)
253.954 + { for (aij = q->ptr; aij != NULL; aij = aij->c_next)
253.955 + { if (aij == apq) continue; /* skip a[p,q] */
253.956 + lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
253.957 + lfe->ref = aij->row->i;
253.958 + lfe->val = aij->val;
253.959 + lfe->next = info->ptr;
253.960 + info->ptr = lfe;
253.961 + }
253.962 + }
253.963 + /* remove the row from the problem */
253.964 + npp_del_row(npp, p);
253.965 + return lb_changed >= ub_changed ? lb_changed : ub_changed;
253.966 +}
253.967 +
253.968 +static int rcv_ineq_singlet(NPP *npp, void *_info)
253.969 +{ /* recover row singleton (inequality constraint) */
253.970 + struct ineq_singlet *info = _info;
253.971 + NPPLFE *lfe;
253.972 + double lambda;
253.973 + if (npp->sol == GLP_MIP) goto done;
253.974 + /* compute lambda~[q] in solution to the transformed problem
253.975 + with formula (8) */
253.976 + lambda = info->c;
253.977 + for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
253.978 + lambda -= lfe->val * npp->r_pi[lfe->ref];
253.979 + if (npp->sol == GLP_SOL)
253.980 + { /* recover basic solution */
253.981 + if (npp->c_stat[info->q] == GLP_BS)
253.982 + { /* column q is basic, so row p is inactive */
253.983 + npp->r_stat[info->p] = GLP_BS;
253.984 + npp->r_pi[info->p] = 0.0;
253.985 + }
253.986 + else if (npp->c_stat[info->q] == GLP_NL)
253.987 +nl: { /* column q is non-basic with lower bound active */
253.988 + if (info->lb_changed)
253.989 + { /* it is implied bound, so actually row p is active
253.990 + while column q is basic */
253.991 + npp->r_stat[info->p] =
253.992 + (char)(info->apq > 0.0 ? GLP_NL : GLP_NU);
253.993 + npp->c_stat[info->q] = GLP_BS;
253.994 + npp->r_pi[info->p] = lambda / info->apq;
253.995 + }
253.996 + else
253.997 + { /* it is original bound, so row p is inactive */
253.998 + npp->r_stat[info->p] = GLP_BS;
253.999 + npp->r_pi[info->p] = 0.0;
253.1000 + }
253.1001 + }
253.1002 + else if (npp->c_stat[info->q] == GLP_NU)
253.1003 +nu: { /* column q is non-basic with upper bound active */
253.1004 + if (info->ub_changed)
253.1005 + { /* it is implied bound, so actually row p is active
253.1006 + while column q is basic */
253.1007 + npp->r_stat[info->p] =
253.1008 + (char)(info->apq > 0.0 ? GLP_NU : GLP_NL);
253.1009 + npp->c_stat[info->q] = GLP_BS;
253.1010 + npp->r_pi[info->p] = lambda / info->apq;
253.1011 + }
253.1012 + else
253.1013 + { /* it is original bound, so row p is inactive */
253.1014 + npp->r_stat[info->p] = GLP_BS;
253.1015 + npp->r_pi[info->p] = 0.0;
253.1016 + }
253.1017 + }
253.1018 + else if (npp->c_stat[info->q] == GLP_NS)
253.1019 + { /* column q is non-basic and fixed; note, however, that in
253.1020 + in the original problem it is non-fixed */
253.1021 + if (lambda > +1e-7)
253.1022 + { if (info->apq > 0.0 && info->lb != -DBL_MAX ||
253.1023 + info->apq < 0.0 && info->ub != +DBL_MAX ||
253.1024 + !info->lb_changed)
253.1025 + { /* either corresponding bound of row p exists or
253.1026 + column q remains non-basic with its original lower
253.1027 + bound active */
253.1028 + npp->c_stat[info->q] = GLP_NL;
253.1029 + goto nl;
253.1030 + }
253.1031 + }
253.1032 + if (lambda < -1e-7)
253.1033 + { if (info->apq > 0.0 && info->ub != +DBL_MAX ||
253.1034 + info->apq < 0.0 && info->lb != -DBL_MAX ||
253.1035 + !info->ub_changed)
253.1036 + { /* either corresponding bound of row p exists or
253.1037 + column q remains non-basic with its original upper
253.1038 + bound active */
253.1039 + npp->c_stat[info->q] = GLP_NU;
253.1040 + goto nu;
253.1041 + }
253.1042 + }
253.1043 + /* either lambda~[q] is close to zero, or corresponding
253.1044 + bound of row p does not exist, because lambda~[q] has
253.1045 + wrong sign due to round-off errors; in the latter case
253.1046 + lambda~[q] is also assumed to be close to zero; so, we
253.1047 + can make row p active on its existing bound and column q
253.1048 + basic; pi[p] will have wrong sign, but it also will be
253.1049 + close to zero (rarus casus of dual degeneracy) */
253.1050 + if (info->lb != -DBL_MAX && info->ub == +DBL_MAX)
253.1051 + { /* row lower bound exists, but upper bound doesn't */
253.1052 + npp->r_stat[info->p] = GLP_NL;
253.1053 + }
253.1054 + else if (info->lb == -DBL_MAX && info->ub != +DBL_MAX)
253.1055 + { /* row upper bound exists, but lower bound doesn't */
253.1056 + npp->r_stat[info->p] = GLP_NU;
253.1057 + }
253.1058 + else if (info->lb != -DBL_MAX && info->ub != +DBL_MAX)
253.1059 + { /* both row lower and upper bounds exist */
253.1060 + /* to choose proper active row bound we should not use
253.1061 + lambda~[q], because its value being close to zero is
253.1062 + unreliable; so we choose that bound which provides
253.1063 + primal feasibility for original constraint (1) */
253.1064 + if (info->apq * npp->c_value[info->q] <=
253.1065 + 0.5 * (info->lb + info->ub))
253.1066 + npp->r_stat[info->p] = GLP_NL;
253.1067 + else
253.1068 + npp->r_stat[info->p] = GLP_NU;
253.1069 + }
253.1070 + else
253.1071 + { npp_error();
253.1072 + return 1;
253.1073 + }
253.1074 + npp->c_stat[info->q] = GLP_BS;
253.1075 + npp->r_pi[info->p] = lambda / info->apq;
253.1076 + }
253.1077 + else
253.1078 + { npp_error();
253.1079 + return 1;
253.1080 + }
253.1081 + }
253.1082 + if (npp->sol == GLP_IPT)
253.1083 + { /* recover interior-point solution */
253.1084 + if (lambda > +DBL_EPSILON && info->lb_changed ||
253.1085 + lambda < -DBL_EPSILON && info->ub_changed)
253.1086 + { /* actually row p has corresponding active bound */
253.1087 + npp->r_pi[info->p] = lambda / info->apq;
253.1088 + }
253.1089 + else
253.1090 + { /* either bounds of column q are both inactive or its
253.1091 + original bound is active */
253.1092 + npp->r_pi[info->p] = 0.0;
253.1093 + }
253.1094 + }
253.1095 +done: return 0;
253.1096 +}
253.1097 +
253.1098 +/***********************************************************************
253.1099 +* NAME
253.1100 +*
253.1101 +* npp_implied_slack - process column singleton (implied slack variable)
253.1102 +*
253.1103 +* SYNOPSIS
253.1104 +*
253.1105 +* #include "glpnpp.h"
253.1106 +* void npp_implied_slack(NPP *npp, NPPCOL *q);
253.1107 +*
253.1108 +* DESCRIPTION
253.1109 +*
253.1110 +* The routine npp_implied_slack processes column q:
253.1111 +*
253.1112 +* l[q] <= x[q] <= u[q], (1)
253.1113 +*
253.1114 +* where l[q] < u[q], having the only non-zero coefficient in row p,
253.1115 +* which is equality constraint:
253.1116 +*
253.1117 +* sum a[p,j] x[j] + a[p,q] x[q] = b. (2)
253.1118 +* j!=q
253.1119 +*
253.1120 +* PROBLEM TRANSFORMATION
253.1121 +*
253.1122 +* (If x[q] is integral, this transformation must not be used.)
253.1123 +*
253.1124 +* The term a[p,q] x[q] in constraint (2) can be considered as a slack
253.1125 +* variable that allows to carry bounds of column q over row p and then
253.1126 +* remove column q from the problem.
253.1127 +*
253.1128 +* Constraint (2) can be written as follows:
253.1129 +*
253.1130 +* sum a[p,j] x[j] = b - a[p,q] x[q]. (3)
253.1131 +* j!=q
253.1132 +*
253.1133 +* According to (1) constraint (3) is equivalent to the following
253.1134 +* inequality constraint:
253.1135 +*
253.1136 +* L[p] <= sum a[p,j] x[j] <= U[p], (4)
253.1137 +* j!=q
253.1138 +*
253.1139 +* where
253.1140 +*
253.1141 +* ( b - a[p,q] u[q], if a[p,q] > 0
253.1142 +* L[p] = < (5)
253.1143 +* ( b - a[p,q] l[q], if a[p,q] < 0
253.1144 +*
253.1145 +* ( b - a[p,q] l[q], if a[p,q] > 0
253.1146 +* U[p] = < (6)
253.1147 +* ( b - a[p,q] u[q], if a[p,q] < 0
253.1148 +*
253.1149 +* From (2) it follows that:
253.1150 +*
253.1151 +* 1
253.1152 +* x[q] = ------ (b - sum a[p,j] x[j]). (7)
253.1153 +* a[p,q] j!=q
253.1154 +*
253.1155 +* In order to eliminate x[q] from the objective row we substitute it
253.1156 +* from (6) to that row:
253.1157 +*
253.1158 +* z = sum c[j] x[j] + c[q] x[q] + c[0] =
253.1159 +* j!=q
253.1160 +* 1
253.1161 +* = sum c[j] x[j] + c[q] [------ (b - sum a[p,j] x[j])] + c0 =
253.1162 +* j!=q a[p,q] j!=q
253.1163 +*
253.1164 +* = sum c~[j] x[j] + c~[0],
253.1165 +* j!=q
253.1166 +* a[p,j] b
253.1167 +* c~[j] = c[j] - c[q] ------, c~0 = c0 - c[q] ------ (8)
253.1168 +* a[p,q] a[p,q]
253.1169 +*
253.1170 +* are values of objective coefficients and constant term, resp., in
253.1171 +* the transformed problem.
253.1172 +*
253.1173 +* Note that column q is column singleton, so in the dual system of the
253.1174 +* original problem it corresponds to the following row singleton:
253.1175 +*
253.1176 +* a[p,q] pi[p] + lambda[q] = c[q]. (9)
253.1177 +*
253.1178 +* In the transformed problem row (9) would be the following:
253.1179 +*
253.1180 +* a[p,q] pi~[p] + lambda[q] = c~[q] = 0. (10)
253.1181 +*
253.1182 +* Subtracting (10) from (9) we have:
253.1183 +*
253.1184 +* a[p,q] (pi[p] - pi~[p]) = c[q]
253.1185 +*
253.1186 +* that gives the following formula to compute multiplier for row p in
253.1187 +* solution to the original problem using its value in solution to the
253.1188 +* transformed problem:
253.1189 +*
253.1190 +* pi[p] = pi~[p] + c[q] / a[p,q]. (11)
253.1191 +*
253.1192 +* RECOVERING BASIC SOLUTION
253.1193 +*
253.1194 +* Status of column q in solution to the original problem is defined
253.1195 +* by status of row p in solution to the transformed problem and the
253.1196 +* sign of coefficient a[p,q] in the original inequality constraint (2)
253.1197 +* as follows:
253.1198 +*
253.1199 +* +-----------------------+---------+--------------------+
253.1200 +* | Status of row p | Sign of | Status of column q |
253.1201 +* | (transformed problem) | a[p,q] | (original problem) |
253.1202 +* +-----------------------+---------+--------------------+
253.1203 +* | GLP_BS | + / - | GLP_BS |
253.1204 +* | GLP_NL | + | GLP_NU |
253.1205 +* | GLP_NL | - | GLP_NL |
253.1206 +* | GLP_NU | + | GLP_NL |
253.1207 +* | GLP_NU | - | GLP_NU |
253.1208 +* | GLP_NF | + / - | GLP_NF |
253.1209 +* +-----------------------+---------+--------------------+
253.1210 +*
253.1211 +* Value of column q is computed with formula (7). Since originally row
253.1212 +* p is equality constraint, its status is assigned GLP_NS, and value of
253.1213 +* its multiplier pi[p] is computed with formula (11).
253.1214 +*
253.1215 +* RECOVERING INTERIOR-POINT SOLUTION
253.1216 +*
253.1217 +* Value of column q is computed with formula (7). Row multiplier value
253.1218 +* pi[p] is computed with formula (11).
253.1219 +*
253.1220 +* RECOVERING MIP SOLUTION
253.1221 +*
253.1222 +* Value of column q is computed with formula (7). */
253.1223 +
253.1224 +struct implied_slack
253.1225 +{ /* column singleton (implied slack variable) */
253.1226 + int p;
253.1227 + /* row reference number */
253.1228 + int q;
253.1229 + /* column reference number */
253.1230 + double apq;
253.1231 + /* constraint coefficient a[p,q] */
253.1232 + double b;
253.1233 + /* right-hand side of original equality constraint */
253.1234 + double c;
253.1235 + /* original objective coefficient at x[q] */
253.1236 + NPPLFE *ptr;
253.1237 + /* list of non-zero coefficients a[p,j], j != q */
253.1238 +};
253.1239 +
253.1240 +static int rcv_implied_slack(NPP *npp, void *info);
253.1241 +
253.1242 +void npp_implied_slack(NPP *npp, NPPCOL *q)
253.1243 +{ /* process column singleton (implied slack variable) */
253.1244 + struct implied_slack *info;
253.1245 + NPPROW *p;
253.1246 + NPPAIJ *aij;
253.1247 + NPPLFE *lfe;
253.1248 + /* the column must be non-integral non-fixed singleton */
253.1249 + xassert(!q->is_int);
253.1250 + xassert(q->lb < q->ub);
253.1251 + xassert(q->ptr != NULL && q->ptr->c_next == NULL);
253.1252 + /* corresponding row must be equality constraint */
253.1253 + aij = q->ptr;
253.1254 + p = aij->row;
253.1255 + xassert(p->lb == p->ub);
253.1256 + /* create transformation stack entry */
253.1257 + info = npp_push_tse(npp,
253.1258 + rcv_implied_slack, sizeof(struct implied_slack));
253.1259 + info->p = p->i;
253.1260 + info->q = q->j;
253.1261 + info->apq = aij->val;
253.1262 + info->b = p->lb;
253.1263 + info->c = q->coef;
253.1264 + info->ptr = NULL;
253.1265 + /* save row coefficients a[p,j], j != q, and substitute x[q]
253.1266 + into the objective row */
253.1267 + for (aij = p->ptr; aij != NULL; aij = aij->r_next)
253.1268 + { if (aij->col == q) continue; /* skip a[p,q] */
253.1269 + lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
253.1270 + lfe->ref = aij->col->j;
253.1271 + lfe->val = aij->val;
253.1272 + lfe->next = info->ptr;
253.1273 + info->ptr = lfe;
253.1274 + aij->col->coef -= info->c * (aij->val / info->apq);
253.1275 + }
253.1276 + npp->c0 += info->c * (info->b / info->apq);
253.1277 + /* compute new row bounds */
253.1278 + if (info->apq > 0.0)
253.1279 + { p->lb = (q->ub == +DBL_MAX ?
253.1280 + -DBL_MAX : info->b - info->apq * q->ub);
253.1281 + p->ub = (q->lb == -DBL_MAX ?
253.1282 + +DBL_MAX : info->b - info->apq * q->lb);
253.1283 + }
253.1284 + else
253.1285 + { p->lb = (q->lb == -DBL_MAX ?
253.1286 + -DBL_MAX : info->b - info->apq * q->lb);
253.1287 + p->ub = (q->ub == +DBL_MAX ?
253.1288 + +DBL_MAX : info->b - info->apq * q->ub);
253.1289 + }
253.1290 + /* remove the column from the problem */
253.1291 + npp_del_col(npp, q);
253.1292 + return;
253.1293 +}
253.1294 +
253.1295 +static int rcv_implied_slack(NPP *npp, void *_info)
253.1296 +{ /* recover column singleton (implied slack variable) */
253.1297 + struct implied_slack *info = _info;
253.1298 + NPPLFE *lfe;
253.1299 + double temp;
253.1300 + if (npp->sol == GLP_SOL)
253.1301 + { /* assign statuses to row p and column q */
253.1302 + if (npp->r_stat[info->p] == GLP_BS ||
253.1303 + npp->r_stat[info->p] == GLP_NF)
253.1304 + npp->c_stat[info->q] = npp->r_stat[info->p];
253.1305 + else if (npp->r_stat[info->p] == GLP_NL)
253.1306 + npp->c_stat[info->q] =
253.1307 + (char)(info->apq > 0.0 ? GLP_NU : GLP_NL);
253.1308 + else if (npp->r_stat[info->p] == GLP_NU)
253.1309 + npp->c_stat[info->q] =
253.1310 + (char)(info->apq > 0.0 ? GLP_NL : GLP_NU);
253.1311 + else
253.1312 + { npp_error();
253.1313 + return 1;
253.1314 + }
253.1315 + npp->r_stat[info->p] = GLP_NS;
253.1316 + }
253.1317 + if (npp->sol != GLP_MIP)
253.1318 + { /* compute multiplier for row p */
253.1319 + npp->r_pi[info->p] += info->c / info->apq;
253.1320 + }
253.1321 + /* compute value of column q */
253.1322 + temp = info->b;
253.1323 + for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
253.1324 + temp -= lfe->val * npp->c_value[lfe->ref];
253.1325 + npp->c_value[info->q] = temp / info->apq;
253.1326 + return 0;
253.1327 +}
253.1328 +
253.1329 +/***********************************************************************
253.1330 +* NAME
253.1331 +*
253.1332 +* npp_implied_free - process column singleton (implied free variable)
253.1333 +*
253.1334 +* SYNOPSIS
253.1335 +*
253.1336 +* #include "glpnpp.h"
253.1337 +* int npp_implied_free(NPP *npp, NPPCOL *q);
253.1338 +*
253.1339 +* DESCRIPTION
253.1340 +*
253.1341 +* The routine npp_implied_free processes column q:
253.1342 +*
253.1343 +* l[q] <= x[q] <= u[q], (1)
253.1344 +*
253.1345 +* having non-zero coefficient in the only row p, which is inequality
253.1346 +* constraint:
253.1347 +*
253.1348 +* L[p] <= sum a[p,j] x[j] + a[p,q] x[q] <= U[p], (2)
253.1349 +* j!=q
253.1350 +*
253.1351 +* where l[q] < u[q], L[p] < U[p], L[p] > -oo and/or U[p] < +oo.
253.1352 +*
253.1353 +* RETURNS
253.1354 +*
253.1355 +* 0 - success;
253.1356 +*
253.1357 +* 1 - column lower and/or upper bound(s) can be active;
253.1358 +*
253.1359 +* 2 - problem has no dual feasible solution.
253.1360 +*
253.1361 +* PROBLEM TRANSFORMATION
253.1362 +*
253.1363 +* Constraint (2) can be written as follows:
253.1364 +*
253.1365 +* L[p] - sum a[p,j] x[j] <= a[p,q] x[q] <= U[p] - sum a[p,j] x[j],
253.1366 +* j!=q j!=q
253.1367 +*
253.1368 +* from which it follows that:
253.1369 +*
253.1370 +* alfa <= a[p,q] x[q] <= beta, (3)
253.1371 +*
253.1372 +* where
253.1373 +*
253.1374 +* alfa = inf(L[p] - sum a[p,j] x[j]) =
253.1375 +* j!=q
253.1376 +*
253.1377 +* = L[p] - sup sum a[p,j] x[j] = (4)
253.1378 +* j!=q
253.1379 +*
253.1380 +* = L[p] - sum a[p,j] u[j] - sum a[p,j] l[j],
253.1381 +* j in Jp j in Jn
253.1382 +*
253.1383 +* beta = sup(L[p] - sum a[p,j] x[j]) =
253.1384 +* j!=q
253.1385 +*
253.1386 +* = L[p] - inf sum a[p,j] x[j] = (5)
253.1387 +* j!=q
253.1388 +*
253.1389 +* = L[p] - sum a[p,j] l[j] - sum a[p,j] u[j],
253.1390 +* j in Jp j in Jn
253.1391 +*
253.1392 +* Jp = {j != q: a[p,j] > 0}, Jn = {j != q: a[p,j] < 0}. (6)
253.1393 +*
253.1394 +* Inequality (3) defines implied bounds of variable x[q]:
253.1395 +*
253.1396 +* l'[q] <= x[q] <= u'[q], (7)
253.1397 +*
253.1398 +* where
253.1399 +*
253.1400 +* ( alfa / a[p,q], if a[p,q] > 0
253.1401 +* l'[q] = < (8a)
253.1402 +* ( beta / a[p,q], if a[p,q] < 0
253.1403 +*
253.1404 +* ( beta / a[p,q], if a[p,q] > 0
253.1405 +* u'[q] = < (8b)
253.1406 +* ( alfa / a[p,q], if a[p,q] < 0
253.1407 +*
253.1408 +* Thus, if l'[q] > l[q] - eps and u'[q] < u[q] + eps, where eps is
253.1409 +* an absolute tolerance for column value, column bounds (1) cannot be
253.1410 +* active, in which case column q can be replaced by equivalent free
253.1411 +* (unbounded) column.
253.1412 +*
253.1413 +* Note that column q is column singleton, so in the dual system of the
253.1414 +* original problem it corresponds to the following row singleton:
253.1415 +*
253.1416 +* a[p,q] pi[p] + lambda[q] = c[q], (9)
253.1417 +*
253.1418 +* from which it follows that:
253.1419 +*
253.1420 +* pi[p] = (c[q] - lambda[q]) / a[p,q]. (10)
253.1421 +*
253.1422 +* Let x[q] be implied free (unbounded) variable. Then column q can be
253.1423 +* only basic, so its multiplier lambda[q] is equal to zero, and from
253.1424 +* (10) we have:
253.1425 +*
253.1426 +* pi[p] = c[q] / a[p,q]. (11)
253.1427 +*
253.1428 +* There are possible three cases:
253.1429 +*
253.1430 +* 1) pi[p] < -eps, where eps is an absolute tolerance for row
253.1431 +* multiplier. In this case, to provide dual feasibility of the
253.1432 +* original problem, row p must be active on its lower bound, and
253.1433 +* if its lower bound does not exist (L[p] = -oo), the problem has
253.1434 +* no dual feasible solution;
253.1435 +*
253.1436 +* 2) pi[p] > +eps. In this case row p must be active on its upper
253.1437 +* bound, and if its upper bound does not exist (U[p] = +oo), the
253.1438 +* problem has no dual feasible solution;
253.1439 +*
253.1440 +* 3) -eps <= pi[p] <= +eps. In this case any (either lower or upper)
253.1441 +* bound of row p can be active, because this does not affect dual
253.1442 +* feasibility.
253.1443 +*
253.1444 +* Thus, in all three cases original inequality constraint (2) can be
253.1445 +* replaced by equality constraint, where the right-hand side is either
253.1446 +* lower or upper bound of row p, and bounds of column q can be removed
253.1447 +* that makes it free (unbounded). (May note that this transformation
253.1448 +* can be followed by transformation "Column singleton (implied slack
253.1449 +* variable)" performed by the routine npp_implied_slack.)
253.1450 +*
253.1451 +* RECOVERING BASIC SOLUTION
253.1452 +*
253.1453 +* Status of row p in solution to the original problem is determined
253.1454 +* by its status in solution to the transformed problem and its bound,
253.1455 +* which was choosen to be active:
253.1456 +*
253.1457 +* +-----------------------+--------+--------------------+
253.1458 +* | Status of row p | Active | Status of row p |
253.1459 +* | (transformed problem) | bound | (original problem) |
253.1460 +* +-----------------------+--------+--------------------+
253.1461 +* | GLP_BS | L[p] | GLP_BS |
253.1462 +* | GLP_BS | U[p] | GLP_BS |
253.1463 +* | GLP_NS | L[p] | GLP_NL |
253.1464 +* | GLP_NS | U[p] | GLP_NU |
253.1465 +* +-----------------------+--------+--------------------+
253.1466 +*
253.1467 +* Value of row multiplier pi[p] (as well as value of column q) in
253.1468 +* solution to the original problem is the same as in solution to the
253.1469 +* transformed problem.
253.1470 +*
253.1471 +* RECOVERING INTERIOR-POINT SOLUTION
253.1472 +*
253.1473 +* Value of row multiplier pi[p] in solution to the original problem is
253.1474 +* the same as in solution to the transformed problem.
253.1475 +*
253.1476 +* RECOVERING MIP SOLUTION
253.1477 +*
253.1478 +* None needed. */
253.1479 +
253.1480 +struct implied_free
253.1481 +{ /* column singleton (implied free variable) */
253.1482 + int p;
253.1483 + /* row reference number */
253.1484 + char stat;
253.1485 + /* row status:
253.1486 + GLP_NL - active constraint on lower bound
253.1487 + GLP_NU - active constraint on upper bound */
253.1488 +};
253.1489 +
253.1490 +static int rcv_implied_free(NPP *npp, void *info);
253.1491 +
253.1492 +int npp_implied_free(NPP *npp, NPPCOL *q)
253.1493 +{ /* process column singleton (implied free variable) */
253.1494 + struct implied_free *info;
253.1495 + NPPROW *p;
253.1496 + NPPAIJ *apq, *aij;
253.1497 + double alfa, beta, l, u, pi, eps;
253.1498 + /* the column must be non-fixed singleton */
253.1499 + xassert(q->lb < q->ub);
253.1500 + xassert(q->ptr != NULL && q->ptr->c_next == NULL);
253.1501 + /* corresponding row must be inequality constraint */
253.1502 + apq = q->ptr;
253.1503 + p = apq->row;
253.1504 + xassert(p->lb != -DBL_MAX || p->ub != +DBL_MAX);
253.1505 + xassert(p->lb < p->ub);
253.1506 + /* compute alfa */
253.1507 + alfa = p->lb;
253.1508 + if (alfa != -DBL_MAX)
253.1509 + { for (aij = p->ptr; aij != NULL; aij = aij->r_next)
253.1510 + { if (aij == apq) continue; /* skip a[p,q] */
253.1511 + if (aij->val > 0.0)
253.1512 + { if (aij->col->ub == +DBL_MAX)
253.1513 + { alfa = -DBL_MAX;
253.1514 + break;
253.1515 + }
253.1516 + alfa -= aij->val * aij->col->ub;
253.1517 + }
253.1518 + else /* < 0.0 */
253.1519 + { if (aij->col->lb == -DBL_MAX)
253.1520 + { alfa = -DBL_MAX;
253.1521 + break;
253.1522 + }
253.1523 + alfa -= aij->val * aij->col->lb;
253.1524 + }
253.1525 + }
253.1526 + }
253.1527 + /* compute beta */
253.1528 + beta = p->ub;
253.1529 + if (beta != +DBL_MAX)
253.1530 + { for (aij = p->ptr; aij != NULL; aij = aij->r_next)
253.1531 + { if (aij == apq) continue; /* skip a[p,q] */
253.1532 + if (aij->val > 0.0)
253.1533 + { if (aij->col->lb == -DBL_MAX)
253.1534 + { beta = +DBL_MAX;
253.1535 + break;
253.1536 + }
253.1537 + beta -= aij->val * aij->col->lb;
253.1538 + }
253.1539 + else /* < 0.0 */
253.1540 + { if (aij->col->ub == +DBL_MAX)
253.1541 + { beta = +DBL_MAX;
253.1542 + break;
253.1543 + }
253.1544 + beta -= aij->val * aij->col->ub;
253.1545 + }
253.1546 + }
253.1547 + }
253.1548 + /* compute implied column lower bound l'[q] */
253.1549 + if (apq->val > 0.0)
253.1550 + l = (alfa == -DBL_MAX ? -DBL_MAX : alfa / apq->val);
253.1551 + else /* < 0.0 */
253.1552 + l = (beta == +DBL_MAX ? -DBL_MAX : beta / apq->val);
253.1553 + /* compute implied column upper bound u'[q] */
253.1554 + if (apq->val > 0.0)
253.1555 + u = (beta == +DBL_MAX ? +DBL_MAX : beta / apq->val);
253.1556 + else
253.1557 + u = (alfa == -DBL_MAX ? +DBL_MAX : alfa / apq->val);
253.1558 + /* check if column lower bound l[q] can be active */
253.1559 + if (q->lb != -DBL_MAX)
253.1560 + { eps = 1e-9 + 1e-12 * fabs(q->lb);
253.1561 + if (l < q->lb - eps) return 1; /* yes, it can */
253.1562 + }
253.1563 + /* check if column upper bound u[q] can be active */
253.1564 + if (q->ub != +DBL_MAX)
253.1565 + { eps = 1e-9 + 1e-12 * fabs(q->ub);
253.1566 + if (u > q->ub + eps) return 1; /* yes, it can */
253.1567 + }
253.1568 + /* okay; make column q free (unbounded) */
253.1569 + q->lb = -DBL_MAX, q->ub = +DBL_MAX;
253.1570 + /* create transformation stack entry */
253.1571 + info = npp_push_tse(npp,
253.1572 + rcv_implied_free, sizeof(struct implied_free));
253.1573 + info->p = p->i;
253.1574 + info->stat = -1;
253.1575 + /* compute row multiplier pi[p] */
253.1576 + pi = q->coef / apq->val;
253.1577 + /* check dual feasibility for row p */
253.1578 + if (pi > +DBL_EPSILON)
253.1579 + { /* lower bound L[p] must be active */
253.1580 + if (p->lb != -DBL_MAX)
253.1581 +nl: { info->stat = GLP_NL;
253.1582 + p->ub = p->lb;
253.1583 + }
253.1584 + else
253.1585 + { if (pi > +1e-5) return 2; /* dual infeasibility */
253.1586 + /* take a chance on U[p] */
253.1587 + xassert(p->ub != +DBL_MAX);
253.1588 + goto nu;
253.1589 + }
253.1590 + }
253.1591 + else if (pi < -DBL_EPSILON)
253.1592 + { /* upper bound U[p] must be active */
253.1593 + if (p->ub != +DBL_MAX)
253.1594 +nu: { info->stat = GLP_NU;
253.1595 + p->lb = p->ub;
253.1596 + }
253.1597 + else
253.1598 + { if (pi < -1e-5) return 2; /* dual infeasibility */
253.1599 + /* take a chance on L[p] */
253.1600 + xassert(p->lb != -DBL_MAX);
253.1601 + goto nl;
253.1602 + }
253.1603 + }
253.1604 + else
253.1605 + { /* any bound (either L[p] or U[p]) can be made active */
253.1606 + if (p->ub == +DBL_MAX)
253.1607 + { xassert(p->lb != -DBL_MAX);
253.1608 + goto nl;
253.1609 + }
253.1610 + if (p->lb == -DBL_MAX)
253.1611 + { xassert(p->ub != +DBL_MAX);
253.1612 + goto nu;
253.1613 + }
253.1614 + if (fabs(p->lb) <= fabs(p->ub)) goto nl; else goto nu;
253.1615 + }
253.1616 + return 0;
253.1617 +}
253.1618 +
253.1619 +static int rcv_implied_free(NPP *npp, void *_info)
253.1620 +{ /* recover column singleton (implied free variable) */
253.1621 + struct implied_free *info = _info;
253.1622 + if (npp->sol == GLP_SOL)
253.1623 + { if (npp->r_stat[info->p] == GLP_BS)
253.1624 + npp->r_stat[info->p] = GLP_BS;
253.1625 + else if (npp->r_stat[info->p] == GLP_NS)
253.1626 + { xassert(info->stat == GLP_NL || info->stat == GLP_NU);
253.1627 + npp->r_stat[info->p] = info->stat;
253.1628 + }
253.1629 + else
253.1630 + { npp_error();
253.1631 + return 1;
253.1632 + }
253.1633 + }
253.1634 + return 0;
253.1635 +}
253.1636 +
253.1637 +/***********************************************************************
253.1638 +* NAME
253.1639 +*
253.1640 +* npp_eq_doublet - process row doubleton (equality constraint)
253.1641 +*
253.1642 +* SYNOPSIS
253.1643 +*
253.1644 +* #include "glpnpp.h"
253.1645 +* NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p);
253.1646 +*
253.1647 +* DESCRIPTION
253.1648 +*
253.1649 +* The routine npp_eq_doublet processes row p, which is equality
253.1650 +* constraint having exactly two non-zero coefficients:
253.1651 +*
253.1652 +* a[p,q] x[q] + a[p,r] x[r] = b. (1)
253.1653 +*
253.1654 +* As the result of processing one of columns q or r is eliminated from
253.1655 +* all other rows and, thus, becomes column singleton of type "implied
253.1656 +* slack variable". Row p is not changed and along with column q and r
253.1657 +* remains in the problem.
253.1658 +*
253.1659 +* RETURNS
253.1660 +*
253.1661 +* The routine npp_eq_doublet returns pointer to the descriptor of that
253.1662 +* column q or r which has been eliminated. If, due to some reason, the
253.1663 +* elimination was not performed, the routine returns NULL.
253.1664 +*
253.1665 +* PROBLEM TRANSFORMATION
253.1666 +*
253.1667 +* First, we decide which column q or r will be eliminated. Let it be
253.1668 +* column q. Consider i-th constraint row, where column q has non-zero
253.1669 +* coefficient a[i,q] != 0:
253.1670 +*
253.1671 +* L[i] <= sum a[i,j] x[j] <= U[i]. (2)
253.1672 +* j
253.1673 +*
253.1674 +* In order to eliminate column q from row (2) we subtract from it row
253.1675 +* (1) multiplied by gamma[i] = a[i,q] / a[p,q], i.e. we replace in the
253.1676 +* transformed problem row (2) by its linear combination with row (1).
253.1677 +* This transformation changes only coefficients in columns q and r,
253.1678 +* and bounds of row i as follows:
253.1679 +*
253.1680 +* a~[i,q] = a[i,q] - gamma[i] a[p,q] = 0, (3)
253.1681 +*
253.1682 +* a~[i,r] = a[i,r] - gamma[i] a[p,r], (4)
253.1683 +*
253.1684 +* L~[i] = L[i] - gamma[i] b, (5)
253.1685 +*
253.1686 +* U~[i] = U[i] - gamma[i] b. (6)
253.1687 +*
253.1688 +* RECOVERING BASIC SOLUTION
253.1689 +*
253.1690 +* The transformation of the primal system of the original problem:
253.1691 +*
253.1692 +* L <= A x <= U (7)
253.1693 +*
253.1694 +* is equivalent to multiplying from the left a transformation matrix F
253.1695 +* by components of this primal system, which in the transformed problem
253.1696 +* becomes the following:
253.1697 +*
253.1698 +* F L <= F A x <= F U ==> L~ <= A~x <= U~. (8)
253.1699 +*
253.1700 +* The matrix F has the following structure:
253.1701 +*
253.1702 +* ( 1 -gamma[1] )
253.1703 +* ( )
253.1704 +* ( 1 -gamma[2] )
253.1705 +* ( )
253.1706 +* ( ... ... )
253.1707 +* ( )
253.1708 +* F = ( 1 -gamma[p-1] ) (9)
253.1709 +* ( )
253.1710 +* ( 1 )
253.1711 +* ( )
253.1712 +* ( -gamma[p+1] 1 )
253.1713 +* ( )
253.1714 +* ( ... ... )
253.1715 +*
253.1716 +* where its column containing elements -gamma[i] corresponds to row p
253.1717 +* of the primal system.
253.1718 +*
253.1719 +* From (8) it follows that the dual system of the original problem:
253.1720 +*
253.1721 +* A'pi + lambda = c, (10)
253.1722 +*
253.1723 +* in the transformed problem becomes the following:
253.1724 +*
253.1725 +* A'F'inv(F')pi + lambda = c ==> (A~)'pi~ + lambda = c, (11)
253.1726 +*
253.1727 +* where:
253.1728 +*
253.1729 +* pi~ = inv(F')pi (12)
253.1730 +*
253.1731 +* is the vector of row multipliers in the transformed problem. Thus:
253.1732 +*
253.1733 +* pi = F'pi~. (13)
253.1734 +*
253.1735 +* Therefore, as it follows from (13), value of multiplier for row p in
253.1736 +* solution to the original problem can be computed as follows:
253.1737 +*
253.1738 +* pi[p] = pi~[p] - sum gamma[i] pi~[i], (14)
253.1739 +* i
253.1740 +*
253.1741 +* where pi~[i] = pi[i] is multiplier for row i (i != p).
253.1742 +*
253.1743 +* Note that the statuses of all rows and columns are not changed.
253.1744 +*
253.1745 +* RECOVERING INTERIOR-POINT SOLUTION
253.1746 +*
253.1747 +* Multiplier for row p in solution to the original problem is computed
253.1748 +* with formula (14).
253.1749 +*
253.1750 +* RECOVERING MIP SOLUTION
253.1751 +*
253.1752 +* None needed. */
253.1753 +
253.1754 +struct eq_doublet
253.1755 +{ /* row doubleton (equality constraint) */
253.1756 + int p;
253.1757 + /* row reference number */
253.1758 + double apq;
253.1759 + /* constraint coefficient a[p,q] */
253.1760 + NPPLFE *ptr;
253.1761 + /* list of non-zero coefficients a[i,q], i != p */
253.1762 +};
253.1763 +
253.1764 +static int rcv_eq_doublet(NPP *npp, void *info);
253.1765 +
253.1766 +NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p)
253.1767 +{ /* process row doubleton (equality constraint) */
253.1768 + struct eq_doublet *info;
253.1769 + NPPROW *i;
253.1770 + NPPCOL *q, *r;
253.1771 + NPPAIJ *apq, *apr, *aiq, *air, *next;
253.1772 + NPPLFE *lfe;
253.1773 + double gamma;
253.1774 + /* the row must be doubleton equality constraint */
253.1775 + xassert(p->lb == p->ub);
253.1776 + xassert(p->ptr != NULL && p->ptr->r_next != NULL &&
253.1777 + p->ptr->r_next->r_next == NULL);
253.1778 + /* choose column to be eliminated */
253.1779 + { NPPAIJ *a1, *a2;
253.1780 + a1 = p->ptr, a2 = a1->r_next;
253.1781 + if (fabs(a2->val) < 0.001 * fabs(a1->val))
253.1782 + { /* only first column can be eliminated, because second one
253.1783 + has too small constraint coefficient */
253.1784 + apq = a1, apr = a2;
253.1785 + }
253.1786 + else if (fabs(a1->val) < 0.001 * fabs(a2->val))
253.1787 + { /* only second column can be eliminated, because first one
253.1788 + has too small constraint coefficient */
253.1789 + apq = a2, apr = a1;
253.1790 + }
253.1791 + else
253.1792 + { /* both columns are appropriate; choose that one which is
253.1793 + shorter to minimize fill-in */
253.1794 + if (npp_col_nnz(npp, a1->col) <= npp_col_nnz(npp, a2->col))
253.1795 + { /* first column is shorter */
253.1796 + apq = a1, apr = a2;
253.1797 + }
253.1798 + else
253.1799 + { /* second column is shorter */
253.1800 + apq = a2, apr = a1;
253.1801 + }
253.1802 + }
253.1803 + }
253.1804 + /* now columns q and r have been chosen */
253.1805 + q = apq->col, r = apr->col;
253.1806 + /* create transformation stack entry */
253.1807 + info = npp_push_tse(npp,
253.1808 + rcv_eq_doublet, sizeof(struct eq_doublet));
253.1809 + info->p = p->i;
253.1810 + info->apq = apq->val;
253.1811 + info->ptr = NULL;
253.1812 + /* transform each row i (i != p), where a[i,q] != 0, to eliminate
253.1813 + column q */
253.1814 + for (aiq = q->ptr; aiq != NULL; aiq = next)
253.1815 + { next = aiq->c_next;
253.1816 + if (aiq == apq) continue; /* skip row p */
253.1817 + i = aiq->row; /* row i to be transformed */
253.1818 + /* save constraint coefficient a[i,q] */
253.1819 + if (npp->sol != GLP_MIP)
253.1820 + { lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
253.1821 + lfe->ref = i->i;
253.1822 + lfe->val = aiq->val;
253.1823 + lfe->next = info->ptr;
253.1824 + info->ptr = lfe;
253.1825 + }
253.1826 + /* find coefficient a[i,r] in row i */
253.1827 + for (air = i->ptr; air != NULL; air = air->r_next)
253.1828 + if (air->col == r) break;
253.1829 + /* if a[i,r] does not exist, create a[i,r] = 0 */
253.1830 + if (air == NULL)
253.1831 + air = npp_add_aij(npp, i, r, 0.0);
253.1832 + /* compute gamma[i] = a[i,q] / a[p,q] */
253.1833 + gamma = aiq->val / apq->val;
253.1834 + /* (row i) := (row i) - gamma[i] * (row p); see (3)-(6) */
253.1835 + /* new a[i,q] is exact zero due to elimnation; remove it from
253.1836 + row i */
253.1837 + npp_del_aij(npp, aiq);
253.1838 + /* compute new a[i,r] */
253.1839 + air->val -= gamma * apr->val;
253.1840 + /* if new a[i,r] is close to zero due to numeric cancelation,
253.1841 + remove it from row i */
253.1842 + if (fabs(air->val) <= 1e-10)
253.1843 + npp_del_aij(npp, air);
253.1844 + /* compute new lower and upper bounds of row i */
253.1845 + if (i->lb == i->ub)
253.1846 + i->lb = i->ub = (i->lb - gamma * p->lb);
253.1847 + else
253.1848 + { if (i->lb != -DBL_MAX)
253.1849 + i->lb -= gamma * p->lb;
253.1850 + if (i->ub != +DBL_MAX)
253.1851 + i->ub -= gamma * p->lb;
253.1852 + }
253.1853 + }
253.1854 + return q;
253.1855 +}
253.1856 +
253.1857 +static int rcv_eq_doublet(NPP *npp, void *_info)
253.1858 +{ /* recover row doubleton (equality constraint) */
253.1859 + struct eq_doublet *info = _info;
253.1860 + NPPLFE *lfe;
253.1861 + double gamma, temp;
253.1862 + /* we assume that processing row p is followed by processing
253.1863 + column q as singleton of type "implied slack variable", in
253.1864 + which case row p must always be active equality constraint */
253.1865 + if (npp->sol == GLP_SOL)
253.1866 + { if (npp->r_stat[info->p] != GLP_NS)
253.1867 + { npp_error();
253.1868 + return 1;
253.1869 + }
253.1870 + }
253.1871 + if (npp->sol != GLP_MIP)
253.1872 + { /* compute value of multiplier for row p; see (14) */
253.1873 + temp = npp->r_pi[info->p];
253.1874 + for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
253.1875 + { gamma = lfe->val / info->apq; /* a[i,q] / a[p,q] */
253.1876 + temp -= gamma * npp->r_pi[lfe->ref];
253.1877 + }
253.1878 + npp->r_pi[info->p] = temp;
253.1879 + }
253.1880 + return 0;
253.1881 +}
253.1882 +
253.1883 +/***********************************************************************
253.1884 +* NAME
253.1885 +*
253.1886 +* npp_forcing_row - process forcing row
253.1887 +*
253.1888 +* SYNOPSIS
253.1889 +*
253.1890 +* #include "glpnpp.h"
253.1891 +* int npp_forcing_row(NPP *npp, NPPROW *p, int at);
253.1892 +*
253.1893 +* DESCRIPTION
253.1894 +*
253.1895 +* The routine npp_forcing row processes row p of general format:
253.1896 +*
253.1897 +* L[p] <= sum a[p,j] x[j] <= U[p], (1)
253.1898 +* j
253.1899 +*
253.1900 +* l[j] <= x[j] <= u[j], (2)
253.1901 +*
253.1902 +* where L[p] <= U[p] and l[j] < u[j] for all a[p,j] != 0. It is also
253.1903 +* assumed that:
253.1904 +*
253.1905 +* 1) if at = 0 then |L[p] - U'[p]| <= eps, where U'[p] is implied
253.1906 +* row upper bound (see below), eps is an absolute tolerance for row
253.1907 +* value;
253.1908 +*
253.1909 +* 2) if at = 1 then |U[p] - L'[p]| <= eps, where L'[p] is implied
253.1910 +* row lower bound (see below).
253.1911 +*
253.1912 +* RETURNS
253.1913 +*
253.1914 +* 0 - success;
253.1915 +*
253.1916 +* 1 - cannot fix columns due to too small constraint coefficients.
253.1917 +*
253.1918 +* PROBLEM TRANSFORMATION
253.1919 +*
253.1920 +* Implied lower and upper bounds of row (1) are determined by bounds
253.1921 +* of corresponding columns (variables) as follows:
253.1922 +*
253.1923 +* L'[p] = inf sum a[p,j] x[j] =
253.1924 +* j
253.1925 +* (3)
253.1926 +* = sum a[p,j] l[j] + sum a[p,j] u[j],
253.1927 +* j in Jp j in Jn
253.1928 +*
253.1929 +* U'[p] = sup sum a[p,j] x[j] =
253.1930 +* (4)
253.1931 +* = sum a[p,j] u[j] + sum a[p,j] l[j],
253.1932 +* j in Jp j in Jn
253.1933 +*
253.1934 +* Jp = {j: a[p,j] > 0}, Jn = {j: a[p,j] < 0}. (5)
253.1935 +*
253.1936 +* If L[p] =~ U'[p] (at = 0), solution can be primal feasible only when
253.1937 +* all variables take their boundary values as defined by (4):
253.1938 +*
253.1939 +* ( u[j], if j in Jp
253.1940 +* x[j] = < (6)
253.1941 +* ( l[j], if j in Jn
253.1942 +*
253.1943 +* Similarly, if U[p] =~ L'[p] (at = 1), solution can be primal feasible
253.1944 +* only when all variables take their boundary values as defined by (3):
253.1945 +*
253.1946 +* ( l[j], if j in Jp
253.1947 +* x[j] = < (7)
253.1948 +* ( u[j], if j in Jn
253.1949 +*
253.1950 +* Condition (6) or (7) allows fixing all columns (variables x[j])
253.1951 +* in row (1) on their bounds and then removing them from the problem
253.1952 +* (see the routine npp_fixed_col). Due to this row p becomes redundant,
253.1953 +* so it can be replaced by equivalent free (unbounded) row and also
253.1954 +* removed from the problem (see the routine npp_free_row).
253.1955 +*
253.1956 +* 1. To apply this transformation row (1) should not have coefficients
253.1957 +* whose magnitude is too small, i.e. all a[p,j] should satisfy to
253.1958 +* the following condition:
253.1959 +*
253.1960 +* |a[p,j]| >= eps * max(1, |a[p,k]|), (8)
253.1961 +* k
253.1962 +* where eps is a relative tolerance for constraint coefficients.
253.1963 +* Otherwise, fixing columns may be numerically unreliable and may
253.1964 +* lead to wrong solution.
253.1965 +*
253.1966 +* 2. The routine fixes columns and remove bounds of row p, however,
253.1967 +* it does not remove the row and columns from the problem.
253.1968 +*
253.1969 +* RECOVERING BASIC SOLUTION
253.1970 +*
253.1971 +* In the transformed problem row p being inactive constraint is
253.1972 +* assigned status GLP_BS (as the result of transformation of free
253.1973 +* row), and all columns in this row are assigned status GLP_NS (as the
253.1974 +* result of transformation of fixed columns).
253.1975 +*
253.1976 +* Note that in the dual system of the transformed (as well as original)
253.1977 +* problem every column j in row p corresponds to the following row:
253.1978 +*
253.1979 +* sum a[i,j] pi[i] + a[p,j] pi[p] + lambda[j] = c[j], (9)
253.1980 +* i!=p
253.1981 +*
253.1982 +* from which it follows that:
253.1983 +*
253.1984 +* lambda[j] = c[j] - sum a[i,j] pi[i] - a[p,j] pi[p]. (10)
253.1985 +* i!=p
253.1986 +*
253.1987 +* In the transformed problem values of all multipliers pi[i] are known
253.1988 +* (including pi[i], whose value is zero, since row p is inactive).
253.1989 +* Thus, using formula (10) it is possible to compute values of
253.1990 +* multipliers lambda[j] for all columns in row p.
253.1991 +*
253.1992 +* Note also that in the original problem all columns in row p are
253.1993 +* bounded, not fixed. So status GLP_NS assigned to every such column
253.1994 +* must be changed to GLP_NL or GLP_NU depending on which bound the
253.1995 +* corresponding column has been fixed. This status change may lead to
253.1996 +* dual feasibility violation for solution of the original problem,
253.1997 +* because now column multipliers must satisfy to the following
253.1998 +* condition:
253.1999 +*
253.2000 +* ( >= 0, if status of column j is GLP_NL,
253.2001 +* lambda[j] < (11)
253.2002 +* ( <= 0, if status of column j is GLP_NU.
253.2003 +*
253.2004 +* If this condition holds, solution to the original problem is the
253.2005 +* same as to the transformed problem. Otherwise, we have to perform
253.2006 +* one degenerate pivoting step of the primal simplex method to obtain
253.2007 +* dual feasible (hence, optimal) solution to the original problem as
253.2008 +* follows. If, on problem transformation, row p was made active on its
253.2009 +* lower bound (case at = 0), we change its status to GLP_NL (or GLP_NS)
253.2010 +* and start increasing its multiplier pi[p]. Otherwise, if row p was
253.2011 +* made active on its upper bound (case at = 1), we change its status
253.2012 +* to GLP_NU (or GLP_NS) and start decreasing pi[p]. From (10) it
253.2013 +* follows that:
253.2014 +*
253.2015 +* delta lambda[j] = - a[p,j] * delta pi[p] = - a[p,j] pi[p]. (12)
253.2016 +*
253.2017 +* Simple analysis of formulae (3)-(5) shows that changing pi[p] in the
253.2018 +* specified direction causes increasing lambda[j] for every column j
253.2019 +* assigned status GLP_NL (delta lambda[j] > 0) and decreasing lambda[j]
253.2020 +* for every column j assigned status GLP_NU (delta lambda[j] < 0). It
253.2021 +* is understood that once the last lambda[q], which violates condition
253.2022 +* (11), has reached zero, multipliers lambda[j] for all columns get
253.2023 +* valid signs. Such column q can be determined as follows. Let d[j] be
253.2024 +* initial value of lambda[j] (i.e. reduced cost of column j) in the
253.2025 +* transformed problem computed with formula (10) when pi[p] = 0. Then
253.2026 +* lambda[j] = d[j] + delta lambda[j], and from (12) it follows that
253.2027 +* lambda[j] becomes zero if:
253.2028 +*
253.2029 +* delta lambda[j] = - a[p,j] pi[p] = - d[j] ==>
253.2030 +* (13)
253.2031 +* pi[p] = d[j] / a[p,j].
253.2032 +*
253.2033 +* Therefore, the last column q, for which lambda[q] becomes zero, can
253.2034 +* be determined from the following condition:
253.2035 +*
253.2036 +* |d[q] / a[p,q]| = max |pi[p]| = max |d[j] / a[p,j]|, (14)
253.2037 +* j in D j in D
253.2038 +*
253.2039 +* where D is a set of columns j whose, reduced costs d[j] have invalid
253.2040 +* signs, i.e. violate condition (11). (Thus, if D is empty, solution
253.2041 +* to the original problem is the same as solution to the transformed
253.2042 +* problem, and no correction is needed as was noticed above.) In
253.2043 +* solution to the original problem column q is assigned status GLP_BS,
253.2044 +* since it replaces column of auxiliary variable of row p (becoming
253.2045 +* active) in the basis, and multiplier for row p is assigned its new
253.2046 +* value, which is pi[p] = d[q] / a[p,q]. Note that due to primal
253.2047 +* degeneracy values of all columns having non-zero coefficients in row
253.2048 +* p remain unchanged.
253.2049 +*
253.2050 +* RECOVERING INTERIOR-POINT SOLUTION
253.2051 +*
253.2052 +* Value of multiplier pi[p] in solution to the original problem is
253.2053 +* corrected in the same way as for basic solution. Values of all
253.2054 +* columns having non-zero coefficients in row p remain unchanged.
253.2055 +*
253.2056 +* RECOVERING MIP SOLUTION
253.2057 +*
253.2058 +* None needed. */
253.2059 +
253.2060 +struct forcing_col
253.2061 +{ /* column fixed on its bound by forcing row */
253.2062 + int j;
253.2063 + /* column reference number */
253.2064 + char stat;
253.2065 + /* original column status:
253.2066 + GLP_NL - fixed on lower bound
253.2067 + GLP_NU - fixed on upper bound */
253.2068 + double a;
253.2069 + /* constraint coefficient a[p,j] */
253.2070 + double c;
253.2071 + /* objective coefficient c[j] */
253.2072 + NPPLFE *ptr;
253.2073 + /* list of non-zero coefficients a[i,j], i != p */
253.2074 + struct forcing_col *next;
253.2075 + /* pointer to another column fixed by forcing row */
253.2076 +};
253.2077 +
253.2078 +struct forcing_row
253.2079 +{ /* forcing row */
253.2080 + int p;
253.2081 + /* row reference number */
253.2082 + char stat;
253.2083 + /* status assigned to the row if it becomes active:
253.2084 + GLP_NS - active equality constraint
253.2085 + GLP_NL - inequality constraint with lower bound active
253.2086 + GLP_NU - inequality constraint with upper bound active */
253.2087 + struct forcing_col *ptr;
253.2088 + /* list of all columns having non-zero constraint coefficient
253.2089 + a[p,j] in the forcing row */
253.2090 +};
253.2091 +
253.2092 +static int rcv_forcing_row(NPP *npp, void *info);
253.2093 +
253.2094 +int npp_forcing_row(NPP *npp, NPPROW *p, int at)
253.2095 +{ /* process forcing row */
253.2096 + struct forcing_row *info;
253.2097 + struct forcing_col *col = NULL;
253.2098 + NPPCOL *j;
253.2099 + NPPAIJ *apj, *aij;
253.2100 + NPPLFE *lfe;
253.2101 + double big;
253.2102 + xassert(at == 0 || at == 1);
253.2103 + /* determine maximal magnitude of the row coefficients */
253.2104 + big = 1.0;
253.2105 + for (apj = p->ptr; apj != NULL; apj = apj->r_next)
253.2106 + if (big < fabs(apj->val)) big = fabs(apj->val);
253.2107 + /* if there are too small coefficients in the row, transformation
253.2108 + should not be applied */
253.2109 + for (apj = p->ptr; apj != NULL; apj = apj->r_next)
253.2110 + if (fabs(apj->val) < 1e-7 * big) return 1;
253.2111 + /* create transformation stack entry */
253.2112 + info = npp_push_tse(npp,
253.2113 + rcv_forcing_row, sizeof(struct forcing_row));
253.2114 + info->p = p->i;
253.2115 + if (p->lb == p->ub)
253.2116 + { /* equality constraint */
253.2117 + info->stat = GLP_NS;
253.2118 + }
253.2119 + else if (at == 0)
253.2120 + { /* inequality constraint; case L[p] = U'[p] */
253.2121 + info->stat = GLP_NL;
253.2122 + xassert(p->lb != -DBL_MAX);
253.2123 + }
253.2124 + else /* at == 1 */
253.2125 + { /* inequality constraint; case U[p] = L'[p] */
253.2126 + info->stat = GLP_NU;
253.2127 + xassert(p->ub != +DBL_MAX);
253.2128 + }
253.2129 + info->ptr = NULL;
253.2130 + /* scan the forcing row, fix columns at corresponding bounds, and
253.2131 + save column information (the latter is not needed for MIP) */
253.2132 + for (apj = p->ptr; apj != NULL; apj = apj->r_next)
253.2133 + { /* column j has non-zero coefficient in the forcing row */
253.2134 + j = apj->col;
253.2135 + /* it must be non-fixed */
253.2136 + xassert(j->lb < j->ub);
253.2137 + /* allocate stack entry to save column information */
253.2138 + if (npp->sol != GLP_MIP)
253.2139 + { col = dmp_get_atom(npp->stack, sizeof(struct forcing_col));
253.2140 + col->j = j->j;
253.2141 + col->stat = -1; /* will be set below */
253.2142 + col->a = apj->val;
253.2143 + col->c = j->coef;
253.2144 + col->ptr = NULL;
253.2145 + col->next = info->ptr;
253.2146 + info->ptr = col;
253.2147 + }
253.2148 + /* fix column j */
253.2149 + if (at == 0 && apj->val < 0.0 || at != 0 && apj->val > 0.0)
253.2150 + { /* at its lower bound */
253.2151 + if (npp->sol != GLP_MIP)
253.2152 + col->stat = GLP_NL;
253.2153 + xassert(j->lb != -DBL_MAX);
253.2154 + j->ub = j->lb;
253.2155 + }
253.2156 + else
253.2157 + { /* at its upper bound */
253.2158 + if (npp->sol != GLP_MIP)
253.2159 + col->stat = GLP_NU;
253.2160 + xassert(j->ub != +DBL_MAX);
253.2161 + j->lb = j->ub;
253.2162 + }
253.2163 + /* save column coefficients a[i,j], i != p */
253.2164 + if (npp->sol != GLP_MIP)
253.2165 + { for (aij = j->ptr; aij != NULL; aij = aij->c_next)
253.2166 + { if (aij == apj) continue; /* skip a[p,j] */
253.2167 + lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
253.2168 + lfe->ref = aij->row->i;
253.2169 + lfe->val = aij->val;
253.2170 + lfe->next = col->ptr;
253.2171 + col->ptr = lfe;
253.2172 + }
253.2173 + }
253.2174 + }
253.2175 + /* make the row free (unbounded) */
253.2176 + p->lb = -DBL_MAX, p->ub = +DBL_MAX;
253.2177 + return 0;
253.2178 +}
253.2179 +
253.2180 +static int rcv_forcing_row(NPP *npp, void *_info)
253.2181 +{ /* recover forcing row */
253.2182 + struct forcing_row *info = _info;
253.2183 + struct forcing_col *col, *piv;
253.2184 + NPPLFE *lfe;
253.2185 + double d, big, temp;
253.2186 + if (npp->sol == GLP_MIP) goto done;
253.2187 + /* initially solution to the original problem is the same as
253.2188 + to the transformed problem, where row p is inactive constraint
253.2189 + with pi[p] = 0, and all columns are non-basic */
253.2190 + if (npp->sol == GLP_SOL)
253.2191 + { if (npp->r_stat[info->p] != GLP_BS)
253.2192 + { npp_error();
253.2193 + return 1;
253.2194 + }
253.2195 + for (col = info->ptr; col != NULL; col = col->next)
253.2196 + { if (npp->c_stat[col->j] != GLP_NS)
253.2197 + { npp_error();
253.2198 + return 1;
253.2199 + }
253.2200 + npp->c_stat[col->j] = col->stat; /* original status */
253.2201 + }
253.2202 + }
253.2203 + /* compute reduced costs d[j] for all columns with formula (10)
253.2204 + and store them in col.c instead objective coefficients */
253.2205 + for (col = info->ptr; col != NULL; col = col->next)
253.2206 + { d = col->c;
253.2207 + for (lfe = col->ptr; lfe != NULL; lfe = lfe->next)
253.2208 + d -= lfe->val * npp->r_pi[lfe->ref];
253.2209 + col->c = d;
253.2210 + }
253.2211 + /* consider columns j, whose multipliers lambda[j] has wrong
253.2212 + sign in solution to the transformed problem (where lambda[j] =
253.2213 + d[j]), and choose column q, whose multipler lambda[q] reaches
253.2214 + zero last on changing row multiplier pi[p]; see (14) */
253.2215 + piv = NULL, big = 0.0;
253.2216 + for (col = info->ptr; col != NULL; col = col->next)
253.2217 + { d = col->c; /* d[j] */
253.2218 + temp = fabs(d / col->a);
253.2219 + if (col->stat == GLP_NL)
253.2220 + { /* column j has active lower bound */
253.2221 + if (d < 0.0 && big < temp)
253.2222 + piv = col, big = temp;
253.2223 + }
253.2224 + else if (col->stat == GLP_NU)
253.2225 + { /* column j has active upper bound */
253.2226 + if (d > 0.0 && big < temp)
253.2227 + piv = col, big = temp;
253.2228 + }
253.2229 + else
253.2230 + { npp_error();
253.2231 + return 1;
253.2232 + }
253.2233 + }
253.2234 + /* if column q does not exist, no correction is needed */
253.2235 + if (piv != NULL)
253.2236 + { /* correct solution; row p becomes active constraint while
253.2237 + column q becomes basic */
253.2238 + if (npp->sol == GLP_SOL)
253.2239 + { npp->r_stat[info->p] = info->stat;
253.2240 + npp->c_stat[piv->j] = GLP_BS;
253.2241 + }
253.2242 + /* assign new value to row multiplier pi[p] = d[p] / a[p,q] */
253.2243 + npp->r_pi[info->p] = piv->c / piv->a;
253.2244 + }
253.2245 +done: return 0;
253.2246 +}
253.2247 +
253.2248 +/***********************************************************************
253.2249 +* NAME
253.2250 +*
253.2251 +* npp_analyze_row - perform general row analysis
253.2252 +*
253.2253 +* SYNOPSIS
253.2254 +*
253.2255 +* #include "glpnpp.h"
253.2256 +* int npp_analyze_row(NPP *npp, NPPROW *p);
253.2257 +*
253.2258 +* DESCRIPTION
253.2259 +*
253.2260 +* The routine npp_analyze_row performs analysis of row p of general
253.2261 +* format:
253.2262 +*
253.2263 +* L[p] <= sum a[p,j] x[j] <= U[p], (1)
253.2264 +* j
253.2265 +*
253.2266 +* l[j] <= x[j] <= u[j], (2)
253.2267 +*
253.2268 +* where L[p] <= U[p] and l[j] <= u[j] for all a[p,j] != 0.
253.2269 +*
253.2270 +* RETURNS
253.2271 +*
253.2272 +* 0x?0 - row lower bound does not exist or is redundant;
253.2273 +*
253.2274 +* 0x?1 - row lower bound can be active;
253.2275 +*
253.2276 +* 0x?2 - row lower bound is a forcing bound;
253.2277 +*
253.2278 +* 0x0? - row upper bound does not exist or is redundant;
253.2279 +*
253.2280 +* 0x1? - row upper bound can be active;
253.2281 +*
253.2282 +* 0x2? - row upper bound is a forcing bound;
253.2283 +*
253.2284 +* 0x33 - row bounds are inconsistent with column bounds.
253.2285 +*
253.2286 +* ALGORITHM
253.2287 +*
253.2288 +* Analysis of row (1) is based on analysis of its implied lower and
253.2289 +* upper bounds, which are determined by bounds of corresponding columns
253.2290 +* (variables) as follows:
253.2291 +*
253.2292 +* L'[p] = inf sum a[p,j] x[j] =
253.2293 +* j
253.2294 +* (3)
253.2295 +* = sum a[p,j] l[j] + sum a[p,j] u[j],
253.2296 +* j in Jp j in Jn
253.2297 +*
253.2298 +* U'[p] = sup sum a[p,j] x[j] =
253.2299 +* (4)
253.2300 +* = sum a[p,j] u[j] + sum a[p,j] l[j],
253.2301 +* j in Jp j in Jn
253.2302 +*
253.2303 +* Jp = {j: a[p,j] > 0}, Jn = {j: a[p,j] < 0}. (5)
253.2304 +*
253.2305 +* (Note that bounds of all columns in row p are assumed to be correct,
253.2306 +* so L'[p] <= U'[p].)
253.2307 +*
253.2308 +* Analysis of row lower bound L[p] includes the following cases:
253.2309 +*
253.2310 +* 1) if L[p] > U'[p] + eps, where eps is an absolute tolerance for row
253.2311 +* value, row lower bound L[p] and implied row upper bound U'[p] are
253.2312 +* inconsistent, ergo, the problem has no primal feasible solution;
253.2313 +*
253.2314 +* 2) if U'[p] - eps <= L[p] <= U'[p] + eps, i.e. if L[p] =~ U'[p],
253.2315 +* the row is a forcing row on its lower bound (see description of
253.2316 +* the routine npp_forcing_row);
253.2317 +*
253.2318 +* 3) if L[p] > L'[p] + eps, row lower bound L[p] can be active (this
253.2319 +* conclusion does not account other rows in the problem);
253.2320 +*
253.2321 +* 4) if L[p] <= L'[p] + eps, row lower bound L[p] cannot be active, so
253.2322 +* it is redundant and can be removed (replaced by -oo).
253.2323 +*
253.2324 +* Analysis of row upper bound U[p] is performed in a similar way and
253.2325 +* includes the following cases:
253.2326 +*
253.2327 +* 1) if U[p] < L'[p] - eps, row upper bound U[p] and implied row lower
253.2328 +* bound L'[p] are inconsistent, ergo the problem has no primal
253.2329 +* feasible solution;
253.2330 +*
253.2331 +* 2) if L'[p] - eps <= U[p] <= L'[p] + eps, i.e. if U[p] =~ L'[p],
253.2332 +* the row is a forcing row on its upper bound (see description of
253.2333 +* the routine npp_forcing_row);
253.2334 +*
253.2335 +* 3) if U[p] < U'[p] - eps, row upper bound U[p] can be active (this
253.2336 +* conclusion does not account other rows in the problem);
253.2337 +*
253.2338 +* 4) if U[p] >= U'[p] - eps, row upper bound U[p] cannot be active, so
253.2339 +* it is redundant and can be removed (replaced by +oo). */
253.2340 +
253.2341 +int npp_analyze_row(NPP *npp, NPPROW *p)
253.2342 +{ /* perform general row analysis */
253.2343 + NPPAIJ *aij;
253.2344 + int ret = 0x00;
253.2345 + double l, u, eps;
253.2346 + xassert(npp == npp);
253.2347 + /* compute implied lower bound L'[p]; see (3) */
253.2348 + l = 0.0;
253.2349 + for (aij = p->ptr; aij != NULL; aij = aij->r_next)
253.2350 + { if (aij->val > 0.0)
253.2351 + { if (aij->col->lb == -DBL_MAX)
253.2352 + { l = -DBL_MAX;
253.2353 + break;
253.2354 + }
253.2355 + l += aij->val * aij->col->lb;
253.2356 + }
253.2357 + else /* aij->val < 0.0 */
253.2358 + { if (aij->col->ub == +DBL_MAX)
253.2359 + { l = -DBL_MAX;
253.2360 + break;
253.2361 + }
253.2362 + l += aij->val * aij->col->ub;
253.2363 + }
253.2364 + }
253.2365 + /* compute implied upper bound U'[p]; see (4) */
253.2366 + u = 0.0;
253.2367 + for (aij = p->ptr; aij != NULL; aij = aij->r_next)
253.2368 + { if (aij->val > 0.0)
253.2369 + { if (aij->col->ub == +DBL_MAX)
253.2370 + { u = +DBL_MAX;
253.2371 + break;
253.2372 + }
253.2373 + u += aij->val * aij->col->ub;
253.2374 + }
253.2375 + else /* aij->val < 0.0 */
253.2376 + { if (aij->col->lb == -DBL_MAX)
253.2377 + { u = +DBL_MAX;
253.2378 + break;
253.2379 + }
253.2380 + u += aij->val * aij->col->lb;
253.2381 + }
253.2382 + }
253.2383 + /* column bounds are assumed correct, so L'[p] <= U'[p] */
253.2384 + /* check if row lower bound is consistent */
253.2385 + if (p->lb != -DBL_MAX)
253.2386 + { eps = 1e-3 + 1e-6 * fabs(p->lb);
253.2387 + if (p->lb - eps > u)
253.2388 + { ret = 0x33;
253.2389 + goto done;
253.2390 + }
253.2391 + }
253.2392 + /* check if row upper bound is consistent */
253.2393 + if (p->ub != +DBL_MAX)
253.2394 + { eps = 1e-3 + 1e-6 * fabs(p->ub);
253.2395 + if (p->ub + eps < l)
253.2396 + { ret = 0x33;
253.2397 + goto done;
253.2398 + }
253.2399 + }
253.2400 + /* check if row lower bound can be active/forcing */
253.2401 + if (p->lb != -DBL_MAX)
253.2402 + { eps = 1e-9 + 1e-12 * fabs(p->lb);
253.2403 + if (p->lb - eps > l)
253.2404 + { if (p->lb + eps <= u)
253.2405 + ret |= 0x01;
253.2406 + else
253.2407 + ret |= 0x02;
253.2408 + }
253.2409 + }
253.2410 + /* check if row upper bound can be active/forcing */
253.2411 + if (p->ub != +DBL_MAX)
253.2412 + { eps = 1e-9 + 1e-12 * fabs(p->ub);
253.2413 + if (p->ub + eps < u)
253.2414 + { /* check if the upper bound is forcing */
253.2415 + if (p->ub - eps >= l)
253.2416 + ret |= 0x10;
253.2417 + else
253.2418 + ret |= 0x20;
253.2419 + }
253.2420 + }
253.2421 +done: return ret;
253.2422 +}
253.2423 +
253.2424 +/***********************************************************************
253.2425 +* NAME
253.2426 +*
253.2427 +* npp_inactive_bound - remove row lower/upper inactive bound
253.2428 +*
253.2429 +* SYNOPSIS
253.2430 +*
253.2431 +* #include "glpnpp.h"
253.2432 +* void npp_inactive_bound(NPP *npp, NPPROW *p, int which);
253.2433 +*
253.2434 +* DESCRIPTION
253.2435 +*
253.2436 +* The routine npp_inactive_bound removes lower (if which = 0) or upper
253.2437 +* (if which = 1) bound of row p:
253.2438 +*
253.2439 +* L[p] <= sum a[p,j] x[j] <= U[p],
253.2440 +*
253.2441 +* which (bound) is assumed to be redundant.
253.2442 +*
253.2443 +* PROBLEM TRANSFORMATION
253.2444 +*
253.2445 +* If which = 0, current lower bound L[p] of row p is assigned -oo.
253.2446 +* If which = 1, current upper bound U[p] of row p is assigned +oo.
253.2447 +*
253.2448 +* RECOVERING BASIC SOLUTION
253.2449 +*
253.2450 +* If in solution to the transformed problem row p is inactive
253.2451 +* constraint (GLP_BS), its status is not changed in solution to the
253.2452 +* original problem. Otherwise, status of row p in solution to the
253.2453 +* original problem is defined by its type before transformation and
253.2454 +* its status in solution to the transformed problem as follows:
253.2455 +*
253.2456 +* +---------------------+-------+---------------+---------------+
253.2457 +* | Row | Flag | Row status in | Row status in |
253.2458 +* | type | which | transfmd soln | original soln |
253.2459 +* +---------------------+-------+---------------+---------------+
253.2460 +* | sum >= L[p] | 0 | GLP_NF | GLP_NL |
253.2461 +* | sum <= U[p] | 1 | GLP_NF | GLP_NU |
253.2462 +* | L[p] <= sum <= U[p] | 0 | GLP_NU | GLP_NU |
253.2463 +* | L[p] <= sum <= U[p] | 1 | GLP_NL | GLP_NL |
253.2464 +* | sum = L[p] = U[p] | 0 | GLP_NU | GLP_NS |
253.2465 +* | sum = L[p] = U[p] | 1 | GLP_NL | GLP_NS |
253.2466 +* +---------------------+-------+---------------+---------------+
253.2467 +*
253.2468 +* RECOVERING INTERIOR-POINT SOLUTION
253.2469 +*
253.2470 +* None needed.
253.2471 +*
253.2472 +* RECOVERING MIP SOLUTION
253.2473 +*
253.2474 +* None needed. */
253.2475 +
253.2476 +struct inactive_bound
253.2477 +{ /* row inactive bound */
253.2478 + int p;
253.2479 + /* row reference number */
253.2480 + char stat;
253.2481 + /* row status (if active constraint) */
253.2482 +};
253.2483 +
253.2484 +static int rcv_inactive_bound(NPP *npp, void *info);
253.2485 +
253.2486 +void npp_inactive_bound(NPP *npp, NPPROW *p, int which)
253.2487 +{ /* remove row lower/upper inactive bound */
253.2488 + struct inactive_bound *info;
253.2489 + if (npp->sol == GLP_SOL)
253.2490 + { /* create transformation stack entry */
253.2491 + info = npp_push_tse(npp,
253.2492 + rcv_inactive_bound, sizeof(struct inactive_bound));
253.2493 + info->p = p->i;
253.2494 + if (p->ub == +DBL_MAX)
253.2495 + info->stat = GLP_NL;
253.2496 + else if (p->lb == -DBL_MAX)
253.2497 + info->stat = GLP_NU;
253.2498 + else if (p->lb != p->ub)
253.2499 + info->stat = (char)(which == 0 ? GLP_NU : GLP_NL);
253.2500 + else
253.2501 + info->stat = GLP_NS;
253.2502 + }
253.2503 + /* remove row inactive bound */
253.2504 + if (which == 0)
253.2505 + { xassert(p->lb != -DBL_MAX);
253.2506 + p->lb = -DBL_MAX;
253.2507 + }
253.2508 + else if (which == 1)
253.2509 + { xassert(p->ub != +DBL_MAX);
253.2510 + p->ub = +DBL_MAX;
253.2511 + }
253.2512 + else
253.2513 + xassert(which != which);
253.2514 + return;
253.2515 +}
253.2516 +
253.2517 +static int rcv_inactive_bound(NPP *npp, void *_info)
253.2518 +{ /* recover row status */
253.2519 + struct inactive_bound *info = _info;
253.2520 + if (npp->sol != GLP_SOL)
253.2521 + { npp_error();
253.2522 + return 1;
253.2523 + }
253.2524 + if (npp->r_stat[info->p] == GLP_BS)
253.2525 + npp->r_stat[info->p] = GLP_BS;
253.2526 + else
253.2527 + npp->r_stat[info->p] = info->stat;
253.2528 + return 0;
253.2529 +}
253.2530 +
253.2531 +/***********************************************************************
253.2532 +* NAME
253.2533 +*
253.2534 +* npp_implied_bounds - determine implied column bounds
253.2535 +*
253.2536 +* SYNOPSIS
253.2537 +*
253.2538 +* #include "glpnpp.h"
253.2539 +* void npp_implied_bounds(NPP *npp, NPPROW *p);
253.2540 +*
253.2541 +* DESCRIPTION
253.2542 +*
253.2543 +* The routine npp_implied_bounds inspects general row (constraint) p:
253.2544 +*
253.2545 +* L[p] <= sum a[p,j] x[j] <= U[p], (1)
253.2546 +*
253.2547 +* l[j] <= x[j] <= u[j], (2)
253.2548 +*
253.2549 +* where L[p] <= U[p] and l[j] <= u[j] for all a[p,j] != 0, to compute
253.2550 +* implied bounds of columns (variables x[j]) in this row.
253.2551 +*
253.2552 +* The routine stores implied column bounds l'[j] and u'[j] in column
253.2553 +* descriptors (NPPCOL); it does not change current column bounds l[j]
253.2554 +* and u[j]. (Implied column bounds can be then used to strengthen the
253.2555 +* current column bounds; see the routines npp_implied_lower and
253.2556 +* npp_implied_upper).
253.2557 +*
253.2558 +* ALGORITHM
253.2559 +*
253.2560 +* Current column bounds (2) define implied lower and upper bounds of
253.2561 +* row (1) as follows:
253.2562 +*
253.2563 +* L'[p] = inf sum a[p,j] x[j] =
253.2564 +* j
253.2565 +* (3)
253.2566 +* = sum a[p,j] l[j] + sum a[p,j] u[j],
253.2567 +* j in Jp j in Jn
253.2568 +*
253.2569 +* U'[p] = sup sum a[p,j] x[j] =
253.2570 +* (4)
253.2571 +* = sum a[p,j] u[j] + sum a[p,j] l[j],
253.2572 +* j in Jp j in Jn
253.2573 +*
253.2574 +* Jp = {j: a[p,j] > 0}, Jn = {j: a[p,j] < 0}. (5)
253.2575 +*
253.2576 +* (Note that bounds of all columns in row p are assumed to be correct,
253.2577 +* so L'[p] <= U'[p].)
253.2578 +*
253.2579 +* If L[p] > L'[p] and/or U[p] < U'[p], the lower and/or upper bound of
253.2580 +* row (1) can be active, in which case such row defines implied bounds
253.2581 +* of its variables.
253.2582 +*
253.2583 +* Let x[k] be some variable having in row (1) coefficient a[p,k] != 0.
253.2584 +* Consider a case when row lower bound can be active (L[p] > L'[p]):
253.2585 +*
253.2586 +* sum a[p,j] x[j] >= L[p] ==>
253.2587 +* j
253.2588 +*
253.2589 +* sum a[p,j] x[j] + a[p,k] x[k] >= L[p] ==>
253.2590 +* j!=k
253.2591 +* (6)
253.2592 +* a[p,k] x[k] >= L[p] - sum a[p,j] x[j] ==>
253.2593 +* j!=k
253.2594 +*
253.2595 +* a[p,k] x[k] >= L[p,k],
253.2596 +*
253.2597 +* where
253.2598 +*
253.2599 +* L[p,k] = inf(L[p] - sum a[p,j] x[j]) =
253.2600 +* j!=k
253.2601 +*
253.2602 +* = L[p] - sup sum a[p,j] x[j] = (7)
253.2603 +* j!=k
253.2604 +*
253.2605 +* = L[p] - sum a[p,j] u[j] - sum a[p,j] l[j].
253.2606 +* j in Jp\{k} j in Jn\{k}
253.2607 +*
253.2608 +* Thus:
253.2609 +*
253.2610 +* x[k] >= l'[k] = L[p,k] / a[p,k], if a[p,k] > 0, (8)
253.2611 +*
253.2612 +* x[k] <= u'[k] = L[p,k] / a[p,k], if a[p,k] < 0. (9)
253.2613 +*
253.2614 +* where l'[k] and u'[k] are implied lower and upper bounds of variable
253.2615 +* x[k], resp.
253.2616 +*
253.2617 +* Now consider a similar case when row upper bound can be active
253.2618 +* (U[p] < U'[p]):
253.2619 +*
253.2620 +* sum a[p,j] x[j] <= U[p] ==>
253.2621 +* j
253.2622 +*
253.2623 +* sum a[p,j] x[j] + a[p,k] x[k] <= U[p] ==>
253.2624 +* j!=k
253.2625 +* (10)
253.2626 +* a[p,k] x[k] <= U[p] - sum a[p,j] x[j] ==>
253.2627 +* j!=k
253.2628 +*
253.2629 +* a[p,k] x[k] <= U[p,k],
253.2630 +*
253.2631 +* where:
253.2632 +*
253.2633 +* U[p,k] = sup(U[p] - sum a[p,j] x[j]) =
253.2634 +* j!=k
253.2635 +*
253.2636 +* = U[p] - inf sum a[p,j] x[j] = (11)
253.2637 +* j!=k
253.2638 +*
253.2639 +* = U[p] - sum a[p,j] l[j] - sum a[p,j] u[j].
253.2640 +* j in Jp\{k} j in Jn\{k}
253.2641 +*
253.2642 +* Thus:
253.2643 +*
253.2644 +* x[k] <= u'[k] = U[p,k] / a[p,k], if a[p,k] > 0, (12)
253.2645 +*
253.2646 +* x[k] >= l'[k] = U[p,k] / a[p,k], if a[p,k] < 0. (13)
253.2647 +*
253.2648 +* Note that in formulae (8), (9), (12), and (13) coefficient a[p,k]
253.2649 +* must not be too small in magnitude relatively to other non-zero
253.2650 +* coefficients in row (1), i.e. the following condition must hold:
253.2651 +*
253.2652 +* |a[p,k]| >= eps * max(1, |a[p,j]|), (14)
253.2653 +* j
253.2654 +*
253.2655 +* where eps is a relative tolerance for constraint coefficients.
253.2656 +* Otherwise the implied column bounds can be numerical inreliable. For
253.2657 +* example, using formula (8) for the following inequality constraint:
253.2658 +*
253.2659 +* 1e-12 x1 - x2 - x3 >= 0,
253.2660 +*
253.2661 +* where x1 >= -1, x2, x3, >= 0, may lead to numerically unreliable
253.2662 +* conclusion that x1 >= 0.
253.2663 +*
253.2664 +* Using formulae (8), (9), (12), and (13) to compute implied bounds
253.2665 +* for one variable requires |J| operations, where J = {j: a[p,j] != 0},
253.2666 +* because this needs computing L[p,k] and U[p,k]. Thus, computing
253.2667 +* implied bounds for all variables in row (1) would require |J|^2
253.2668 +* operations, that is not a good technique. However, the total number
253.2669 +* of operations can be reduced to |J| as follows.
253.2670 +*
253.2671 +* Let a[p,k] > 0. Then from (7) and (11) we have:
253.2672 +*
253.2673 +* L[p,k] = L[p] - (U'[p] - a[p,k] u[k]) =
253.2674 +*
253.2675 +* = L[p] - U'[p] + a[p,k] u[k],
253.2676 +*
253.2677 +* U[p,k] = U[p] - (L'[p] - a[p,k] l[k]) =
253.2678 +*
253.2679 +* = U[p] - L'[p] + a[p,k] l[k],
253.2680 +*
253.2681 +* where L'[p] and U'[p] are implied row lower and upper bounds defined
253.2682 +* by formulae (3) and (4). Substituting these expressions into (8) and
253.2683 +* (12) gives:
253.2684 +*
253.2685 +* l'[k] = L[p,k] / a[p,k] = u[k] + (L[p] - U'[p]) / a[p,k], (15)
253.2686 +*
253.2687 +* u'[k] = U[p,k] / a[p,k] = l[k] + (U[p] - L'[p]) / a[p,k]. (16)
253.2688 +*
253.2689 +* Similarly, if a[p,k] < 0, according to (7) and (11) we have:
253.2690 +*
253.2691 +* L[p,k] = L[p] - (U'[p] - a[p,k] l[k]) =
253.2692 +*
253.2693 +* = L[p] - U'[p] + a[p,k] l[k],
253.2694 +*
253.2695 +* U[p,k] = U[p] - (L'[p] - a[p,k] u[k]) =
253.2696 +*
253.2697 +* = U[p] - L'[p] + a[p,k] u[k],
253.2698 +*
253.2699 +* and substituting these expressions into (8) and (12) gives:
253.2700 +*
253.2701 +* l'[k] = U[p,k] / a[p,k] = u[k] + (U[p] - L'[p]) / a[p,k], (17)
253.2702 +*
253.2703 +* u'[k] = L[p,k] / a[p,k] = l[k] + (L[p] - U'[p]) / a[p,k]. (18)
253.2704 +*
253.2705 +* Note that formulae (15)-(18) can be used only if L'[p] and U'[p]
253.2706 +* exist. However, if for some variable x[j] it happens that l[j] = -oo
253.2707 +* and/or u[j] = +oo, values of L'[p] (if a[p,j] > 0) and/or U'[p] (if
253.2708 +* a[p,j] < 0) are undefined. Consider, therefore, the most general
253.2709 +* situation, when some column bounds (2) may not exist.
253.2710 +*
253.2711 +* Let:
253.2712 +*
253.2713 +* J' = {j : (a[p,j] > 0 and l[j] = -oo) or
253.2714 +* (19)
253.2715 +* (a[p,j] < 0 and u[j] = +oo)}.
253.2716 +*
253.2717 +* Then (assuming that row upper bound U[p] can be active) the following
253.2718 +* three cases are possible:
253.2719 +*
253.2720 +* 1) |J'| = 0. In this case L'[p] exists, thus, for all variables x[j]
253.2721 +* in row (1) we can use formulae (16) and (17);
253.2722 +*
253.2723 +* 2) J' = {k}. In this case L'[p] = -oo, however, U[p,k] (11) exists,
253.2724 +* so for variable x[k] we can use formulae (12) and (13). Note that
253.2725 +* for all other variables x[j] (j != k) l'[j] = -oo (if a[p,j] < 0)
253.2726 +* or u'[j] = +oo (if a[p,j] > 0);
253.2727 +*
253.2728 +* 3) |J'| > 1. In this case for all variables x[j] in row [1] we have
253.2729 +* l'[j] = -oo (if a[p,j] < 0) or u'[j] = +oo (if a[p,j] > 0).
253.2730 +*
253.2731 +* Similarly, let:
253.2732 +*
253.2733 +* J'' = {j : (a[p,j] > 0 and u[j] = +oo) or
253.2734 +* (20)
253.2735 +* (a[p,j] < 0 and l[j] = -oo)}.
253.2736 +*
253.2737 +* Then (assuming that row lower bound L[p] can be active) the following
253.2738 +* three cases are possible:
253.2739 +*
253.2740 +* 1) |J''| = 0. In this case U'[p] exists, thus, for all variables x[j]
253.2741 +* in row (1) we can use formulae (15) and (18);
253.2742 +*
253.2743 +* 2) J'' = {k}. In this case U'[p] = +oo, however, L[p,k] (7) exists,
253.2744 +* so for variable x[k] we can use formulae (8) and (9). Note that
253.2745 +* for all other variables x[j] (j != k) l'[j] = -oo (if a[p,j] > 0)
253.2746 +* or u'[j] = +oo (if a[p,j] < 0);
253.2747 +*
253.2748 +* 3) |J''| > 1. In this case for all variables x[j] in row (1) we have
253.2749 +* l'[j] = -oo (if a[p,j] > 0) or u'[j] = +oo (if a[p,j] < 0). */
253.2750 +
253.2751 +void npp_implied_bounds(NPP *npp, NPPROW *p)
253.2752 +{ NPPAIJ *apj, *apk;
253.2753 + double big, eps, temp;
253.2754 + xassert(npp == npp);
253.2755 + /* initialize implied bounds for all variables and determine
253.2756 + maximal magnitude of row coefficients a[p,j] */
253.2757 + big = 1.0;
253.2758 + for (apj = p->ptr; apj != NULL; apj = apj->r_next)
253.2759 + { apj->col->ll.ll = -DBL_MAX, apj->col->uu.uu = +DBL_MAX;
253.2760 + if (big < fabs(apj->val)) big = fabs(apj->val);
253.2761 + }
253.2762 + eps = 1e-6 * big;
253.2763 + /* process row lower bound (assuming that it can be active) */
253.2764 + if (p->lb != -DBL_MAX)
253.2765 + { apk = NULL;
253.2766 + for (apj = p->ptr; apj != NULL; apj = apj->r_next)
253.2767 + { if (apj->val > 0.0 && apj->col->ub == +DBL_MAX ||
253.2768 + apj->val < 0.0 && apj->col->lb == -DBL_MAX)
253.2769 + { if (apk == NULL)
253.2770 + apk = apj;
253.2771 + else
253.2772 + goto skip1;
253.2773 + }
253.2774 + }
253.2775 + /* if a[p,k] = NULL then |J'| = 0 else J' = { k } */
253.2776 + temp = p->lb;
253.2777 + for (apj = p->ptr; apj != NULL; apj = apj->r_next)
253.2778 + { if (apj == apk)
253.2779 + /* skip a[p,k] */;
253.2780 + else if (apj->val > 0.0)
253.2781 + temp -= apj->val * apj->col->ub;
253.2782 + else /* apj->val < 0.0 */
253.2783 + temp -= apj->val * apj->col->lb;
253.2784 + }
253.2785 + /* compute column implied bounds */
253.2786 + if (apk == NULL)
253.2787 + { /* temp = L[p] - U'[p] */
253.2788 + for (apj = p->ptr; apj != NULL; apj = apj->r_next)
253.2789 + { if (apj->val >= +eps)
253.2790 + { /* l'[j] := u[j] + (L[p] - U'[p]) / a[p,j] */
253.2791 + apj->col->ll.ll = apj->col->ub + temp / apj->val;
253.2792 + }
253.2793 + else if (apj->val <= -eps)
253.2794 + { /* u'[j] := l[j] + (L[p] - U'[p]) / a[p,j] */
253.2795 + apj->col->uu.uu = apj->col->lb + temp / apj->val;
253.2796 + }
253.2797 + }
253.2798 + }
253.2799 + else
253.2800 + { /* temp = L[p,k] */
253.2801 + if (apk->val >= +eps)
253.2802 + { /* l'[k] := L[p,k] / a[p,k] */
253.2803 + apk->col->ll.ll = temp / apk->val;
253.2804 + }
253.2805 + else if (apk->val <= -eps)
253.2806 + { /* u'[k] := L[p,k] / a[p,k] */
253.2807 + apk->col->uu.uu = temp / apk->val;
253.2808 + }
253.2809 + }
253.2810 +skip1: ;
253.2811 + }
253.2812 + /* process row upper bound (assuming that it can be active) */
253.2813 + if (p->ub != +DBL_MAX)
253.2814 + { apk = NULL;
253.2815 + for (apj = p->ptr; apj != NULL; apj = apj->r_next)
253.2816 + { if (apj->val > 0.0 && apj->col->lb == -DBL_MAX ||
253.2817 + apj->val < 0.0 && apj->col->ub == +DBL_MAX)
253.2818 + { if (apk == NULL)
253.2819 + apk = apj;
253.2820 + else
253.2821 + goto skip2;
253.2822 + }
253.2823 + }
253.2824 + /* if a[p,k] = NULL then |J''| = 0 else J'' = { k } */
253.2825 + temp = p->ub;
253.2826 + for (apj = p->ptr; apj != NULL; apj = apj->r_next)
253.2827 + { if (apj == apk)
253.2828 + /* skip a[p,k] */;
253.2829 + else if (apj->val > 0.0)
253.2830 + temp -= apj->val * apj->col->lb;
253.2831 + else /* apj->val < 0.0 */
253.2832 + temp -= apj->val * apj->col->ub;
253.2833 + }
253.2834 + /* compute column implied bounds */
253.2835 + if (apk == NULL)
253.2836 + { /* temp = U[p] - L'[p] */
253.2837 + for (apj = p->ptr; apj != NULL; apj = apj->r_next)
253.2838 + { if (apj->val >= +eps)
253.2839 + { /* u'[j] := l[j] + (U[p] - L'[p]) / a[p,j] */
253.2840 + apj->col->uu.uu = apj->col->lb + temp / apj->val;
253.2841 + }
253.2842 + else if (apj->val <= -eps)
253.2843 + { /* l'[j] := u[j] + (U[p] - L'[p]) / a[p,j] */
253.2844 + apj->col->ll.ll = apj->col->ub + temp / apj->val;
253.2845 + }
253.2846 + }
253.2847 + }
253.2848 + else
253.2849 + { /* temp = U[p,k] */
253.2850 + if (apk->val >= +eps)
253.2851 + { /* u'[k] := U[p,k] / a[p,k] */
253.2852 + apk->col->uu.uu = temp / apk->val;
253.2853 + }
253.2854 + else if (apk->val <= -eps)
253.2855 + { /* l'[k] := U[p,k] / a[p,k] */
253.2856 + apk->col->ll.ll = temp / apk->val;
253.2857 + }
253.2858 + }
253.2859 +skip2: ;
253.2860 + }
253.2861 + return;
253.2862 +}
253.2863 +
253.2864 +/* eof */
254.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
254.2 +++ b/src/glpnpp04.c Mon Dec 06 13:09:21 2010 +0100
254.3 @@ -0,0 +1,1414 @@
254.4 +/* glpnpp04.c */
254.5 +
254.6 +/***********************************************************************
254.7 +* This code is part of GLPK (GNU Linear Programming Kit).
254.8 +*
254.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
254.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
254.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
254.12 +* E-mail: <mao@gnu.org>.
254.13 +*
254.14 +* GLPK is free software: you can redistribute it and/or modify it
254.15 +* under the terms of the GNU General Public License as published by
254.16 +* the Free Software Foundation, either version 3 of the License, or
254.17 +* (at your option) any later version.
254.18 +*
254.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
254.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
254.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
254.22 +* License for more details.
254.23 +*
254.24 +* You should have received a copy of the GNU General Public License
254.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
254.26 +***********************************************************************/
254.27 +
254.28 +#include "glpnpp.h"
254.29 +
254.30 +/***********************************************************************
254.31 +* NAME
254.32 +*
254.33 +* npp_binarize_prob - binarize MIP problem
254.34 +*
254.35 +* SYNOPSIS
254.36 +*
254.37 +* #include "glpnpp.h"
254.38 +* int npp_binarize_prob(NPP *npp);
254.39 +*
254.40 +* DESCRIPTION
254.41 +*
254.42 +* The routine npp_binarize_prob replaces in the original MIP problem
254.43 +* every integer variable:
254.44 +*
254.45 +* l[q] <= x[q] <= u[q], (1)
254.46 +*
254.47 +* where l[q] < u[q], by an equivalent sum of binary variables.
254.48 +*
254.49 +* RETURNS
254.50 +*
254.51 +* The routine returns the number of integer variables for which the
254.52 +* transformation failed, because u[q] - l[q] > d_max.
254.53 +*
254.54 +* PROBLEM TRANSFORMATION
254.55 +*
254.56 +* If variable x[q] has non-zero lower bound, it is first processed
254.57 +* with the routine npp_lbnd_col. Thus, we can assume that:
254.58 +*
254.59 +* 0 <= x[q] <= u[q]. (2)
254.60 +*
254.61 +* If u[q] = 1, variable x[q] is already binary, so further processing
254.62 +* is not needed. Let, therefore, that 2 <= u[q] <= d_max, and n be a
254.63 +* smallest integer such that u[q] <= 2^n - 1 (n >= 2, since u[q] >= 2).
254.64 +* Then variable x[q] can be replaced by the following sum:
254.65 +*
254.66 +* n-1
254.67 +* x[q] = sum 2^k x[k], (3)
254.68 +* k=0
254.69 +*
254.70 +* where x[k] are binary columns (variables). If u[q] < 2^n - 1, the
254.71 +* following additional inequality constraint must be also included in
254.72 +* the transformed problem:
254.73 +*
254.74 +* n-1
254.75 +* sum 2^k x[k] <= u[q]. (4)
254.76 +* k=0
254.77 +*
254.78 +* Note: Assuming that in the transformed problem x[q] becomes binary
254.79 +* variable x[0], this transformation causes new n-1 binary variables
254.80 +* to appear.
254.81 +*
254.82 +* Substituting x[q] from (3) to the objective row gives:
254.83 +*
254.84 +* z = sum c[j] x[j] + c[0] =
254.85 +* j
254.86 +*
254.87 +* = sum c[j] x[j] + c[q] x[q] + c[0] =
254.88 +* j!=q
254.89 +* n-1
254.90 +* = sum c[j] x[j] + c[q] sum 2^k x[k] + c[0] =
254.91 +* j!=q k=0
254.92 +* n-1
254.93 +* = sum c[j] x[j] + sum c[k] x[k] + c[0],
254.94 +* j!=q k=0
254.95 +*
254.96 +* where:
254.97 +*
254.98 +* c[k] = 2^k c[q], k = 0, ..., n-1. (5)
254.99 +*
254.100 +* And substituting x[q] from (3) to i-th constraint row i gives:
254.101 +*
254.102 +* L[i] <= sum a[i,j] x[j] <= U[i] ==>
254.103 +* j
254.104 +*
254.105 +* L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
254.106 +* j!=q
254.107 +* n-1
254.108 +* L[i] <= sum a[i,j] x[j] + a[i,q] sum 2^k x[k] <= U[i] ==>
254.109 +* j!=q k=0
254.110 +* n-1
254.111 +* L[i] <= sum a[i,j] x[j] + sum a[i,k] x[k] <= U[i],
254.112 +* j!=q k=0
254.113 +*
254.114 +* where:
254.115 +*
254.116 +* a[i,k] = 2^k a[i,q], k = 0, ..., n-1. (6)
254.117 +*
254.118 +* RECOVERING SOLUTION
254.119 +*
254.120 +* Value of variable x[q] is computed with formula (3). */
254.121 +
254.122 +struct binarize
254.123 +{ int q;
254.124 + /* column reference number for x[q] = x[0] */
254.125 + int j;
254.126 + /* column reference number for x[1]; x[2] has reference number
254.127 + j+1, x[3] - j+2, etc. */
254.128 + int n;
254.129 + /* total number of binary variables, n >= 2 */
254.130 +};
254.131 +
254.132 +static int rcv_binarize_prob(NPP *npp, void *info);
254.133 +
254.134 +int npp_binarize_prob(NPP *npp)
254.135 +{ /* binarize MIP problem */
254.136 + struct binarize *info;
254.137 + NPPROW *row;
254.138 + NPPCOL *col, *bin;
254.139 + NPPAIJ *aij;
254.140 + int u, n, k, temp, nfails, nvars, nbins, nrows;
254.141 + /* new variables will be added to the end of the column list, so
254.142 + we go from the end to beginning of the column list */
254.143 + nfails = nvars = nbins = nrows = 0;
254.144 + for (col = npp->c_tail; col != NULL; col = col->prev)
254.145 + { /* skip continuous variable */
254.146 + if (!col->is_int) continue;
254.147 + /* skip fixed variable */
254.148 + if (col->lb == col->ub) continue;
254.149 + /* skip binary variable */
254.150 + if (col->lb == 0.0 && col->ub == 1.0) continue;
254.151 + /* check if the transformation is applicable */
254.152 + if (col->lb < -1e6 || col->ub > +1e6 ||
254.153 + col->ub - col->lb > 4095.0)
254.154 + { /* unfortunately, not */
254.155 + nfails++;
254.156 + continue;
254.157 + }
254.158 + /* process integer non-binary variable x[q] */
254.159 + nvars++;
254.160 + /* make x[q] non-negative, if its lower bound is non-zero */
254.161 + if (col->lb != 0.0)
254.162 + npp_lbnd_col(npp, col);
254.163 + /* now 0 <= x[q] <= u[q] */
254.164 + xassert(col->lb == 0.0);
254.165 + u = (int)col->ub;
254.166 + xassert(col->ub == (double)u);
254.167 + /* if x[q] is binary, further processing is not needed */
254.168 + if (u == 1) continue;
254.169 + /* determine smallest n such that u <= 2^n - 1 (thus, n is the
254.170 + number of binary variables needed) */
254.171 + n = 2, temp = 4;
254.172 + while (u >= temp)
254.173 + n++, temp += temp;
254.174 + nbins += n;
254.175 + /* create transformation stack entry */
254.176 + info = npp_push_tse(npp,
254.177 + rcv_binarize_prob, sizeof(struct binarize));
254.178 + info->q = col->j;
254.179 + info->j = 0; /* will be set below */
254.180 + info->n = n;
254.181 + /* if u < 2^n - 1, we need one additional row for (4) */
254.182 + if (u < temp - 1)
254.183 + { row = npp_add_row(npp), nrows++;
254.184 + row->lb = -DBL_MAX, row->ub = u;
254.185 + }
254.186 + else
254.187 + row = NULL;
254.188 + /* in the transformed problem variable x[q] becomes binary
254.189 + variable x[0], so its objective and constraint coefficients
254.190 + are not changed */
254.191 + col->ub = 1.0;
254.192 + /* include x[0] into constraint (4) */
254.193 + if (row != NULL)
254.194 + npp_add_aij(npp, row, col, 1.0);
254.195 + /* add other binary variables x[1], ..., x[n-1] */
254.196 + for (k = 1, temp = 2; k < n; k++, temp += temp)
254.197 + { /* add new binary variable x[k] */
254.198 + bin = npp_add_col(npp);
254.199 + bin->is_int = 1;
254.200 + bin->lb = 0.0, bin->ub = 1.0;
254.201 + bin->coef = (double)temp * col->coef;
254.202 + /* store column reference number for x[1] */
254.203 + if (info->j == 0)
254.204 + info->j = bin->j;
254.205 + else
254.206 + xassert(info->j + (k-1) == bin->j);
254.207 + /* duplicate constraint coefficients for x[k]; this also
254.208 + automatically includes x[k] into constraint (4) */
254.209 + for (aij = col->ptr; aij != NULL; aij = aij->c_next)
254.210 + npp_add_aij(npp, aij->row, bin, (double)temp * aij->val);
254.211 + }
254.212 + }
254.213 + if (nvars > 0)
254.214 + xprintf("%d integer variable(s) were replaced by %d binary one"
254.215 + "s\n", nvars, nbins);
254.216 + if (nrows > 0)
254.217 + xprintf("%d row(s) were added due to binarization\n", nrows);
254.218 + if (nfails > 0)
254.219 + xprintf("Binarization failed for %d integer variable(s)\n",
254.220 + nfails);
254.221 + return nfails;
254.222 +}
254.223 +
254.224 +static int rcv_binarize_prob(NPP *npp, void *_info)
254.225 +{ /* recovery binarized variable */
254.226 + struct binarize *info = _info;
254.227 + int k, temp;
254.228 + double sum;
254.229 + /* compute value of x[q]; see formula (3) */
254.230 + sum = npp->c_value[info->q];
254.231 + for (k = 1, temp = 2; k < info->n; k++, temp += temp)
254.232 + sum += (double)temp * npp->c_value[info->j + (k-1)];
254.233 + npp->c_value[info->q] = sum;
254.234 + return 0;
254.235 +}
254.236 +
254.237 +/**********************************************************************/
254.238 +
254.239 +struct elem
254.240 +{ /* linear form element a[j] x[j] */
254.241 + double aj;
254.242 + /* non-zero coefficient value */
254.243 + NPPCOL *xj;
254.244 + /* pointer to variable (column) */
254.245 + struct elem *next;
254.246 + /* pointer to another term */
254.247 +};
254.248 +
254.249 +static struct elem *copy_form(NPP *npp, NPPROW *row, double s)
254.250 +{ /* copy linear form */
254.251 + NPPAIJ *aij;
254.252 + struct elem *ptr, *e;
254.253 + ptr = NULL;
254.254 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
254.255 + { e = dmp_get_atom(npp->pool, sizeof(struct elem));
254.256 + e->aj = s * aij->val;
254.257 + e->xj = aij->col;
254.258 + e->next = ptr;
254.259 + ptr = e;
254.260 + }
254.261 + return ptr;
254.262 +}
254.263 +
254.264 +static void drop_form(NPP *npp, struct elem *ptr)
254.265 +{ /* drop linear form */
254.266 + struct elem *e;
254.267 + while (ptr != NULL)
254.268 + { e = ptr;
254.269 + ptr = e->next;
254.270 + dmp_free_atom(npp->pool, e, sizeof(struct elem));
254.271 + }
254.272 + return;
254.273 +}
254.274 +
254.275 +/***********************************************************************
254.276 +* NAME
254.277 +*
254.278 +* npp_is_packing - test if constraint is packing inequality
254.279 +*
254.280 +* SYNOPSIS
254.281 +*
254.282 +* #include "glpnpp.h"
254.283 +* int npp_is_packing(NPP *npp, NPPROW *row);
254.284 +*
254.285 +* RETURNS
254.286 +*
254.287 +* If the specified row (constraint) is packing inequality (see below),
254.288 +* the routine npp_is_packing returns non-zero. Otherwise, it returns
254.289 +* zero.
254.290 +*
254.291 +* PACKING INEQUALITIES
254.292 +*
254.293 +* In canonical format the packing inequality is the following:
254.294 +*
254.295 +* sum x[j] <= 1, (1)
254.296 +* j in J
254.297 +*
254.298 +* where all variables x[j] are binary. This inequality expresses the
254.299 +* condition that in any integer feasible solution at most one variable
254.300 +* from set J can take non-zero (unity) value while other variables
254.301 +* must be equal to zero. W.l.o.g. it is assumed that |J| >= 2, because
254.302 +* if J is empty or |J| = 1, the inequality (1) is redundant.
254.303 +*
254.304 +* In general case the packing inequality may include original variables
254.305 +* x[j] as well as their complements x~[j]:
254.306 +*
254.307 +* sum x[j] + sum x~[j] <= 1, (2)
254.308 +* j in Jp j in Jn
254.309 +*
254.310 +* where Jp and Jn are not intersected. Therefore, using substitution
254.311 +* x~[j] = 1 - x[j] gives the packing inequality in generalized format:
254.312 +*
254.313 +* sum x[j] - sum x[j] <= 1 - |Jn|. (3)
254.314 +* j in Jp j in Jn */
254.315 +
254.316 +int npp_is_packing(NPP *npp, NPPROW *row)
254.317 +{ /* test if constraint is packing inequality */
254.318 + NPPCOL *col;
254.319 + NPPAIJ *aij;
254.320 + int b;
254.321 + xassert(npp == npp);
254.322 + if (!(row->lb == -DBL_MAX && row->ub != +DBL_MAX))
254.323 + return 0;
254.324 + b = 1;
254.325 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
254.326 + { col = aij->col;
254.327 + if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
254.328 + return 0;
254.329 + if (aij->val == +1.0)
254.330 + ;
254.331 + else if (aij->val == -1.0)
254.332 + b--;
254.333 + else
254.334 + return 0;
254.335 + }
254.336 + if (row->ub != (double)b) return 0;
254.337 + return 1;
254.338 +}
254.339 +
254.340 +/***********************************************************************
254.341 +* NAME
254.342 +*
254.343 +* npp_hidden_packing - identify hidden packing inequality
254.344 +*
254.345 +* SYNOPSIS
254.346 +*
254.347 +* #include "glpnpp.h"
254.348 +* int npp_hidden_packing(NPP *npp, NPPROW *row);
254.349 +*
254.350 +* DESCRIPTION
254.351 +*
254.352 +* The routine npp_hidden_packing processes specified inequality
254.353 +* constraint, which includes only binary variables, and the number of
254.354 +* the variables is not less than two. If the original inequality is
254.355 +* equivalent to a packing inequality, the routine replaces it by this
254.356 +* equivalent inequality. If the original constraint is double-sided
254.357 +* inequality, it is replaced by a pair of single-sided inequalities,
254.358 +* if necessary.
254.359 +*
254.360 +* RETURNS
254.361 +*
254.362 +* If the original inequality constraint was replaced by equivalent
254.363 +* packing inequality, the routine npp_hidden_packing returns non-zero.
254.364 +* Otherwise, it returns zero.
254.365 +*
254.366 +* PROBLEM TRANSFORMATION
254.367 +*
254.368 +* Consider an inequality constraint:
254.369 +*
254.370 +* sum a[j] x[j] <= b, (1)
254.371 +* j in J
254.372 +*
254.373 +* where all variables x[j] are binary, and |J| >= 2. (In case of '>='
254.374 +* inequality it can be transformed to '<=' format by multiplying both
254.375 +* its sides by -1.)
254.376 +*
254.377 +* Let Jp = {j: a[j] > 0}, Jn = {j: a[j] < 0}. Performing substitution
254.378 +* x[j] = 1 - x~[j] for all j in Jn, we have:
254.379 +*
254.380 +* sum a[j] x[j] <= b ==>
254.381 +* j in J
254.382 +*
254.383 +* sum a[j] x[j] + sum a[j] x[j] <= b ==>
254.384 +* j in Jp j in Jn
254.385 +*
254.386 +* sum a[j] x[j] + sum a[j] (1 - x~[j]) <= b ==>
254.387 +* j in Jp j in Jn
254.388 +*
254.389 +* sum a[j] x[j] - sum a[j] x~[j] <= b - sum a[j].
254.390 +* j in Jp j in Jn j in Jn
254.391 +*
254.392 +* Thus, meaning the transformation above, we can assume that in
254.393 +* inequality (1) all coefficients a[j] are positive. Moreover, we can
254.394 +* assume that a[j] <= b. In fact, let a[j] > b; then the following
254.395 +* three cases are possible:
254.396 +*
254.397 +* 1) b < 0. In this case inequality (1) is infeasible, so the problem
254.398 +* has no feasible solution (see the routine npp_analyze_row);
254.399 +*
254.400 +* 2) b = 0. In this case inequality (1) is a forcing inequality on its
254.401 +* upper bound (see the routine npp_forcing row), from which it
254.402 +* follows that all variables x[j] should be fixed at zero;
254.403 +*
254.404 +* 3) b > 0. In this case inequality (1) defines an implied zero upper
254.405 +* bound for variable x[j] (see the routine npp_implied_bounds), from
254.406 +* which it follows that x[j] should be fixed at zero.
254.407 +*
254.408 +* It is assumed that all three cases listed above have been recognized
254.409 +* by the routine npp_process_prob, which performs basic MIP processing
254.410 +* prior to a call the routine npp_hidden_packing. So, if one of these
254.411 +* cases occurs, we should just skip processing such constraint.
254.412 +*
254.413 +* Thus, let 0 < a[j] <= b. Then it is obvious that constraint (1) is
254.414 +* equivalent to packing inquality only if:
254.415 +*
254.416 +* a[j] + a[k] > b + eps (2)
254.417 +*
254.418 +* for all j, k in J, j != k, where eps is an absolute tolerance for
254.419 +* row (linear form) value. Checking the condition (2) for all j and k,
254.420 +* j != k, requires time O(|J|^2). However, this time can be reduced to
254.421 +* O(|J|), if use minimal a[j] and a[k], in which case it is sufficient
254.422 +* to check the condition (2) only once.
254.423 +*
254.424 +* Once the original inequality (1) is replaced by equivalent packing
254.425 +* inequality, we need to perform back substitution x~[j] = 1 - x[j] for
254.426 +* all j in Jn (see above).
254.427 +*
254.428 +* RECOVERING SOLUTION
254.429 +*
254.430 +* None needed. */
254.431 +
254.432 +static int hidden_packing(NPP *npp, struct elem *ptr, double *_b)
254.433 +{ /* process inequality constraint: sum a[j] x[j] <= b;
254.434 + 0 - specified row is NOT hidden packing inequality;
254.435 + 1 - specified row is packing inequality;
254.436 + 2 - specified row is hidden packing inequality. */
254.437 + struct elem *e, *ej, *ek;
254.438 + int neg;
254.439 + double b = *_b, eps;
254.440 + xassert(npp == npp);
254.441 + /* a[j] must be non-zero, x[j] must be binary, for all j in J */
254.442 + for (e = ptr; e != NULL; e = e->next)
254.443 + { xassert(e->aj != 0.0);
254.444 + xassert(e->xj->is_int);
254.445 + xassert(e->xj->lb == 0.0 && e->xj->ub == 1.0);
254.446 + }
254.447 + /* check if the specified inequality constraint already has the
254.448 + form of packing inequality */
254.449 + neg = 0; /* neg is |Jn| */
254.450 + for (e = ptr; e != NULL; e = e->next)
254.451 + { if (e->aj == +1.0)
254.452 + ;
254.453 + else if (e->aj == -1.0)
254.454 + neg++;
254.455 + else
254.456 + break;
254.457 + }
254.458 + if (e == NULL)
254.459 + { /* all coefficients a[j] are +1 or -1; check rhs b */
254.460 + if (b == (double)(1 - neg))
254.461 + { /* it is packing inequality; no processing is needed */
254.462 + return 1;
254.463 + }
254.464 + }
254.465 + /* substitute x[j] = 1 - x~[j] for all j in Jn to make all a[j]
254.466 + positive; the result is a~[j] = |a[j]| and new rhs b */
254.467 + for (e = ptr; e != NULL; e = e->next)
254.468 + if (e->aj < 0) b -= e->aj;
254.469 + /* now a[j] > 0 for all j in J (actually |a[j]| are used) */
254.470 + /* if a[j] > b, skip processing--this case must not appear */
254.471 + for (e = ptr; e != NULL; e = e->next)
254.472 + if (fabs(e->aj) > b) return 0;
254.473 + /* now 0 < a[j] <= b for all j in J */
254.474 + /* find two minimal coefficients a[j] and a[k], j != k */
254.475 + ej = NULL;
254.476 + for (e = ptr; e != NULL; e = e->next)
254.477 + if (ej == NULL || fabs(ej->aj) > fabs(e->aj)) ej = e;
254.478 + xassert(ej != NULL);
254.479 + ek = NULL;
254.480 + for (e = ptr; e != NULL; e = e->next)
254.481 + if (e != ej)
254.482 + if (ek == NULL || fabs(ek->aj) > fabs(e->aj)) ek = e;
254.483 + xassert(ek != NULL);
254.484 + /* the specified constraint is equivalent to packing inequality
254.485 + iff a[j] + a[k] > b + eps */
254.486 + eps = 1e-3 + 1e-6 * fabs(b);
254.487 + if (fabs(ej->aj) + fabs(ek->aj) <= b + eps) return 0;
254.488 + /* perform back substitution x~[j] = 1 - x[j] and construct the
254.489 + final equivalent packing inequality in generalized format */
254.490 + b = 1.0;
254.491 + for (e = ptr; e != NULL; e = e->next)
254.492 + { if (e->aj > 0.0)
254.493 + e->aj = +1.0;
254.494 + else /* e->aj < 0.0 */
254.495 + e->aj = -1.0, b -= 1.0;
254.496 + }
254.497 + *_b = b;
254.498 + return 2;
254.499 +}
254.500 +
254.501 +int npp_hidden_packing(NPP *npp, NPPROW *row)
254.502 +{ /* identify hidden packing inequality */
254.503 + NPPROW *copy;
254.504 + NPPAIJ *aij;
254.505 + struct elem *ptr, *e;
254.506 + int kase, ret, count = 0;
254.507 + double b;
254.508 + /* the row must be inequality constraint */
254.509 + xassert(row->lb < row->ub);
254.510 + for (kase = 0; kase <= 1; kase++)
254.511 + { if (kase == 0)
254.512 + { /* process row upper bound */
254.513 + if (row->ub == +DBL_MAX) continue;
254.514 + ptr = copy_form(npp, row, +1.0);
254.515 + b = + row->ub;
254.516 + }
254.517 + else
254.518 + { /* process row lower bound */
254.519 + if (row->lb == -DBL_MAX) continue;
254.520 + ptr = copy_form(npp, row, -1.0);
254.521 + b = - row->lb;
254.522 + }
254.523 + /* now the inequality has the form "sum a[j] x[j] <= b" */
254.524 + ret = hidden_packing(npp, ptr, &b);
254.525 + xassert(0 <= ret && ret <= 2);
254.526 + if (kase == 1 && ret == 1 || ret == 2)
254.527 + { /* the original inequality has been identified as hidden
254.528 + packing inequality */
254.529 + count++;
254.530 +#ifdef GLP_DEBUG
254.531 + xprintf("Original constraint:\n");
254.532 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
254.533 + xprintf(" %+g x%d", aij->val, aij->col->j);
254.534 + if (row->lb != -DBL_MAX) xprintf(", >= %g", row->lb);
254.535 + if (row->ub != +DBL_MAX) xprintf(", <= %g", row->ub);
254.536 + xprintf("\n");
254.537 + xprintf("Equivalent packing inequality:\n");
254.538 + for (e = ptr; e != NULL; e = e->next)
254.539 + xprintf(" %sx%d", e->aj > 0.0 ? "+" : "-", e->xj->j);
254.540 + xprintf(", <= %g\n", b);
254.541 +#endif
254.542 + if (row->lb == -DBL_MAX || row->ub == +DBL_MAX)
254.543 + { /* the original row is single-sided inequality; no copy
254.544 + is needed */
254.545 + copy = NULL;
254.546 + }
254.547 + else
254.548 + { /* the original row is double-sided inequality; we need
254.549 + to create its copy for other bound before replacing it
254.550 + with the equivalent inequality */
254.551 + copy = npp_add_row(npp);
254.552 + if (kase == 0)
254.553 + { /* the copy is for lower bound */
254.554 + copy->lb = row->lb, copy->ub = +DBL_MAX;
254.555 + }
254.556 + else
254.557 + { /* the copy is for upper bound */
254.558 + copy->lb = -DBL_MAX, copy->ub = row->ub;
254.559 + }
254.560 + /* copy original row coefficients */
254.561 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
254.562 + npp_add_aij(npp, copy, aij->col, aij->val);
254.563 + }
254.564 + /* replace the original inequality by equivalent one */
254.565 + npp_erase_row(npp, row);
254.566 + row->lb = -DBL_MAX, row->ub = b;
254.567 + for (e = ptr; e != NULL; e = e->next)
254.568 + npp_add_aij(npp, row, e->xj, e->aj);
254.569 + /* continue processing lower bound for the copy */
254.570 + if (copy != NULL) row = copy;
254.571 + }
254.572 + drop_form(npp, ptr);
254.573 + }
254.574 + return count;
254.575 +}
254.576 +
254.577 +/***********************************************************************
254.578 +* NAME
254.579 +*
254.580 +* npp_implied_packing - identify implied packing inequality
254.581 +*
254.582 +* SYNOPSIS
254.583 +*
254.584 +* #include "glpnpp.h"
254.585 +* int npp_implied_packing(NPP *npp, NPPROW *row, int which,
254.586 +* NPPCOL *var[], char set[]);
254.587 +*
254.588 +* DESCRIPTION
254.589 +*
254.590 +* The routine npp_implied_packing processes specified row (constraint)
254.591 +* of general format:
254.592 +*
254.593 +* L <= sum a[j] x[j] <= U. (1)
254.594 +* j
254.595 +*
254.596 +* If which = 0, only lower bound L, which must exist, is considered,
254.597 +* while upper bound U is ignored. Similarly, if which = 1, only upper
254.598 +* bound U, which must exist, is considered, while lower bound L is
254.599 +* ignored. Thus, if the specified row is a double-sided inequality or
254.600 +* equality constraint, this routine should be called twice for both
254.601 +* lower and upper bounds.
254.602 +*
254.603 +* The routine npp_implied_packing attempts to find a non-trivial (i.e.
254.604 +* having not less than two binary variables) packing inequality:
254.605 +*
254.606 +* sum x[j] - sum x[j] <= 1 - |Jn|, (2)
254.607 +* j in Jp j in Jn
254.608 +*
254.609 +* which is relaxation of the constraint (1) in the sense that any
254.610 +* solution satisfying to that constraint also satisfies to the packing
254.611 +* inequality (2). If such relaxation exists, the routine stores
254.612 +* pointers to descriptors of corresponding binary variables and their
254.613 +* flags, resp., to locations var[1], var[2], ..., var[len] and set[1],
254.614 +* set[2], ..., set[len], where set[j] = 0 means that j in Jp and
254.615 +* set[j] = 1 means that j in Jn.
254.616 +*
254.617 +* RETURNS
254.618 +*
254.619 +* The routine npp_implied_packing returns len, which is the total
254.620 +* number of binary variables in the packing inequality found, len >= 2.
254.621 +* However, if the relaxation does not exist, the routine returns zero.
254.622 +*
254.623 +* ALGORITHM
254.624 +*
254.625 +* If which = 0, the constraint coefficients (1) are multiplied by -1
254.626 +* and b is assigned -L; if which = 1, the constraint coefficients (1)
254.627 +* are not changed and b is assigned +U. In both cases the specified
254.628 +* constraint gets the following format:
254.629 +*
254.630 +* sum a[j] x[j] <= b. (3)
254.631 +* j
254.632 +*
254.633 +* (Note that (3) is a relaxation of (1), because one of bounds L or U
254.634 +* is ignored.)
254.635 +*
254.636 +* Let J be set of binary variables, Kp be set of non-binary (integer
254.637 +* or continuous) variables with a[j] > 0, and Kn be set of non-binary
254.638 +* variables with a[j] < 0. Then the inequality (3) can be written as
254.639 +* follows:
254.640 +*
254.641 +* sum a[j] x[j] <= b - sum a[j] x[j] - sum a[j] x[j]. (4)
254.642 +* j in J j in Kp j in Kn
254.643 +*
254.644 +* To get rid of non-binary variables we can replace the inequality (4)
254.645 +* by the following relaxed inequality:
254.646 +*
254.647 +* sum a[j] x[j] <= b~, (5)
254.648 +* j in J
254.649 +*
254.650 +* where:
254.651 +*
254.652 +* b~ = sup(b - sum a[j] x[j] - sum a[j] x[j]) =
254.653 +* j in Kp j in Kn
254.654 +*
254.655 +* = b - inf sum a[j] x[j] - inf sum a[j] x[j] = (6)
254.656 +* j in Kp j in Kn
254.657 +*
254.658 +* = b - sum a[j] l[j] - sum a[j] u[j].
254.659 +* j in Kp j in Kn
254.660 +*
254.661 +* Note that if lower bound l[j] (if j in Kp) or upper bound u[j]
254.662 +* (if j in Kn) of some non-binary variable x[j] does not exist, then
254.663 +* formally b = +oo, in which case further analysis is not performed.
254.664 +*
254.665 +* Let Bp = {j in J: a[j] > 0}, Bn = {j in J: a[j] < 0}. To make all
254.666 +* the inequality coefficients in (5) positive, we replace all x[j] in
254.667 +* Bn by their complementaries, substituting x[j] = 1 - x~[j] for all
254.668 +* j in Bn, that gives:
254.669 +*
254.670 +* sum a[j] x[j] - sum a[j] x~[j] <= b~ - sum a[j]. (7)
254.671 +* j in Bp j in Bn j in Bn
254.672 +*
254.673 +* This inequality is a relaxation of the original constraint (1), and
254.674 +* it is a binary knapsack inequality. Writing it in the standard format
254.675 +* we have:
254.676 +*
254.677 +* sum alfa[j] z[j] <= beta, (8)
254.678 +* j in J
254.679 +*
254.680 +* where:
254.681 +* ( + a[j], if j in Bp,
254.682 +* alfa[j] = < (9)
254.683 +* ( - a[j], if j in Bn,
254.684 +*
254.685 +* ( x[j], if j in Bp,
254.686 +* z[j] = < (10)
254.687 +* ( 1 - x[j], if j in Bn,
254.688 +*
254.689 +* beta = b~ - sum a[j]. (11)
254.690 +* j in Bn
254.691 +*
254.692 +* In the inequality (8) all coefficients are positive, therefore, the
254.693 +* packing relaxation to be found for this inequality is the following:
254.694 +*
254.695 +* sum z[j] <= 1. (12)
254.696 +* j in P
254.697 +*
254.698 +* It is obvious that set P within J, which we would like to find, must
254.699 +* satisfy to the following condition:
254.700 +*
254.701 +* alfa[j] + alfa[k] > beta + eps for all j, k in P, j != k, (13)
254.702 +*
254.703 +* where eps is an absolute tolerance for value of the linear form.
254.704 +* Thus, it is natural to take P = {j: alpha[j] > (beta + eps) / 2}.
254.705 +* Moreover, if in the equality (8) there exist coefficients alfa[k],
254.706 +* for which alfa[k] <= (beta + eps) / 2, but which, nevertheless,
254.707 +* satisfies to the condition (13) for all j in P, *one* corresponding
254.708 +* variable z[k] (having, for example, maximal coefficient alfa[k]) can
254.709 +* be included in set P, that allows increasing the number of binary
254.710 +* variables in (12) by one.
254.711 +*
254.712 +* Once the set P has been built, for the inequality (12) we need to
254.713 +* perform back substitution according to (10) in order to express it
254.714 +* through the original binary variables. As the result of such back
254.715 +* substitution the relaxed packing inequality get its final format (2),
254.716 +* where Jp = J intersect Bp, and Jn = J intersect Bn. */
254.717 +
254.718 +int npp_implied_packing(NPP *npp, NPPROW *row, int which,
254.719 + NPPCOL *var[], char set[])
254.720 +{ struct elem *ptr, *e, *i, *k;
254.721 + int len = 0;
254.722 + double b, eps;
254.723 + /* build inequality (3) */
254.724 + if (which == 0)
254.725 + { ptr = copy_form(npp, row, -1.0);
254.726 + xassert(row->lb != -DBL_MAX);
254.727 + b = - row->lb;
254.728 + }
254.729 + else if (which == 1)
254.730 + { ptr = copy_form(npp, row, +1.0);
254.731 + xassert(row->ub != +DBL_MAX);
254.732 + b = + row->ub;
254.733 + }
254.734 + /* remove non-binary variables to build relaxed inequality (5);
254.735 + compute its right-hand side b~ with formula (6) */
254.736 + for (e = ptr; e != NULL; e = e->next)
254.737 + { if (!(e->xj->is_int && e->xj->lb == 0.0 && e->xj->ub == 1.0))
254.738 + { /* x[j] is non-binary variable */
254.739 + if (e->aj > 0.0)
254.740 + { if (e->xj->lb == -DBL_MAX) goto done;
254.741 + b -= e->aj * e->xj->lb;
254.742 + }
254.743 + else /* e->aj < 0.0 */
254.744 + { if (e->xj->ub == +DBL_MAX) goto done;
254.745 + b -= e->aj * e->xj->ub;
254.746 + }
254.747 + /* a[j] = 0 means that variable x[j] is removed */
254.748 + e->aj = 0.0;
254.749 + }
254.750 + }
254.751 + /* substitute x[j] = 1 - x~[j] to build knapsack inequality (8);
254.752 + compute its right-hand side beta with formula (11) */
254.753 + for (e = ptr; e != NULL; e = e->next)
254.754 + if (e->aj < 0.0) b -= e->aj;
254.755 + /* if beta is close to zero, the knapsack inequality is either
254.756 + infeasible or forcing inequality; this must never happen, so
254.757 + we skip further analysis */
254.758 + if (b < 1e-3) goto done;
254.759 + /* build set P as well as sets Jp and Jn, and determine x[k] as
254.760 + explained above in comments to the routine */
254.761 + eps = 1e-3 + 1e-6 * b;
254.762 + i = k = NULL;
254.763 + for (e = ptr; e != NULL; e = e->next)
254.764 + { /* note that alfa[j] = |a[j]| */
254.765 + if (fabs(e->aj) > 0.5 * (b + eps))
254.766 + { /* alfa[j] > (b + eps) / 2; include x[j] in set P, i.e. in
254.767 + set Jp or Jn */
254.768 + var[++len] = e->xj;
254.769 + set[len] = (char)(e->aj > 0.0 ? 0 : 1);
254.770 + /* alfa[i] = min alfa[j] over all j included in set P */
254.771 + if (i == NULL || fabs(i->aj) > fabs(e->aj)) i = e;
254.772 + }
254.773 + else if (fabs(e->aj) >= 1e-3)
254.774 + { /* alfa[k] = max alfa[j] over all j not included in set P;
254.775 + we skip coefficient a[j] if it is close to zero to avoid
254.776 + numerically unreliable results */
254.777 + if (k == NULL || fabs(k->aj) < fabs(e->aj)) k = e;
254.778 + }
254.779 + }
254.780 + /* if alfa[k] satisfies to condition (13) for all j in P, include
254.781 + x[k] in P */
254.782 + if (i != NULL && k != NULL && fabs(i->aj) + fabs(k->aj) > b + eps)
254.783 + { var[++len] = k->xj;
254.784 + set[len] = (char)(k->aj > 0.0 ? 0 : 1);
254.785 + }
254.786 + /* trivial packing inequality being redundant must never appear,
254.787 + so we just ignore it */
254.788 + if (len < 2) len = 0;
254.789 +done: drop_form(npp, ptr);
254.790 + return len;
254.791 +}
254.792 +
254.793 +/***********************************************************************
254.794 +* NAME
254.795 +*
254.796 +* npp_is_covering - test if constraint is covering inequality
254.797 +*
254.798 +* SYNOPSIS
254.799 +*
254.800 +* #include "glpnpp.h"
254.801 +* int npp_is_covering(NPP *npp, NPPROW *row);
254.802 +*
254.803 +* RETURNS
254.804 +*
254.805 +* If the specified row (constraint) is covering inequality (see below),
254.806 +* the routine npp_is_covering returns non-zero. Otherwise, it returns
254.807 +* zero.
254.808 +*
254.809 +* COVERING INEQUALITIES
254.810 +*
254.811 +* In canonical format the covering inequality is the following:
254.812 +*
254.813 +* sum x[j] >= 1, (1)
254.814 +* j in J
254.815 +*
254.816 +* where all variables x[j] are binary. This inequality expresses the
254.817 +* condition that in any integer feasible solution variables in set J
254.818 +* cannot be all equal to zero at the same time, i.e. at least one
254.819 +* variable must take non-zero (unity) value. W.l.o.g. it is assumed
254.820 +* that |J| >= 2, because if J is empty, the inequality (1) is
254.821 +* infeasible, and if |J| = 1, the inequality (1) is a forcing row.
254.822 +*
254.823 +* In general case the covering inequality may include original
254.824 +* variables x[j] as well as their complements x~[j]:
254.825 +*
254.826 +* sum x[j] + sum x~[j] >= 1, (2)
254.827 +* j in Jp j in Jn
254.828 +*
254.829 +* where Jp and Jn are not intersected. Therefore, using substitution
254.830 +* x~[j] = 1 - x[j] gives the packing inequality in generalized format:
254.831 +*
254.832 +* sum x[j] - sum x[j] >= 1 - |Jn|. (3)
254.833 +* j in Jp j in Jn
254.834 +*
254.835 +* (May note that the inequality (3) cuts off infeasible solutions,
254.836 +* where x[j] = 0 for all j in Jp and x[j] = 1 for all j in Jn.)
254.837 +*
254.838 +* NOTE: If |J| = 2, the inequality (3) is equivalent to packing
254.839 +* inequality (see the routine npp_is_packing). */
254.840 +
254.841 +int npp_is_covering(NPP *npp, NPPROW *row)
254.842 +{ /* test if constraint is covering inequality */
254.843 + NPPCOL *col;
254.844 + NPPAIJ *aij;
254.845 + int b;
254.846 + xassert(npp == npp);
254.847 + if (!(row->lb != -DBL_MAX && row->ub == +DBL_MAX))
254.848 + return 0;
254.849 + b = 1;
254.850 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
254.851 + { col = aij->col;
254.852 + if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
254.853 + return 0;
254.854 + if (aij->val == +1.0)
254.855 + ;
254.856 + else if (aij->val == -1.0)
254.857 + b--;
254.858 + else
254.859 + return 0;
254.860 + }
254.861 + if (row->lb != (double)b) return 0;
254.862 + return 1;
254.863 +}
254.864 +
254.865 +/***********************************************************************
254.866 +* NAME
254.867 +*
254.868 +* npp_hidden_covering - identify hidden covering inequality
254.869 +*
254.870 +* SYNOPSIS
254.871 +*
254.872 +* #include "glpnpp.h"
254.873 +* int npp_hidden_covering(NPP *npp, NPPROW *row);
254.874 +*
254.875 +* DESCRIPTION
254.876 +*
254.877 +* The routine npp_hidden_covering processes specified inequality
254.878 +* constraint, which includes only binary variables, and the number of
254.879 +* the variables is not less than three. If the original inequality is
254.880 +* equivalent to a covering inequality (see below), the routine
254.881 +* replaces it by the equivalent inequality. If the original constraint
254.882 +* is double-sided inequality, it is replaced by a pair of single-sided
254.883 +* inequalities, if necessary.
254.884 +*
254.885 +* RETURNS
254.886 +*
254.887 +* If the original inequality constraint was replaced by equivalent
254.888 +* covering inequality, the routine npp_hidden_covering returns
254.889 +* non-zero. Otherwise, it returns zero.
254.890 +*
254.891 +* PROBLEM TRANSFORMATION
254.892 +*
254.893 +* Consider an inequality constraint:
254.894 +*
254.895 +* sum a[j] x[j] >= b, (1)
254.896 +* j in J
254.897 +*
254.898 +* where all variables x[j] are binary, and |J| >= 3. (In case of '<='
254.899 +* inequality it can be transformed to '>=' format by multiplying both
254.900 +* its sides by -1.)
254.901 +*
254.902 +* Let Jp = {j: a[j] > 0}, Jn = {j: a[j] < 0}. Performing substitution
254.903 +* x[j] = 1 - x~[j] for all j in Jn, we have:
254.904 +*
254.905 +* sum a[j] x[j] >= b ==>
254.906 +* j in J
254.907 +*
254.908 +* sum a[j] x[j] + sum a[j] x[j] >= b ==>
254.909 +* j in Jp j in Jn
254.910 +*
254.911 +* sum a[j] x[j] + sum a[j] (1 - x~[j]) >= b ==>
254.912 +* j in Jp j in Jn
254.913 +*
254.914 +* sum m a[j] x[j] - sum a[j] x~[j] >= b - sum a[j].
254.915 +* j in Jp j in Jn j in Jn
254.916 +*
254.917 +* Thus, meaning the transformation above, we can assume that in
254.918 +* inequality (1) all coefficients a[j] are positive. Moreover, we can
254.919 +* assume that b > 0, because otherwise the inequality (1) would be
254.920 +* redundant (see the routine npp_analyze_row). It is then obvious that
254.921 +* constraint (1) is equivalent to covering inequality only if:
254.922 +*
254.923 +* a[j] >= b, (2)
254.924 +*
254.925 +* for all j in J.
254.926 +*
254.927 +* Once the original inequality (1) is replaced by equivalent covering
254.928 +* inequality, we need to perform back substitution x~[j] = 1 - x[j] for
254.929 +* all j in Jn (see above).
254.930 +*
254.931 +* RECOVERING SOLUTION
254.932 +*
254.933 +* None needed. */
254.934 +
254.935 +static int hidden_covering(NPP *npp, struct elem *ptr, double *_b)
254.936 +{ /* process inequality constraint: sum a[j] x[j] >= b;
254.937 + 0 - specified row is NOT hidden covering inequality;
254.938 + 1 - specified row is covering inequality;
254.939 + 2 - specified row is hidden covering inequality. */
254.940 + struct elem *e;
254.941 + int neg;
254.942 + double b = *_b, eps;
254.943 + xassert(npp == npp);
254.944 + /* a[j] must be non-zero, x[j] must be binary, for all j in J */
254.945 + for (e = ptr; e != NULL; e = e->next)
254.946 + { xassert(e->aj != 0.0);
254.947 + xassert(e->xj->is_int);
254.948 + xassert(e->xj->lb == 0.0 && e->xj->ub == 1.0);
254.949 + }
254.950 + /* check if the specified inequality constraint already has the
254.951 + form of covering inequality */
254.952 + neg = 0; /* neg is |Jn| */
254.953 + for (e = ptr; e != NULL; e = e->next)
254.954 + { if (e->aj == +1.0)
254.955 + ;
254.956 + else if (e->aj == -1.0)
254.957 + neg++;
254.958 + else
254.959 + break;
254.960 + }
254.961 + if (e == NULL)
254.962 + { /* all coefficients a[j] are +1 or -1; check rhs b */
254.963 + if (b == (double)(1 - neg))
254.964 + { /* it is covering inequality; no processing is needed */
254.965 + return 1;
254.966 + }
254.967 + }
254.968 + /* substitute x[j] = 1 - x~[j] for all j in Jn to make all a[j]
254.969 + positive; the result is a~[j] = |a[j]| and new rhs b */
254.970 + for (e = ptr; e != NULL; e = e->next)
254.971 + if (e->aj < 0) b -= e->aj;
254.972 + /* now a[j] > 0 for all j in J (actually |a[j]| are used) */
254.973 + /* if b <= 0, skip processing--this case must not appear */
254.974 + if (b < 1e-3) return 0;
254.975 + /* now a[j] > 0 for all j in J, and b > 0 */
254.976 + /* the specified constraint is equivalent to covering inequality
254.977 + iff a[j] >= b for all j in J */
254.978 + eps = 1e-9 + 1e-12 * fabs(b);
254.979 + for (e = ptr; e != NULL; e = e->next)
254.980 + if (fabs(e->aj) < b - eps) return 0;
254.981 + /* perform back substitution x~[j] = 1 - x[j] and construct the
254.982 + final equivalent covering inequality in generalized format */
254.983 + b = 1.0;
254.984 + for (e = ptr; e != NULL; e = e->next)
254.985 + { if (e->aj > 0.0)
254.986 + e->aj = +1.0;
254.987 + else /* e->aj < 0.0 */
254.988 + e->aj = -1.0, b -= 1.0;
254.989 + }
254.990 + *_b = b;
254.991 + return 2;
254.992 +}
254.993 +
254.994 +int npp_hidden_covering(NPP *npp, NPPROW *row)
254.995 +{ /* identify hidden covering inequality */
254.996 + NPPROW *copy;
254.997 + NPPAIJ *aij;
254.998 + struct elem *ptr, *e;
254.999 + int kase, ret, count = 0;
254.1000 + double b;
254.1001 + /* the row must be inequality constraint */
254.1002 + xassert(row->lb < row->ub);
254.1003 + for (kase = 0; kase <= 1; kase++)
254.1004 + { if (kase == 0)
254.1005 + { /* process row lower bound */
254.1006 + if (row->lb == -DBL_MAX) continue;
254.1007 + ptr = copy_form(npp, row, +1.0);
254.1008 + b = + row->lb;
254.1009 + }
254.1010 + else
254.1011 + { /* process row upper bound */
254.1012 + if (row->ub == +DBL_MAX) continue;
254.1013 + ptr = copy_form(npp, row, -1.0);
254.1014 + b = - row->ub;
254.1015 + }
254.1016 + /* now the inequality has the form "sum a[j] x[j] >= b" */
254.1017 + ret = hidden_covering(npp, ptr, &b);
254.1018 + xassert(0 <= ret && ret <= 2);
254.1019 + if (kase == 1 && ret == 1 || ret == 2)
254.1020 + { /* the original inequality has been identified as hidden
254.1021 + covering inequality */
254.1022 + count++;
254.1023 +#ifdef GLP_DEBUG
254.1024 + xprintf("Original constraint:\n");
254.1025 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
254.1026 + xprintf(" %+g x%d", aij->val, aij->col->j);
254.1027 + if (row->lb != -DBL_MAX) xprintf(", >= %g", row->lb);
254.1028 + if (row->ub != +DBL_MAX) xprintf(", <= %g", row->ub);
254.1029 + xprintf("\n");
254.1030 + xprintf("Equivalent covering inequality:\n");
254.1031 + for (e = ptr; e != NULL; e = e->next)
254.1032 + xprintf(" %sx%d", e->aj > 0.0 ? "+" : "-", e->xj->j);
254.1033 + xprintf(", >= %g\n", b);
254.1034 +#endif
254.1035 + if (row->lb == -DBL_MAX || row->ub == +DBL_MAX)
254.1036 + { /* the original row is single-sided inequality; no copy
254.1037 + is needed */
254.1038 + copy = NULL;
254.1039 + }
254.1040 + else
254.1041 + { /* the original row is double-sided inequality; we need
254.1042 + to create its copy for other bound before replacing it
254.1043 + with the equivalent inequality */
254.1044 + copy = npp_add_row(npp);
254.1045 + if (kase == 0)
254.1046 + { /* the copy is for upper bound */
254.1047 + copy->lb = -DBL_MAX, copy->ub = row->ub;
254.1048 + }
254.1049 + else
254.1050 + { /* the copy is for lower bound */
254.1051 + copy->lb = row->lb, copy->ub = +DBL_MAX;
254.1052 + }
254.1053 + /* copy original row coefficients */
254.1054 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
254.1055 + npp_add_aij(npp, copy, aij->col, aij->val);
254.1056 + }
254.1057 + /* replace the original inequality by equivalent one */
254.1058 + npp_erase_row(npp, row);
254.1059 + row->lb = b, row->ub = +DBL_MAX;
254.1060 + for (e = ptr; e != NULL; e = e->next)
254.1061 + npp_add_aij(npp, row, e->xj, e->aj);
254.1062 + /* continue processing upper bound for the copy */
254.1063 + if (copy != NULL) row = copy;
254.1064 + }
254.1065 + drop_form(npp, ptr);
254.1066 + }
254.1067 + return count;
254.1068 +}
254.1069 +
254.1070 +/***********************************************************************
254.1071 +* NAME
254.1072 +*
254.1073 +* npp_is_partitioning - test if constraint is partitioning equality
254.1074 +*
254.1075 +* SYNOPSIS
254.1076 +*
254.1077 +* #include "glpnpp.h"
254.1078 +* int npp_is_partitioning(NPP *npp, NPPROW *row);
254.1079 +*
254.1080 +* RETURNS
254.1081 +*
254.1082 +* If the specified row (constraint) is partitioning equality (see
254.1083 +* below), the routine npp_is_partitioning returns non-zero. Otherwise,
254.1084 +* it returns zero.
254.1085 +*
254.1086 +* PARTITIONING EQUALITIES
254.1087 +*
254.1088 +* In canonical format the partitioning equality is the following:
254.1089 +*
254.1090 +* sum x[j] = 1, (1)
254.1091 +* j in J
254.1092 +*
254.1093 +* where all variables x[j] are binary. This equality expresses the
254.1094 +* condition that in any integer feasible solution exactly one variable
254.1095 +* in set J must take non-zero (unity) value while other variables must
254.1096 +* be equal to zero. W.l.o.g. it is assumed that |J| >= 2, because if
254.1097 +* J is empty, the inequality (1) is infeasible, and if |J| = 1, the
254.1098 +* inequality (1) is a fixing row.
254.1099 +*
254.1100 +* In general case the partitioning equality may include original
254.1101 +* variables x[j] as well as their complements x~[j]:
254.1102 +*
254.1103 +* sum x[j] + sum x~[j] = 1, (2)
254.1104 +* j in Jp j in Jn
254.1105 +*
254.1106 +* where Jp and Jn are not intersected. Therefore, using substitution
254.1107 +* x~[j] = 1 - x[j] leads to the partitioning equality in generalized
254.1108 +* format:
254.1109 +*
254.1110 +* sum x[j] - sum x[j] = 1 - |Jn|. (3)
254.1111 +* j in Jp j in Jn */
254.1112 +
254.1113 +int npp_is_partitioning(NPP *npp, NPPROW *row)
254.1114 +{ /* test if constraint is partitioning equality */
254.1115 + NPPCOL *col;
254.1116 + NPPAIJ *aij;
254.1117 + int b;
254.1118 + xassert(npp == npp);
254.1119 + if (row->lb != row->ub) return 0;
254.1120 + b = 1;
254.1121 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
254.1122 + { col = aij->col;
254.1123 + if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
254.1124 + return 0;
254.1125 + if (aij->val == +1.0)
254.1126 + ;
254.1127 + else if (aij->val == -1.0)
254.1128 + b--;
254.1129 + else
254.1130 + return 0;
254.1131 + }
254.1132 + if (row->lb != (double)b) return 0;
254.1133 + return 1;
254.1134 +}
254.1135 +
254.1136 +/***********************************************************************
254.1137 +* NAME
254.1138 +*
254.1139 +* npp_reduce_ineq_coef - reduce inequality constraint coefficients
254.1140 +*
254.1141 +* SYNOPSIS
254.1142 +*
254.1143 +* #include "glpnpp.h"
254.1144 +* int npp_reduce_ineq_coef(NPP *npp, NPPROW *row);
254.1145 +*
254.1146 +* DESCRIPTION
254.1147 +*
254.1148 +* The routine npp_reduce_ineq_coef processes specified inequality
254.1149 +* constraint attempting to replace it by an equivalent constraint,
254.1150 +* where magnitude of coefficients at binary variables is smaller than
254.1151 +* in the original constraint. If the inequality is double-sided, it is
254.1152 +* replaced by a pair of single-sided inequalities, if necessary.
254.1153 +*
254.1154 +* RETURNS
254.1155 +*
254.1156 +* The routine npp_reduce_ineq_coef returns the number of coefficients
254.1157 +* reduced.
254.1158 +*
254.1159 +* BACKGROUND
254.1160 +*
254.1161 +* Consider an inequality constraint:
254.1162 +*
254.1163 +* sum a[j] x[j] >= b. (1)
254.1164 +* j in J
254.1165 +*
254.1166 +* (In case of '<=' inequality it can be transformed to '>=' format by
254.1167 +* multiplying both its sides by -1.) Let x[k] be a binary variable;
254.1168 +* other variables can be integer as well as continuous. We can write
254.1169 +* constraint (1) as follows:
254.1170 +*
254.1171 +* a[k] x[k] + t[k] >= b, (2)
254.1172 +*
254.1173 +* where:
254.1174 +*
254.1175 +* t[k] = sum a[j] x[j]. (3)
254.1176 +* j in J\{k}
254.1177 +*
254.1178 +* Since x[k] is binary, constraint (2) is equivalent to disjunction of
254.1179 +* the following two constraints:
254.1180 +*
254.1181 +* x[k] = 0, t[k] >= b (4)
254.1182 +*
254.1183 +* OR
254.1184 +*
254.1185 +* x[k] = 1, t[k] >= b - a[k]. (5)
254.1186 +*
254.1187 +* Let also that for the partial sum t[k] be known some its implied
254.1188 +* lower bound inf t[k].
254.1189 +*
254.1190 +* Case a[k] > 0. Let inf t[k] < b, since otherwise both constraints
254.1191 +* (4) and (5) and therefore constraint (2) are redundant.
254.1192 +* If inf t[k] > b - a[k], only constraint (5) is redundant, in which
254.1193 +* case it can be replaced with the following redundant and therefore
254.1194 +* equivalent constraint:
254.1195 +*
254.1196 +* t[k] >= b - a'[k] = inf t[k], (6)
254.1197 +*
254.1198 +* where:
254.1199 +*
254.1200 +* a'[k] = b - inf t[k]. (7)
254.1201 +*
254.1202 +* Thus, the original constraint (2) is equivalent to the following
254.1203 +* constraint with coefficient at variable x[k] changed:
254.1204 +*
254.1205 +* a'[k] x[k] + t[k] >= b. (8)
254.1206 +*
254.1207 +* From inf t[k] < b it follows that a'[k] > 0, i.e. the coefficient
254.1208 +* at x[k] keeps its sign. And from inf t[k] > b - a[k] it follows that
254.1209 +* a'[k] < a[k], i.e. the coefficient reduces in magnitude.
254.1210 +*
254.1211 +* Case a[k] < 0. Let inf t[k] < b - a[k], since otherwise both
254.1212 +* constraints (4) and (5) and therefore constraint (2) are redundant.
254.1213 +* If inf t[k] > b, only constraint (4) is redundant, in which case it
254.1214 +* can be replaced with the following redundant and therefore equivalent
254.1215 +* constraint:
254.1216 +*
254.1217 +* t[k] >= b' = inf t[k]. (9)
254.1218 +*
254.1219 +* Rewriting constraint (5) as follows:
254.1220 +*
254.1221 +* t[k] >= b - a[k] = b' - a'[k], (10)
254.1222 +*
254.1223 +* where:
254.1224 +*
254.1225 +* a'[k] = a[k] + b' - b = a[k] + inf t[k] - b, (11)
254.1226 +*
254.1227 +* we can see that disjunction of constraint (9) and (10) is equivalent
254.1228 +* to disjunction of constraint (4) and (5), from which it follows that
254.1229 +* the original constraint (2) is equivalent to the following constraint
254.1230 +* with both coefficient at variable x[k] and right-hand side changed:
254.1231 +*
254.1232 +* a'[k] x[k] + t[k] >= b'. (12)
254.1233 +*
254.1234 +* From inf t[k] < b - a[k] it follows that a'[k] < 0, i.e. the
254.1235 +* coefficient at x[k] keeps its sign. And from inf t[k] > b it follows
254.1236 +* that a'[k] > a[k], i.e. the coefficient reduces in magnitude.
254.1237 +*
254.1238 +* PROBLEM TRANSFORMATION
254.1239 +*
254.1240 +* In the routine npp_reduce_ineq_coef the following implied lower
254.1241 +* bound of the partial sum (3) is used:
254.1242 +*
254.1243 +* inf t[k] = sum a[j] l[j] + sum a[j] u[j], (13)
254.1244 +* j in Jp\{k} k in Jn\{k}
254.1245 +*
254.1246 +* where Jp = {j : a[j] > 0}, Jn = {j : a[j] < 0}, l[j] and u[j] are
254.1247 +* lower and upper bounds, resp., of variable x[j].
254.1248 +*
254.1249 +* In order to compute inf t[k] more efficiently, the following formula,
254.1250 +* which is equivalent to (13), is actually used:
254.1251 +*
254.1252 +* ( h - a[k] l[k] = h, if a[k] > 0,
254.1253 +* inf t[k] = < (14)
254.1254 +* ( h - a[k] u[k] = h - a[k], if a[k] < 0,
254.1255 +*
254.1256 +* where:
254.1257 +*
254.1258 +* h = sum a[j] l[j] + sum a[j] u[j] (15)
254.1259 +* j in Jp j in Jn
254.1260 +*
254.1261 +* is the implied lower bound of row (1).
254.1262 +*
254.1263 +* Reduction of positive coefficient (a[k] > 0) does not change value
254.1264 +* of h, since l[k] = 0. In case of reduction of negative coefficient
254.1265 +* (a[k] < 0) from (11) it follows that:
254.1266 +*
254.1267 +* delta a[k] = a'[k] - a[k] = inf t[k] - b (> 0), (16)
254.1268 +*
254.1269 +* so new value of h (accounting that u[k] = 1) can be computed as
254.1270 +* follows:
254.1271 +*
254.1272 +* h := h + delta a[k] = h + (inf t[k] - b). (17)
254.1273 +*
254.1274 +* RECOVERING SOLUTION
254.1275 +*
254.1276 +* None needed. */
254.1277 +
254.1278 +static int reduce_ineq_coef(NPP *npp, struct elem *ptr, double *_b)
254.1279 +{ /* process inequality constraint: sum a[j] x[j] >= b */
254.1280 + /* returns: the number of coefficients reduced */
254.1281 + struct elem *e;
254.1282 + int count = 0;
254.1283 + double h, inf_t, new_a, b = *_b;
254.1284 + xassert(npp == npp);
254.1285 + /* compute h; see (15) */
254.1286 + h = 0.0;
254.1287 + for (e = ptr; e != NULL; e = e->next)
254.1288 + { if (e->aj > 0.0)
254.1289 + { if (e->xj->lb == -DBL_MAX) goto done;
254.1290 + h += e->aj * e->xj->lb;
254.1291 + }
254.1292 + else /* e->aj < 0.0 */
254.1293 + { if (e->xj->ub == +DBL_MAX) goto done;
254.1294 + h += e->aj * e->xj->ub;
254.1295 + }
254.1296 + }
254.1297 + /* perform reduction of coefficients at binary variables */
254.1298 + for (e = ptr; e != NULL; e = e->next)
254.1299 + { /* skip non-binary variable */
254.1300 + if (!(e->xj->is_int && e->xj->lb == 0.0 && e->xj->ub == 1.0))
254.1301 + continue;
254.1302 + if (e->aj > 0.0)
254.1303 + { /* compute inf t[k]; see (14) */
254.1304 + inf_t = h;
254.1305 + if (b - e->aj < inf_t && inf_t < b)
254.1306 + { /* compute reduced coefficient a'[k]; see (7) */
254.1307 + new_a = b - inf_t;
254.1308 + if (new_a >= +1e-3 &&
254.1309 + e->aj - new_a >= 0.01 * (1.0 + e->aj))
254.1310 + { /* accept a'[k] */
254.1311 +#ifdef GLP_DEBUG
254.1312 + xprintf("+");
254.1313 +#endif
254.1314 + e->aj = new_a;
254.1315 + count++;
254.1316 + }
254.1317 + }
254.1318 + }
254.1319 + else /* e->aj < 0.0 */
254.1320 + { /* compute inf t[k]; see (14) */
254.1321 + inf_t = h - e->aj;
254.1322 + if (b < inf_t && inf_t < b - e->aj)
254.1323 + { /* compute reduced coefficient a'[k]; see (11) */
254.1324 + new_a = e->aj + (inf_t - b);
254.1325 + if (new_a <= -1e-3 &&
254.1326 + new_a - e->aj >= 0.01 * (1.0 - e->aj))
254.1327 + { /* accept a'[k] */
254.1328 +#ifdef GLP_DEBUG
254.1329 + xprintf("-");
254.1330 +#endif
254.1331 + e->aj = new_a;
254.1332 + /* update h; see (17) */
254.1333 + h += (inf_t - b);
254.1334 + /* compute b'; see (9) */
254.1335 + b = inf_t;
254.1336 + count++;
254.1337 + }
254.1338 + }
254.1339 + }
254.1340 + }
254.1341 + *_b = b;
254.1342 +done: return count;
254.1343 +}
254.1344 +
254.1345 +int npp_reduce_ineq_coef(NPP *npp, NPPROW *row)
254.1346 +{ /* reduce inequality constraint coefficients */
254.1347 + NPPROW *copy;
254.1348 + NPPAIJ *aij;
254.1349 + struct elem *ptr, *e;
254.1350 + int kase, count[2];
254.1351 + double b;
254.1352 + /* the row must be inequality constraint */
254.1353 + xassert(row->lb < row->ub);
254.1354 + count[0] = count[1] = 0;
254.1355 + for (kase = 0; kase <= 1; kase++)
254.1356 + { if (kase == 0)
254.1357 + { /* process row lower bound */
254.1358 + if (row->lb == -DBL_MAX) continue;
254.1359 +#ifdef GLP_DEBUG
254.1360 + xprintf("L");
254.1361 +#endif
254.1362 + ptr = copy_form(npp, row, +1.0);
254.1363 + b = + row->lb;
254.1364 + }
254.1365 + else
254.1366 + { /* process row upper bound */
254.1367 + if (row->ub == +DBL_MAX) continue;
254.1368 +#ifdef GLP_DEBUG
254.1369 + xprintf("U");
254.1370 +#endif
254.1371 + ptr = copy_form(npp, row, -1.0);
254.1372 + b = - row->ub;
254.1373 + }
254.1374 + /* now the inequality has the form "sum a[j] x[j] >= b" */
254.1375 + count[kase] = reduce_ineq_coef(npp, ptr, &b);
254.1376 + if (count[kase] > 0)
254.1377 + { /* the original inequality has been replaced by equivalent
254.1378 + one with coefficients reduced */
254.1379 + if (row->lb == -DBL_MAX || row->ub == +DBL_MAX)
254.1380 + { /* the original row is single-sided inequality; no copy
254.1381 + is needed */
254.1382 + copy = NULL;
254.1383 + }
254.1384 + else
254.1385 + { /* the original row is double-sided inequality; we need
254.1386 + to create its copy for other bound before replacing it
254.1387 + with the equivalent inequality */
254.1388 +#ifdef GLP_DEBUG
254.1389 + xprintf("*");
254.1390 +#endif
254.1391 + copy = npp_add_row(npp);
254.1392 + if (kase == 0)
254.1393 + { /* the copy is for upper bound */
254.1394 + copy->lb = -DBL_MAX, copy->ub = row->ub;
254.1395 + }
254.1396 + else
254.1397 + { /* the copy is for lower bound */
254.1398 + copy->lb = row->lb, copy->ub = +DBL_MAX;
254.1399 + }
254.1400 + /* copy original row coefficients */
254.1401 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
254.1402 + npp_add_aij(npp, copy, aij->col, aij->val);
254.1403 + }
254.1404 + /* replace the original inequality by equivalent one */
254.1405 + npp_erase_row(npp, row);
254.1406 + row->lb = b, row->ub = +DBL_MAX;
254.1407 + for (e = ptr; e != NULL; e = e->next)
254.1408 + npp_add_aij(npp, row, e->xj, e->aj);
254.1409 + /* continue processing upper bound for the copy */
254.1410 + if (copy != NULL) row = copy;
254.1411 + }
254.1412 + drop_form(npp, ptr);
254.1413 + }
254.1414 + return count[0] + count[1];
254.1415 +}
254.1416 +
254.1417 +/* eof */
255.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
255.2 +++ b/src/glpnpp05.c Mon Dec 06 13:09:21 2010 +0100
255.3 @@ -0,0 +1,809 @@
255.4 +/* glpnpp05.c */
255.5 +
255.6 +/***********************************************************************
255.7 +* This code is part of GLPK (GNU Linear Programming Kit).
255.8 +*
255.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
255.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
255.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
255.12 +* E-mail: <mao@gnu.org>.
255.13 +*
255.14 +* GLPK is free software: you can redistribute it and/or modify it
255.15 +* under the terms of the GNU General Public License as published by
255.16 +* the Free Software Foundation, either version 3 of the License, or
255.17 +* (at your option) any later version.
255.18 +*
255.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
255.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
255.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
255.22 +* License for more details.
255.23 +*
255.24 +* You should have received a copy of the GNU General Public License
255.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
255.26 +***********************************************************************/
255.27 +
255.28 +#include "glpnpp.h"
255.29 +
255.30 +/***********************************************************************
255.31 +* NAME
255.32 +*
255.33 +* npp_clean_prob - perform initial LP/MIP processing
255.34 +*
255.35 +* SYNOPSIS
255.36 +*
255.37 +* #include "glpnpp.h"
255.38 +* void npp_clean_prob(NPP *npp);
255.39 +*
255.40 +* DESCRIPTION
255.41 +*
255.42 +* The routine npp_clean_prob performs initial LP/MIP processing that
255.43 +* currently includes:
255.44 +*
255.45 +* 1) removing free rows;
255.46 +*
255.47 +* 2) replacing double-sided constraint rows with almost identical
255.48 +* bounds, by equality constraint rows;
255.49 +*
255.50 +* 3) removing fixed columns;
255.51 +*
255.52 +* 4) replacing double-bounded columns with almost identical bounds by
255.53 +* fixed columns and removing those columns;
255.54 +*
255.55 +* 5) initial processing constraint coefficients (not implemented);
255.56 +*
255.57 +* 6) initial processing objective coefficients (not implemented). */
255.58 +
255.59 +void npp_clean_prob(NPP *npp)
255.60 +{ /* perform initial LP/MIP processing */
255.61 + NPPROW *row, *next_row;
255.62 + NPPCOL *col, *next_col;
255.63 + int ret;
255.64 + xassert(npp == npp);
255.65 + /* process rows which originally are free */
255.66 + for (row = npp->r_head; row != NULL; row = next_row)
255.67 + { next_row = row->next;
255.68 + if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
255.69 + { /* process free row */
255.70 +#ifdef GLP_DEBUG
255.71 + xprintf("1");
255.72 +#endif
255.73 + npp_free_row(npp, row);
255.74 + /* row was deleted */
255.75 + }
255.76 + }
255.77 + /* process rows which originally are double-sided inequalities */
255.78 + for (row = npp->r_head; row != NULL; row = next_row)
255.79 + { next_row = row->next;
255.80 + if (row->lb != -DBL_MAX && row->ub != +DBL_MAX &&
255.81 + row->lb < row->ub)
255.82 + { ret = npp_make_equality(npp, row);
255.83 + if (ret == 0)
255.84 + ;
255.85 + else if (ret == 1)
255.86 + { /* row was replaced by equality constraint */
255.87 +#ifdef GLP_DEBUG
255.88 + xprintf("2");
255.89 +#endif
255.90 + }
255.91 + else
255.92 + xassert(ret != ret);
255.93 + }
255.94 + }
255.95 + /* process columns which are originally fixed */
255.96 + for (col = npp->c_head; col != NULL; col = next_col)
255.97 + { next_col = col->next;
255.98 + if (col->lb == col->ub)
255.99 + { /* process fixed column */
255.100 +#ifdef GLP_DEBUG
255.101 + xprintf("3");
255.102 +#endif
255.103 + npp_fixed_col(npp, col);
255.104 + /* column was deleted */
255.105 + }
255.106 + }
255.107 + /* process columns which are originally double-bounded */
255.108 + for (col = npp->c_head; col != NULL; col = next_col)
255.109 + { next_col = col->next;
255.110 + if (col->lb != -DBL_MAX && col->ub != +DBL_MAX &&
255.111 + col->lb < col->ub)
255.112 + { ret = npp_make_fixed(npp, col);
255.113 + if (ret == 0)
255.114 + ;
255.115 + else if (ret == 1)
255.116 + { /* column was replaced by fixed column; process it */
255.117 +#ifdef GLP_DEBUG
255.118 + xprintf("4");
255.119 +#endif
255.120 + npp_fixed_col(npp, col);
255.121 + /* column was deleted */
255.122 + }
255.123 + }
255.124 + }
255.125 + return;
255.126 +}
255.127 +
255.128 +/***********************************************************************
255.129 +* NAME
255.130 +*
255.131 +* npp_process_row - perform basic row processing
255.132 +*
255.133 +* SYNOPSIS
255.134 +*
255.135 +* #include "glpnpp.h"
255.136 +* int npp_process_row(NPP *npp, NPPROW *row, int hard);
255.137 +*
255.138 +* DESCRIPTION
255.139 +*
255.140 +* The routine npp_process_row performs basic row processing that
255.141 +* currently includes:
255.142 +*
255.143 +* 1) removing empty row;
255.144 +*
255.145 +* 2) removing equality constraint row singleton and corresponding
255.146 +* column;
255.147 +*
255.148 +* 3) removing inequality constraint row singleton and corresponding
255.149 +* column if it was fixed;
255.150 +*
255.151 +* 4) performing general row analysis;
255.152 +*
255.153 +* 5) removing redundant row bounds;
255.154 +*
255.155 +* 6) removing forcing row and corresponding columns;
255.156 +*
255.157 +* 7) removing row which becomes free due to redundant bounds;
255.158 +*
255.159 +* 8) computing implied bounds for all columns in the row and using
255.160 +* them to strengthen current column bounds (MIP only, optional,
255.161 +* performed if the flag hard is on).
255.162 +*
255.163 +* Additionally the routine may activate affected rows and/or columns
255.164 +* for further processing.
255.165 +*
255.166 +* RETURNS
255.167 +*
255.168 +* 0 success;
255.169 +*
255.170 +* GLP_ENOPFS primal/integer infeasibility detected;
255.171 +*
255.172 +* GLP_ENODFS dual infeasibility detected. */
255.173 +
255.174 +int npp_process_row(NPP *npp, NPPROW *row, int hard)
255.175 +{ /* perform basic row processing */
255.176 + NPPCOL *col;
255.177 + NPPAIJ *aij, *next_aij, *aaa;
255.178 + int ret;
255.179 + /* row must not be free */
255.180 + xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
255.181 + /* start processing row */
255.182 + if (row->ptr == NULL)
255.183 + { /* empty row */
255.184 + ret = npp_empty_row(npp, row);
255.185 + if (ret == 0)
255.186 + { /* row was deleted */
255.187 +#ifdef GLP_DEBUG
255.188 + xprintf("A");
255.189 +#endif
255.190 + return 0;
255.191 + }
255.192 + else if (ret == 1)
255.193 + { /* primal infeasibility */
255.194 + return GLP_ENOPFS;
255.195 + }
255.196 + else
255.197 + xassert(ret != ret);
255.198 + }
255.199 + if (row->ptr->r_next == NULL)
255.200 + { /* row singleton */
255.201 + col = row->ptr->col;
255.202 + if (row->lb == row->ub)
255.203 + { /* equality constraint */
255.204 + ret = npp_eq_singlet(npp, row);
255.205 + if (ret == 0)
255.206 + { /* column was fixed, row was deleted */
255.207 +#ifdef GLP_DEBUG
255.208 + xprintf("B");
255.209 +#endif
255.210 + /* activate rows affected by column */
255.211 + for (aij = col->ptr; aij != NULL; aij = aij->c_next)
255.212 + npp_activate_row(npp, aij->row);
255.213 + /* process fixed column */
255.214 + npp_fixed_col(npp, col);
255.215 + /* column was deleted */
255.216 + return 0;
255.217 + }
255.218 + else if (ret == 1 || ret == 2)
255.219 + { /* primal/integer infeasibility */
255.220 + return GLP_ENOPFS;
255.221 + }
255.222 + else
255.223 + xassert(ret != ret);
255.224 + }
255.225 + else
255.226 + { /* inequality constraint */
255.227 + ret = npp_ineq_singlet(npp, row);
255.228 + if (0 <= ret && ret <= 3)
255.229 + { /* row was deleted */
255.230 +#ifdef GLP_DEBUG
255.231 + xprintf("C");
255.232 +#endif
255.233 + /* activate column, since its length was changed due to
255.234 + row deletion */
255.235 + npp_activate_col(npp, col);
255.236 + if (ret >= 2)
255.237 + { /* column bounds changed significantly or column was
255.238 + fixed */
255.239 + /* activate rows affected by column */
255.240 + for (aij = col->ptr; aij != NULL; aij = aij->c_next)
255.241 + npp_activate_row(npp, aij->row);
255.242 + }
255.243 + if (ret == 3)
255.244 + { /* column was fixed; process it */
255.245 +#ifdef GLP_DEBUG
255.246 + xprintf("D");
255.247 +#endif
255.248 + npp_fixed_col(npp, col);
255.249 + /* column was deleted */
255.250 + }
255.251 + return 0;
255.252 + }
255.253 + else if (ret == 4)
255.254 + { /* primal infeasibility */
255.255 + return GLP_ENOPFS;
255.256 + }
255.257 + else
255.258 + xassert(ret != ret);
255.259 + }
255.260 + }
255.261 +#if 0
255.262 + /* sometimes this causes too large round-off errors; probably
255.263 + pivot coefficient should be chosen more carefully */
255.264 + if (row->ptr->r_next->r_next == NULL)
255.265 + { /* row doubleton */
255.266 + if (row->lb == row->ub)
255.267 + { /* equality constraint */
255.268 + if (!(row->ptr->col->is_int ||
255.269 + row->ptr->r_next->col->is_int))
255.270 + { /* both columns are continuous */
255.271 + NPPCOL *q;
255.272 + q = npp_eq_doublet(npp, row);
255.273 + if (q != NULL)
255.274 + { /* column q was eliminated */
255.275 +#ifdef GLP_DEBUG
255.276 + xprintf("E");
255.277 +#endif
255.278 + /* now column q is singleton of type "implied slack
255.279 + variable"; we process it here to make sure that on
255.280 + recovering basic solution the row is always active
255.281 + equality constraint (as required by the routine
255.282 + rcv_eq_doublet) */
255.283 + xassert(npp_process_col(npp, q) == 0);
255.284 + /* column q was deleted; note that row p also may be
255.285 + deleted */
255.286 + return 0;
255.287 + }
255.288 + }
255.289 + }
255.290 + }
255.291 +#endif
255.292 + /* general row analysis */
255.293 + ret = npp_analyze_row(npp, row);
255.294 + xassert(0x00 <= ret && ret <= 0xFF);
255.295 + if (ret == 0x33)
255.296 + { /* row bounds are inconsistent with column bounds */
255.297 + return GLP_ENOPFS;
255.298 + }
255.299 + if ((ret & 0x0F) == 0x00)
255.300 + { /* row lower bound does not exist or redundant */
255.301 + if (row->lb != -DBL_MAX)
255.302 + { /* remove redundant row lower bound */
255.303 +#ifdef GLP_DEBUG
255.304 + xprintf("F");
255.305 +#endif
255.306 + npp_inactive_bound(npp, row, 0);
255.307 + }
255.308 + }
255.309 + else if ((ret & 0x0F) == 0x01)
255.310 + { /* row lower bound can be active */
255.311 + /* see below */
255.312 + }
255.313 + else if ((ret & 0x0F) == 0x02)
255.314 + { /* row lower bound is a forcing bound */
255.315 +#ifdef GLP_DEBUG
255.316 + xprintf("G");
255.317 +#endif
255.318 + /* process forcing row */
255.319 + if (npp_forcing_row(npp, row, 0) == 0)
255.320 +fixup: { /* columns were fixed, row was made free */
255.321 + for (aij = row->ptr; aij != NULL; aij = next_aij)
255.322 + { /* process column fixed by forcing row */
255.323 +#ifdef GLP_DEBUG
255.324 + xprintf("H");
255.325 +#endif
255.326 + col = aij->col;
255.327 + next_aij = aij->r_next;
255.328 + /* activate rows affected by column */
255.329 + for (aaa = col->ptr; aaa != NULL; aaa = aaa->c_next)
255.330 + npp_activate_row(npp, aaa->row);
255.331 + /* process fixed column */
255.332 + npp_fixed_col(npp, col);
255.333 + /* column was deleted */
255.334 + }
255.335 + /* process free row (which now is empty due to deletion of
255.336 + all its columns) */
255.337 + npp_free_row(npp, row);
255.338 + /* row was deleted */
255.339 + return 0;
255.340 + }
255.341 + }
255.342 + else
255.343 + xassert(ret != ret);
255.344 + if ((ret & 0xF0) == 0x00)
255.345 + { /* row upper bound does not exist or redundant */
255.346 + if (row->ub != +DBL_MAX)
255.347 + { /* remove redundant row upper bound */
255.348 +#ifdef GLP_DEBUG
255.349 + xprintf("I");
255.350 +#endif
255.351 + npp_inactive_bound(npp, row, 1);
255.352 + }
255.353 + }
255.354 + else if ((ret & 0xF0) == 0x10)
255.355 + { /* row upper bound can be active */
255.356 + /* see below */
255.357 + }
255.358 + else if ((ret & 0xF0) == 0x20)
255.359 + { /* row upper bound is a forcing bound */
255.360 +#ifdef GLP_DEBUG
255.361 + xprintf("J");
255.362 +#endif
255.363 + /* process forcing row */
255.364 + if (npp_forcing_row(npp, row, 1) == 0) goto fixup;
255.365 + }
255.366 + else
255.367 + xassert(ret != ret);
255.368 + if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
255.369 + { /* row became free due to redundant bounds removal */
255.370 +#ifdef GLP_DEBUG
255.371 + xprintf("K");
255.372 +#endif
255.373 + /* activate its columns, since their length will change due
255.374 + to row deletion */
255.375 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
255.376 + npp_activate_col(npp, aij->col);
255.377 + /* process free row */
255.378 + npp_free_row(npp, row);
255.379 + /* row was deleted */
255.380 + return 0;
255.381 + }
255.382 +#if 1 /* 23/XII-2009 */
255.383 + /* row lower and/or upper bounds can be active */
255.384 + if (npp->sol == GLP_MIP && hard)
255.385 + { /* improve current column bounds (optional) */
255.386 + if (npp_improve_bounds(npp, row, 1) < 0)
255.387 + return GLP_ENOPFS;
255.388 + }
255.389 +#endif
255.390 + return 0;
255.391 +}
255.392 +
255.393 +/***********************************************************************
255.394 +* NAME
255.395 +*
255.396 +* npp_improve_bounds - improve current column bounds
255.397 +*
255.398 +* SYNOPSIS
255.399 +*
255.400 +* #include "glpnpp.h"
255.401 +* int npp_improve_bounds(NPP *npp, NPPROW *row, int flag);
255.402 +*
255.403 +* DESCRIPTION
255.404 +*
255.405 +* The routine npp_improve_bounds analyzes specified row (inequality
255.406 +* or equality constraint) to determine implied column bounds and then
255.407 +* uses these bounds to improve (strengthen) current column bounds.
255.408 +*
255.409 +* If the flag is on and current column bounds changed significantly
255.410 +* or the column was fixed, the routine activate rows affected by the
255.411 +* column for further processing. (This feature is intended to be used
255.412 +* in the main loop of the routine npp_process_row.)
255.413 +*
255.414 +* NOTE: This operation can be used for MIP problem only.
255.415 +*
255.416 +* RETURNS
255.417 +*
255.418 +* The routine npp_improve_bounds returns the number of significantly
255.419 +* changed bounds plus the number of column having been fixed due to
255.420 +* bound improvements. However, if the routine detects primal/integer
255.421 +* infeasibility, it returns a negative value. */
255.422 +
255.423 +int npp_improve_bounds(NPP *npp, NPPROW *row, int flag)
255.424 +{ /* improve current column bounds */
255.425 + NPPCOL *col;
255.426 + NPPAIJ *aij, *next_aij, *aaa;
255.427 + int kase, ret, count = 0;
255.428 + double lb, ub;
255.429 + xassert(npp->sol == GLP_MIP);
255.430 + /* row must not be free */
255.431 + xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
255.432 + /* determine implied column bounds */
255.433 + npp_implied_bounds(npp, row);
255.434 + /* and use these bounds to strengthen current column bounds */
255.435 + for (aij = row->ptr; aij != NULL; aij = next_aij)
255.436 + { col = aij->col;
255.437 + next_aij = aij->r_next;
255.438 + for (kase = 0; kase <= 1; kase++)
255.439 + { /* save current column bounds */
255.440 + lb = col->lb, ub = col->ub;
255.441 + if (kase == 0)
255.442 + { /* process implied column lower bound */
255.443 + if (col->ll.ll == -DBL_MAX) continue;
255.444 + ret = npp_implied_lower(npp, col, col->ll.ll);
255.445 + }
255.446 + else
255.447 + { /* process implied column upper bound */
255.448 + if (col->uu.uu == +DBL_MAX) continue;
255.449 + ret = npp_implied_upper(npp, col, col->uu.uu);
255.450 + }
255.451 + if (ret == 0 || ret == 1)
255.452 + { /* current column bounds did not change or changed, but
255.453 + not significantly; restore current column bounds */
255.454 + col->lb = lb, col->ub = ub;
255.455 + }
255.456 + else if (ret == 2 || ret == 3)
255.457 + { /* current column bounds changed significantly or column
255.458 + was fixed */
255.459 +#ifdef GLP_DEBUG
255.460 + xprintf("L");
255.461 +#endif
255.462 + count++;
255.463 + /* activate other rows affected by column, if required */
255.464 + if (flag)
255.465 + { for (aaa = col->ptr; aaa != NULL; aaa = aaa->c_next)
255.466 + { if (aaa->row != row)
255.467 + npp_activate_row(npp, aaa->row);
255.468 + }
255.469 + }
255.470 + if (ret == 3)
255.471 + { /* process fixed column */
255.472 +#ifdef GLP_DEBUG
255.473 + xprintf("M");
255.474 +#endif
255.475 + npp_fixed_col(npp, col);
255.476 + /* column was deleted */
255.477 + break; /* for kase */
255.478 + }
255.479 + }
255.480 + else if (ret == 4)
255.481 + { /* primal/integer infeasibility */
255.482 + return -1;
255.483 + }
255.484 + else
255.485 + xassert(ret != ret);
255.486 + }
255.487 + }
255.488 + return count;
255.489 +}
255.490 +
255.491 +/***********************************************************************
255.492 +* NAME
255.493 +*
255.494 +* npp_process_col - perform basic column processing
255.495 +*
255.496 +* SYNOPSIS
255.497 +*
255.498 +* #include "glpnpp.h"
255.499 +* int npp_process_col(NPP *npp, NPPCOL *col);
255.500 +*
255.501 +* DESCRIPTION
255.502 +*
255.503 +* The routine npp_process_col performs basic column processing that
255.504 +* currently includes:
255.505 +*
255.506 +* 1) fixing and removing empty column;
255.507 +*
255.508 +* 2) removing column singleton, which is implied slack variable, and
255.509 +* corresponding row if it becomes free;
255.510 +*
255.511 +* 3) removing bounds of column, which is implied free variable, and
255.512 +* replacing corresponding row by equality constraint.
255.513 +*
255.514 +* Additionally the routine may activate affected rows and/or columns
255.515 +* for further processing.
255.516 +*
255.517 +* RETURNS
255.518 +*
255.519 +* 0 success;
255.520 +*
255.521 +* GLP_ENOPFS primal/integer infeasibility detected;
255.522 +*
255.523 +* GLP_ENODFS dual infeasibility detected. */
255.524 +
255.525 +int npp_process_col(NPP *npp, NPPCOL *col)
255.526 +{ /* perform basic column processing */
255.527 + NPPROW *row;
255.528 + NPPAIJ *aij;
255.529 + int ret;
255.530 + /* column must not be fixed */
255.531 + xassert(col->lb < col->ub);
255.532 + /* start processing column */
255.533 + if (col->ptr == NULL)
255.534 + { /* empty column */
255.535 + ret = npp_empty_col(npp, col);
255.536 + if (ret == 0)
255.537 + { /* column was fixed and deleted */
255.538 +#ifdef GLP_DEBUG
255.539 + xprintf("N");
255.540 +#endif
255.541 + return 0;
255.542 + }
255.543 + else if (ret == 1)
255.544 + { /* dual infeasibility */
255.545 + return GLP_ENODFS;
255.546 + }
255.547 + else
255.548 + xassert(ret != ret);
255.549 + }
255.550 + if (col->ptr->c_next == NULL)
255.551 + { /* column singleton */
255.552 + row = col->ptr->row;
255.553 + if (row->lb == row->ub)
255.554 + { /* equality constraint */
255.555 + if (!col->is_int)
255.556 +slack: { /* implied slack variable */
255.557 +#ifdef GLP_DEBUG
255.558 + xprintf("O");
255.559 +#endif
255.560 + npp_implied_slack(npp, col);
255.561 + /* column was deleted */
255.562 + if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
255.563 + { /* row became free due to implied slack variable */
255.564 +#ifdef GLP_DEBUG
255.565 + xprintf("P");
255.566 +#endif
255.567 + /* activate columns affected by row */
255.568 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
255.569 + npp_activate_col(npp, aij->col);
255.570 + /* process free row */
255.571 + npp_free_row(npp, row);
255.572 + /* row was deleted */
255.573 + }
255.574 + else
255.575 + { /* row became inequality constraint; activate it
255.576 + since its length changed due to column deletion */
255.577 + npp_activate_row(npp, row);
255.578 + }
255.579 + return 0;
255.580 + }
255.581 + }
255.582 + else
255.583 + { /* inequality constraint */
255.584 + if (!col->is_int)
255.585 + { ret = npp_implied_free(npp, col);
255.586 + if (ret == 0)
255.587 + { /* implied free variable */
255.588 +#ifdef GLP_DEBUG
255.589 + xprintf("Q");
255.590 +#endif
255.591 + /* column bounds were removed, row was replaced by
255.592 + equality constraint */
255.593 + goto slack;
255.594 + }
255.595 + else if (ret == 1)
255.596 + { /* column is not implied free variable, because its
255.597 + lower and/or upper bounds can be active */
255.598 + }
255.599 + else if (ret == 2)
255.600 + { /* dual infeasibility */
255.601 + return GLP_ENODFS;
255.602 + }
255.603 + }
255.604 + }
255.605 + }
255.606 + /* column still exists */
255.607 + return 0;
255.608 +}
255.609 +
255.610 +/***********************************************************************
255.611 +* NAME
255.612 +*
255.613 +* npp_process_prob - perform basic LP/MIP processing
255.614 +*
255.615 +* SYNOPSIS
255.616 +*
255.617 +* #include "glpnpp.h"
255.618 +* int npp_process_prob(NPP *npp, int hard);
255.619 +*
255.620 +* DESCRIPTION
255.621 +*
255.622 +* The routine npp_process_prob performs basic LP/MIP processing that
255.623 +* currently includes:
255.624 +*
255.625 +* 1) initial LP/MIP processing (see the routine npp_clean_prob),
255.626 +*
255.627 +* 2) basic row processing (see the routine npp_process_row), and
255.628 +*
255.629 +* 3) basic column processing (see the routine npp_process_col).
255.630 +*
255.631 +* If the flag hard is on, the routine attempts to improve current
255.632 +* column bounds multiple times within the main processing loop, in
255.633 +* which case this feature may take a time. Otherwise, if the flag hard
255.634 +* is off, improving column bounds is performed only once at the end of
255.635 +* the main loop. (Note that this feature is used for MIP only.)
255.636 +*
255.637 +* The routine uses two sets: the set of active rows and the set of
255.638 +* active columns. Rows/columns are marked by a flag (the field temp in
255.639 +* NPPROW/NPPCOL). If the flag is non-zero, the row/column is active,
255.640 +* in which case it is placed in the beginning of the row/column list;
255.641 +* otherwise, if the flag is zero, the row/column is inactive, in which
255.642 +* case it is placed in the end of the row/column list. If a row/column
255.643 +* being currently processed may affect other rows/columns, the latters
255.644 +* are activated for further processing.
255.645 +*
255.646 +* RETURNS
255.647 +*
255.648 +* 0 success;
255.649 +*
255.650 +* GLP_ENOPFS primal/integer infeasibility detected;
255.651 +*
255.652 +* GLP_ENODFS dual infeasibility detected. */
255.653 +
255.654 +int npp_process_prob(NPP *npp, int hard)
255.655 +{ /* perform basic LP/MIP processing */
255.656 + NPPROW *row;
255.657 + NPPCOL *col;
255.658 + int processing, ret;
255.659 + /* perform initial LP/MIP processing */
255.660 + npp_clean_prob(npp);
255.661 + /* activate all remaining rows and columns */
255.662 + for (row = npp->r_head; row != NULL; row = row->next)
255.663 + row->temp = 1;
255.664 + for (col = npp->c_head; col != NULL; col = col->next)
255.665 + col->temp = 1;
255.666 + /* main processing loop */
255.667 + processing = 1;
255.668 + while (processing)
255.669 + { processing = 0;
255.670 + /* process all active rows */
255.671 + for (;;)
255.672 + { row = npp->r_head;
255.673 + if (row == NULL || !row->temp) break;
255.674 + npp_deactivate_row(npp, row);
255.675 + ret = npp_process_row(npp, row, hard);
255.676 + if (ret != 0) goto done;
255.677 + processing = 1;
255.678 + }
255.679 + /* process all active columns */
255.680 + for (;;)
255.681 + { col = npp->c_head;
255.682 + if (col == NULL || !col->temp) break;
255.683 + npp_deactivate_col(npp, col);
255.684 + ret = npp_process_col(npp, col);
255.685 + if (ret != 0) goto done;
255.686 + processing = 1;
255.687 + }
255.688 + }
255.689 +#if 1 /* 23/XII-2009 */
255.690 + if (npp->sol == GLP_MIP && !hard)
255.691 + { /* improve current column bounds (optional) */
255.692 + for (row = npp->r_head; row != NULL; row = row->next)
255.693 + { if (npp_improve_bounds(npp, row, 0) < 0)
255.694 + { ret = GLP_ENOPFS;
255.695 + goto done;
255.696 + }
255.697 + }
255.698 + }
255.699 +#endif
255.700 + /* all seems ok */
255.701 + ret = 0;
255.702 +done: xassert(ret == 0 || ret == GLP_ENOPFS || ret == GLP_ENODFS);
255.703 +#ifdef GLP_DEBUG
255.704 + xprintf("\n");
255.705 +#endif
255.706 + return ret;
255.707 +}
255.708 +
255.709 +/**********************************************************************/
255.710 +
255.711 +int npp_simplex(NPP *npp, const glp_smcp *parm)
255.712 +{ /* process LP prior to applying primal/dual simplex method */
255.713 + int ret;
255.714 + xassert(npp->sol == GLP_SOL);
255.715 + xassert(parm == parm);
255.716 + ret = npp_process_prob(npp, 0);
255.717 + return ret;
255.718 +}
255.719 +
255.720 +/**********************************************************************/
255.721 +
255.722 +int npp_integer(NPP *npp, const glp_iocp *parm)
255.723 +{ /* process MIP prior to applying branch-and-bound method */
255.724 + NPPROW *row, *prev_row;
255.725 + NPPCOL *col;
255.726 + NPPAIJ *aij;
255.727 + int count, ret;
255.728 + xassert(npp->sol == GLP_MIP);
255.729 + xassert(parm == parm);
255.730 + /*==============================================================*/
255.731 + /* perform basic MIP processing */
255.732 + ret = npp_process_prob(npp, 1);
255.733 + if (ret != 0) goto done;
255.734 + /*==============================================================*/
255.735 + /* binarize problem, if required */
255.736 + if (parm->binarize)
255.737 + npp_binarize_prob(npp);
255.738 + /*==============================================================*/
255.739 + /* identify hidden packing inequalities */
255.740 + count = 0;
255.741 + /* new rows will be added to the end of the row list, so we go
255.742 + from the end to beginning of the row list */
255.743 + for (row = npp->r_tail; row != NULL; row = prev_row)
255.744 + { prev_row = row->prev;
255.745 + /* skip free row */
255.746 + if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) continue;
255.747 + /* skip equality constraint */
255.748 + if (row->lb == row->ub) continue;
255.749 + /* skip row having less than two variables */
255.750 + if (row->ptr == NULL || row->ptr->r_next == NULL) continue;
255.751 + /* skip row having non-binary variables */
255.752 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
255.753 + { col = aij->col;
255.754 + if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
255.755 + break;
255.756 + }
255.757 + if (aij != NULL) continue;
255.758 + count += npp_hidden_packing(npp, row);
255.759 + }
255.760 + if (count > 0)
255.761 + xprintf("%d hidden packing inequaliti(es) were detected\n",
255.762 + count);
255.763 + /*==============================================================*/
255.764 + /* identify hidden covering inequalities */
255.765 + count = 0;
255.766 + /* new rows will be added to the end of the row list, so we go
255.767 + from the end to beginning of the row list */
255.768 + for (row = npp->r_tail; row != NULL; row = prev_row)
255.769 + { prev_row = row->prev;
255.770 + /* skip free row */
255.771 + if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) continue;
255.772 + /* skip equality constraint */
255.773 + if (row->lb == row->ub) continue;
255.774 + /* skip row having less than three variables */
255.775 + if (row->ptr == NULL || row->ptr->r_next == NULL ||
255.776 + row->ptr->r_next->r_next == NULL) continue;
255.777 + /* skip row having non-binary variables */
255.778 + for (aij = row->ptr; aij != NULL; aij = aij->r_next)
255.779 + { col = aij->col;
255.780 + if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
255.781 + break;
255.782 + }
255.783 + if (aij != NULL) continue;
255.784 + count += npp_hidden_covering(npp, row);
255.785 + }
255.786 + if (count > 0)
255.787 + xprintf("%d hidden covering inequaliti(es) were detected\n",
255.788 + count);
255.789 + /*==============================================================*/
255.790 + /* reduce inequality constraint coefficients */
255.791 + count = 0;
255.792 + /* new rows will be added to the end of the row list, so we go
255.793 + from the end to beginning of the row list */
255.794 + for (row = npp->r_tail; row != NULL; row = prev_row)
255.795 + { prev_row = row->prev;
255.796 + /* skip equality constraint */
255.797 + if (row->lb == row->ub) continue;
255.798 + count += npp_reduce_ineq_coef(npp, row);
255.799 + }
255.800 + if (count > 0)
255.801 + xprintf("%d constraint coefficient(s) were reduced\n", count);
255.802 + /*==============================================================*/
255.803 +#ifdef GLP_DEBUG
255.804 + routine(npp);
255.805 +#endif
255.806 + /*==============================================================*/
255.807 + /* all seems ok */
255.808 + ret = 0;
255.809 +done: return ret;
255.810 +}
255.811 +
255.812 +/* eof */
256.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
256.2 +++ b/src/glpqmd.c Mon Dec 06 13:09:21 2010 +0100
256.3 @@ -0,0 +1,584 @@
256.4 +/* glpqmd.c (quotient minimum degree algorithm) */
256.5 +
256.6 +/***********************************************************************
256.7 +* This code is part of GLPK (GNU Linear Programming Kit).
256.8 +*
256.9 +* THIS CODE IS THE RESULT OF TRANSLATION OF THE FORTRAN SUBROUTINES
256.10 +* GENQMD, QMDRCH, QMDQT, QMDUPD, AND QMDMRG FROM THE BOOK:
256.11 +*
256.12 +* ALAN GEORGE, JOSEPH W-H LIU. COMPUTER SOLUTION OF LARGE SPARSE
256.13 +* POSITIVE DEFINITE SYSTEMS. PRENTICE-HALL, 1981.
256.14 +*
256.15 +* THE TRANSLATION HAS BEEN DONE WITH THE PERMISSION OF THE AUTHORS
256.16 +* OF THE ORIGINAL FORTRAN SUBROUTINES: ALAN GEORGE AND JOSEPH LIU,
256.17 +* UNIVERSITY OF WATERLOO, WATERLOO, ONTARIO, CANADA.
256.18 +*
256.19 +* The translation was made by Andrew Makhorin <mao@gnu.org>.
256.20 +*
256.21 +* GLPK is free software: you can redistribute it and/or modify it
256.22 +* under the terms of the GNU General Public License as published by
256.23 +* the Free Software Foundation, either version 3 of the License, or
256.24 +* (at your option) any later version.
256.25 +*
256.26 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
256.27 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
256.28 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
256.29 +* License for more details.
256.30 +*
256.31 +* You should have received a copy of the GNU General Public License
256.32 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
256.33 +***********************************************************************/
256.34 +
256.35 +#include "glpqmd.h"
256.36 +
256.37 +/***********************************************************************
256.38 +* NAME
256.39 +*
256.40 +* genqmd - GENeral Quotient Minimum Degree algorithm
256.41 +*
256.42 +* SYNOPSIS
256.43 +*
256.44 +* #include "glpqmd.h"
256.45 +* void genqmd(int *neqns, int xadj[], int adjncy[], int perm[],
256.46 +* int invp[], int deg[], int marker[], int rchset[], int nbrhd[],
256.47 +* int qsize[], int qlink[], int *nofsub);
256.48 +*
256.49 +* PURPOSE
256.50 +*
256.51 +* This routine implements the minimum degree algorithm. It makes use
256.52 +* of the implicit representation of the elimination graph by quotient
256.53 +* graphs, and the notion of indistinguishable nodes.
256.54 +*
256.55 +* CAUTION
256.56 +*
256.57 +* The adjancy vector adjncy will be destroyed.
256.58 +*
256.59 +* INPUT PARAMETERS
256.60 +*
256.61 +* neqns - number of equations;
256.62 +* (xadj, adjncy) -
256.63 +* the adjancy structure.
256.64 +*
256.65 +* OUTPUT PARAMETERS
256.66 +*
256.67 +* perm - the minimum degree ordering;
256.68 +* invp - the inverse of perm.
256.69 +*
256.70 +* WORKING PARAMETERS
256.71 +*
256.72 +* deg - the degree vector. deg[i] is negative means node i has been
256.73 +* numbered;
256.74 +* marker - a marker vector, where marker[i] is negative means node i
256.75 +* has been merged with another nodeand thus can be ignored;
256.76 +* rchset - vector used for the reachable set;
256.77 +* nbrhd - vector used for neighborhood set;
256.78 +* qsize - vector used to store the size of indistinguishable
256.79 +* supernodes;
256.80 +* qlink - vector used to store indistinguishable nodes, i, qlink[i],
256.81 +* qlink[qlink[i]], ... are the members of the supernode
256.82 +* represented by i.
256.83 +*
256.84 +* PROGRAM SUBROUTINES
256.85 +*
256.86 +* qmdrch, qmdqt, qmdupd.
256.87 +***********************************************************************/
256.88 +
256.89 +void genqmd(int *_neqns, int xadj[], int adjncy[], int perm[],
256.90 + int invp[], int deg[], int marker[], int rchset[], int nbrhd[],
256.91 + int qsize[], int qlink[], int *_nofsub)
256.92 +{ int inode, ip, irch, j, mindeg, ndeg, nhdsze, node, np, num,
256.93 + nump1, nxnode, rchsze, search, thresh;
256.94 +# define neqns (*_neqns)
256.95 +# define nofsub (*_nofsub)
256.96 + /* Initialize degree vector and other working variables. */
256.97 + mindeg = neqns;
256.98 + nofsub = 0;
256.99 + for (node = 1; node <= neqns; node++)
256.100 + { perm[node] = node;
256.101 + invp[node] = node;
256.102 + marker[node] = 0;
256.103 + qsize[node] = 1;
256.104 + qlink[node] = 0;
256.105 + ndeg = xadj[node+1] - xadj[node];
256.106 + deg[node] = ndeg;
256.107 + if (ndeg < mindeg) mindeg = ndeg;
256.108 + }
256.109 + num = 0;
256.110 + /* Perform threshold search to get a node of min degree.
256.111 + Variable search point to where search should start. */
256.112 +s200: search = 1;
256.113 + thresh = mindeg;
256.114 + mindeg = neqns;
256.115 +s300: nump1 = num + 1;
256.116 + if (nump1 > search) search = nump1;
256.117 + for (j = search; j <= neqns; j++)
256.118 + { node = perm[j];
256.119 + if (marker[node] >= 0)
256.120 + { ndeg = deg[node];
256.121 + if (ndeg <= thresh) goto s500;
256.122 + if (ndeg < mindeg) mindeg = ndeg;
256.123 + }
256.124 + }
256.125 + goto s200;
256.126 + /* Node has minimum degree. Find its reachable sets by calling
256.127 + qmdrch. */
256.128 +s500: search = j;
256.129 + nofsub += deg[node];
256.130 + marker[node] = 1;
256.131 + qmdrch(&node, xadj, adjncy, deg, marker, &rchsze, rchset, &nhdsze,
256.132 + nbrhd);
256.133 + /* Eliminate all nodes indistinguishable from node. They are given
256.134 + by node, qlink[node], ... . */
256.135 + nxnode = node;
256.136 +s600: num++;
256.137 + np = invp[nxnode];
256.138 + ip = perm[num];
256.139 + perm[np] = ip;
256.140 + invp[ip] = np;
256.141 + perm[num] = nxnode;
256.142 + invp[nxnode] = num;
256.143 + deg[nxnode] = -1;
256.144 + nxnode = qlink[nxnode];
256.145 + if (nxnode > 0) goto s600;
256.146 + if (rchsze > 0)
256.147 + { /* Update the degrees of the nodes in the reachable set and
256.148 + identify indistinguishable nodes. */
256.149 + qmdupd(xadj, adjncy, &rchsze, rchset, deg, qsize, qlink,
256.150 + marker, &rchset[rchsze+1], &nbrhd[nhdsze+1]);
256.151 + /* Reset marker value of nodes in reach set. Update threshold
256.152 + value for cyclic search. Also call qmdqt to form new
256.153 + quotient graph. */
256.154 + marker[node] = 0;
256.155 + for (irch = 1; irch <= rchsze; irch++)
256.156 + { inode = rchset[irch];
256.157 + if (marker[inode] >= 0)
256.158 + { marker[inode] = 0;
256.159 + ndeg = deg[inode];
256.160 + if (ndeg < mindeg) mindeg = ndeg;
256.161 + if (ndeg <= thresh)
256.162 + { mindeg = thresh;
256.163 + thresh = ndeg;
256.164 + search = invp[inode];
256.165 + }
256.166 + }
256.167 + }
256.168 + if (nhdsze > 0)
256.169 + qmdqt(&node, xadj, adjncy, marker, &rchsze, rchset, nbrhd);
256.170 + }
256.171 + if (num < neqns) goto s300;
256.172 + return;
256.173 +# undef neqns
256.174 +# undef nofsub
256.175 +}
256.176 +
256.177 +/***********************************************************************
256.178 +* NAME
256.179 +*
256.180 +* qmdrch - Quotient MD ReaCHable set
256.181 +*
256.182 +* SYNOPSIS
256.183 +*
256.184 +* #include "glpqmd.h"
256.185 +* void qmdrch(int *root, int xadj[], int adjncy[], int deg[],
256.186 +* int marker[], int *rchsze, int rchset[], int *nhdsze,
256.187 +* int nbrhd[]);
256.188 +*
256.189 +* PURPOSE
256.190 +*
256.191 +* This subroutine determines the reachable set of a node through a
256.192 +* given subset. The adjancy structure is assumed to be stored in a
256.193 +* quotient graph format.
256.194 +*
256.195 +* INPUT PARAMETERS
256.196 +*
256.197 +* root - the given node not in the subset;
256.198 +* (xadj, adjncy) -
256.199 +* the adjancy structure pair;
256.200 +* deg - the degree vector. deg[i] < 0 means the node belongs to the
256.201 +* given subset.
256.202 +*
256.203 +* OUTPUT PARAMETERS
256.204 +*
256.205 +* (rchsze, rchset) -
256.206 +* the reachable set;
256.207 +* (nhdsze, nbrhd) -
256.208 +* the neighborhood set.
256.209 +*
256.210 +* UPDATED PARAMETERS
256.211 +*
256.212 +* marker - the marker vector for reach and nbrhd sets. > 0 means the
256.213 +* node is in reach set. < 0 means the node has been merged
256.214 +* with others in the quotient or it is in nbrhd set.
256.215 +***********************************************************************/
256.216 +
256.217 +void qmdrch(int *_root, int xadj[], int adjncy[], int deg[],
256.218 + int marker[], int *_rchsze, int rchset[], int *_nhdsze,
256.219 + int nbrhd[])
256.220 +{ int i, istop, istrt, j, jstop, jstrt, nabor, node;
256.221 +# define root (*_root)
256.222 +# define rchsze (*_rchsze)
256.223 +# define nhdsze (*_nhdsze)
256.224 + /* Loop through the neighbors of root in the quotient graph. */
256.225 + nhdsze = 0;
256.226 + rchsze = 0;
256.227 + istrt = xadj[root];
256.228 + istop = xadj[root+1] - 1;
256.229 + if (istop < istrt) return;
256.230 + for (i = istrt; i <= istop; i++)
256.231 + { nabor = adjncy[i];
256.232 + if (nabor == 0) return;
256.233 + if (marker[nabor] == 0)
256.234 + { if (deg[nabor] >= 0)
256.235 + { /* Include nabor into the reachable set. */
256.236 + rchsze++;
256.237 + rchset[rchsze] = nabor;
256.238 + marker[nabor] = 1;
256.239 + goto s600;
256.240 + }
256.241 + /* nabor has been eliminated. Find nodes reachable from
256.242 + it. */
256.243 + marker[nabor] = -1;
256.244 + nhdsze++;
256.245 + nbrhd[nhdsze] = nabor;
256.246 +s300: jstrt = xadj[nabor];
256.247 + jstop = xadj[nabor+1] - 1;
256.248 + for (j = jstrt; j <= jstop; j++)
256.249 + { node = adjncy[j];
256.250 + nabor = - node;
256.251 + if (node < 0) goto s300;
256.252 + if (node == 0) goto s600;
256.253 + if (marker[node] == 0)
256.254 + { rchsze++;
256.255 + rchset[rchsze] = node;
256.256 + marker[node] = 1;
256.257 + }
256.258 + }
256.259 + }
256.260 +s600: ;
256.261 + }
256.262 + return;
256.263 +# undef root
256.264 +# undef rchsze
256.265 +# undef nhdsze
256.266 +}
256.267 +
256.268 +/***********************************************************************
256.269 +* NAME
256.270 +*
256.271 +* qmdqt - Quotient MD Quotient graph Transformation
256.272 +*
256.273 +* SYNOPSIS
256.274 +*
256.275 +* #include "glpqmd.h"
256.276 +* void qmdqt(int *root, int xadj[], int adjncy[], int marker[],
256.277 +* int *rchsze, int rchset[], int nbrhd[]);
256.278 +*
256.279 +* PURPOSE
256.280 +*
256.281 +* This subroutine performs the quotient graph transformation after a
256.282 +* node has been eliminated.
256.283 +*
256.284 +* INPUT PARAMETERS
256.285 +*
256.286 +* root - the node just eliminated. It becomes the representative of
256.287 +* the new supernode;
256.288 +* (xadj, adjncy) -
256.289 +* the adjancy structure;
256.290 +* (rchsze, rchset) -
256.291 +* the reachable set of root in the old quotient graph;
256.292 +* nbrhd - the neighborhood set which will be merged with root to form
256.293 +* the new supernode;
256.294 +* marker - the marker vector.
256.295 +*
256.296 +* UPDATED PARAMETERS
256.297 +*
256.298 +* adjncy - becomes the adjncy of the quotient graph.
256.299 +***********************************************************************/
256.300 +
256.301 +void qmdqt(int *_root, int xadj[], int adjncy[], int marker[],
256.302 + int *_rchsze, int rchset[], int nbrhd[])
256.303 +{ int inhd, irch, j, jstop, jstrt, link, nabor, node;
256.304 +# define root (*_root)
256.305 +# define rchsze (*_rchsze)
256.306 + irch = 0;
256.307 + inhd = 0;
256.308 + node = root;
256.309 +s100: jstrt = xadj[node];
256.310 + jstop = xadj[node+1] - 2;
256.311 + if (jstop >= jstrt)
256.312 + { /* Place reach nodes into the adjacent list of node. */
256.313 + for (j = jstrt; j <= jstop; j++)
256.314 + { irch++;
256.315 + adjncy[j] = rchset[irch];
256.316 + if (irch >= rchsze) goto s400;
256.317 + }
256.318 + }
256.319 + /* Link to other space provided by the nbrhd set. */
256.320 + link = adjncy[jstop+1];
256.321 + node = - link;
256.322 + if (link >= 0)
256.323 + { inhd++;
256.324 + node = nbrhd[inhd];
256.325 + adjncy[jstop+1] = - node;
256.326 + }
256.327 + goto s100;
256.328 + /* All reachable nodes have been saved. End the adjacent list.
256.329 + Add root to the neighborhood list of each node in the reach
256.330 + set. */
256.331 +s400: adjncy[j+1] = 0;
256.332 + for (irch = 1; irch <= rchsze; irch++)
256.333 + { node = rchset[irch];
256.334 + if (marker[node] >= 0)
256.335 + { jstrt = xadj[node];
256.336 + jstop = xadj[node+1] - 1;
256.337 + for (j = jstrt; j <= jstop; j++)
256.338 + { nabor = adjncy[j];
256.339 + if (marker[nabor] < 0)
256.340 + { adjncy[j] = root;
256.341 + goto s600;
256.342 + }
256.343 + }
256.344 + }
256.345 +s600: ;
256.346 + }
256.347 + return;
256.348 +# undef root
256.349 +# undef rchsze
256.350 +}
256.351 +
256.352 +/***********************************************************************
256.353 +* NAME
256.354 +*
256.355 +* qmdupd - Quotient MD UPDate
256.356 +*
256.357 +* SYNOPSIS
256.358 +*
256.359 +* #include "glpqmd.h"
256.360 +* void qmdupd(int xadj[], int adjncy[], int *nlist, int list[],
256.361 +* int deg[], int qsize[], int qlink[], int marker[], int rchset[],
256.362 +* int nbrhd[]);
256.363 +*
256.364 +* PURPOSE
256.365 +*
256.366 +* This routine performs degree update for a set of nodes in the minimum
256.367 +* degree algorithm.
256.368 +*
256.369 +* INPUT PARAMETERS
256.370 +*
256.371 +* (xadj, adjncy) -
256.372 +* the adjancy structure;
256.373 +* (nlist, list) -
256.374 +* the list of nodes whose degree has to be updated.
256.375 +*
256.376 +* UPDATED PARAMETERS
256.377 +*
256.378 +* deg - the degree vector;
256.379 +* qsize - size of indistinguishable supernodes;
256.380 +* qlink - linked list for indistinguishable nodes;
256.381 +* marker - used to mark those nodes in reach/nbrhd sets.
256.382 +*
256.383 +* WORKING PARAMETERS
256.384 +*
256.385 +* rchset - the reachable set;
256.386 +* nbrhd - the neighborhood set.
256.387 +*
256.388 +* PROGRAM SUBROUTINES
256.389 +*
256.390 +* qmdmrg.
256.391 +***********************************************************************/
256.392 +
256.393 +void qmdupd(int xadj[], int adjncy[], int *_nlist, int list[],
256.394 + int deg[], int qsize[], int qlink[], int marker[], int rchset[],
256.395 + int nbrhd[])
256.396 +{ int deg0, deg1, il, inhd, inode, irch, j, jstop, jstrt, mark,
256.397 + nabor, nhdsze, node, rchsze;
256.398 +# define nlist (*_nlist)
256.399 + /* Find all eliminated supernodes that are adjacent to some nodes
256.400 + in the given list. Put them into (nhdsze, nbrhd). deg0 contains
256.401 + the number of nodes in the list. */
256.402 + if (nlist <= 0) return;
256.403 + deg0 = 0;
256.404 + nhdsze = 0;
256.405 + for (il = 1; il <= nlist; il++)
256.406 + { node = list[il];
256.407 + deg0 += qsize[node];
256.408 + jstrt = xadj[node];
256.409 + jstop = xadj[node+1] - 1;
256.410 + for (j = jstrt; j <= jstop; j++)
256.411 + { nabor = adjncy[j];
256.412 + if (marker[nabor] == 0 && deg[nabor] < 0)
256.413 + { marker[nabor] = -1;
256.414 + nhdsze++;
256.415 + nbrhd[nhdsze] = nabor;
256.416 + }
256.417 + }
256.418 + }
256.419 + /* Merge indistinguishable nodes in the list by calling the
256.420 + subroutine qmdmrg. */
256.421 + if (nhdsze > 0)
256.422 + qmdmrg(xadj, adjncy, deg, qsize, qlink, marker, °0, &nhdsze,
256.423 + nbrhd, rchset, &nbrhd[nhdsze+1]);
256.424 + /* Find the new degrees of the nodes that have not been merged. */
256.425 + for (il = 1; il <= nlist; il++)
256.426 + { node = list[il];
256.427 + mark = marker[node];
256.428 + if (mark == 0 || mark == 1)
256.429 + { marker[node] = 2;
256.430 + qmdrch(&node, xadj, adjncy, deg, marker, &rchsze, rchset,
256.431 + &nhdsze, nbrhd);
256.432 + deg1 = deg0;
256.433 + if (rchsze > 0)
256.434 + { for (irch = 1; irch <= rchsze; irch++)
256.435 + { inode = rchset[irch];
256.436 + deg1 += qsize[inode];
256.437 + marker[inode] = 0;
256.438 + }
256.439 + }
256.440 + deg[node] = deg1 - 1;
256.441 + if (nhdsze > 0)
256.442 + { for (inhd = 1; inhd <= nhdsze; inhd++)
256.443 + { inode = nbrhd[inhd];
256.444 + marker[inode] = 0;
256.445 + }
256.446 + }
256.447 + }
256.448 + }
256.449 + return;
256.450 +# undef nlist
256.451 +}
256.452 +
256.453 +/***********************************************************************
256.454 +* NAME
256.455 +*
256.456 +* qmdmrg - Quotient MD MeRGe
256.457 +*
256.458 +* SYNOPSIS
256.459 +*
256.460 +* #include "qmdmrg.h"
256.461 +* void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[],
256.462 +* int qlink[], int marker[], int *deg0, int *nhdsze, int nbrhd[],
256.463 +* int rchset[], int ovrlp[]);
256.464 +*
256.465 +* PURPOSE
256.466 +*
256.467 +* This routine merges indistinguishable nodes in the minimum degree
256.468 +* ordering algorithm. It also computes the new degrees of these new
256.469 +* supernodes.
256.470 +*
256.471 +* INPUT PARAMETERS
256.472 +*
256.473 +* (xadj, adjncy) -
256.474 +* the adjancy structure;
256.475 +* deg0 - the number of nodes in the given set;
256.476 +* (nhdsze, nbrhd) -
256.477 +* the set of eliminated supernodes adjacent to some nodes in
256.478 +* the set.
256.479 +*
256.480 +* UPDATED PARAMETERS
256.481 +*
256.482 +* deg - the degree vector;
256.483 +* qsize - size of indistinguishable nodes;
256.484 +* qlink - linked list for indistinguishable nodes;
256.485 +* marker - the given set is given by those nodes with marker value set
256.486 +* to 1. Those nodes with degree updated will have marker value
256.487 +* set to 2.
256.488 +*
256.489 +* WORKING PARAMETERS
256.490 +*
256.491 +* rchset - the reachable set;
256.492 +* ovrlp - temp vector to store the intersection of two reachable sets.
256.493 +***********************************************************************/
256.494 +
256.495 +void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[],
256.496 + int qlink[], int marker[], int *_deg0, int *_nhdsze, int nbrhd[],
256.497 + int rchset[], int ovrlp[])
256.498 +{ int deg1, head, inhd, iov, irch, j, jstop, jstrt, link, lnode,
256.499 + mark, mrgsze, nabor, node, novrlp, rchsze, root;
256.500 +# define deg0 (*_deg0)
256.501 +# define nhdsze (*_nhdsze)
256.502 + /* Initialization. */
256.503 + if (nhdsze <= 0) return;
256.504 + for (inhd = 1; inhd <= nhdsze; inhd++)
256.505 + { root = nbrhd[inhd];
256.506 + marker[root] = 0;
256.507 + }
256.508 + /* Loop through each eliminated supernode in the set
256.509 + (nhdsze, nbrhd). */
256.510 + for (inhd = 1; inhd <= nhdsze; inhd++)
256.511 + { root = nbrhd[inhd];
256.512 + marker[root] = -1;
256.513 + rchsze = 0;
256.514 + novrlp = 0;
256.515 + deg1 = 0;
256.516 +s200: jstrt = xadj[root];
256.517 + jstop = xadj[root+1] - 1;
256.518 + /* Determine the reachable set and its intersection with the
256.519 + input reachable set. */
256.520 + for (j = jstrt; j <= jstop; j++)
256.521 + { nabor = adjncy[j];
256.522 + root = - nabor;
256.523 + if (nabor < 0) goto s200;
256.524 + if (nabor == 0) break;
256.525 + mark = marker[nabor];
256.526 + if (mark == 0)
256.527 + { rchsze++;
256.528 + rchset[rchsze] = nabor;
256.529 + deg1 += qsize[nabor];
256.530 + marker[nabor] = 1;
256.531 + }
256.532 + else if (mark == 1)
256.533 + { novrlp++;
256.534 + ovrlp[novrlp] = nabor;
256.535 + marker[nabor] = 2;
256.536 + }
256.537 + }
256.538 + /* From the overlapped set, determine the nodes that can be
256.539 + merged together. */
256.540 + head = 0;
256.541 + mrgsze = 0;
256.542 + for (iov = 1; iov <= novrlp; iov++)
256.543 + { node = ovrlp[iov];
256.544 + jstrt = xadj[node];
256.545 + jstop = xadj[node+1] - 1;
256.546 + for (j = jstrt; j <= jstop; j++)
256.547 + { nabor = adjncy[j];
256.548 + if (marker[nabor] == 0)
256.549 + { marker[node] = 1;
256.550 + goto s1100;
256.551 + }
256.552 + }
256.553 + /* Node belongs to the new merged supernode. Update the
256.554 + vectors qlink and qsize. */
256.555 + mrgsze += qsize[node];
256.556 + marker[node] = -1;
256.557 + lnode = node;
256.558 +s900: link = qlink[lnode];
256.559 + if (link > 0)
256.560 + { lnode = link;
256.561 + goto s900;
256.562 + }
256.563 + qlink[lnode] = head;
256.564 + head = node;
256.565 +s1100: ;
256.566 + }
256.567 + if (head > 0)
256.568 + { qsize[head] = mrgsze;
256.569 + deg[head] = deg0 + deg1 - 1;
256.570 + marker[head] = 2;
256.571 + }
256.572 + /* Reset marker values. */
256.573 + root = nbrhd[inhd];
256.574 + marker[root] = 0;
256.575 + if (rchsze > 0)
256.576 + { for (irch = 1; irch <= rchsze; irch++)
256.577 + { node = rchset[irch];
256.578 + marker[node] = 0;
256.579 + }
256.580 + }
256.581 + }
256.582 + return;
256.583 +# undef deg0
256.584 +# undef nhdsze
256.585 +}
256.586 +
256.587 +/* eof */
257.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
257.2 +++ b/src/glpqmd.h Mon Dec 06 13:09:21 2010 +0100
257.3 @@ -0,0 +1,59 @@
257.4 +/* glpqmd.h (quotient minimum degree algorithm) */
257.5 +
257.6 +/***********************************************************************
257.7 +* This code is part of GLPK (GNU Linear Programming Kit).
257.8 +*
257.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
257.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
257.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
257.12 +* E-mail: <mao@gnu.org>.
257.13 +*
257.14 +* GLPK is free software: you can redistribute it and/or modify it
257.15 +* under the terms of the GNU General Public License as published by
257.16 +* the Free Software Foundation, either version 3 of the License, or
257.17 +* (at your option) any later version.
257.18 +*
257.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
257.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
257.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
257.22 +* License for more details.
257.23 +*
257.24 +* You should have received a copy of the GNU General Public License
257.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
257.26 +***********************************************************************/
257.27 +
257.28 +#ifndef GLPQMD_H
257.29 +#define GLPQMD_H
257.30 +
257.31 +#define genqmd _glp_qmd_genqmd
257.32 +void genqmd(int *neqns, int xadj[], int adjncy[], int perm[],
257.33 + int invp[], int deg[], int marker[], int rchset[], int nbrhd[],
257.34 + int qsize[], int qlink[], int *nofsub);
257.35 +/* GENeral Quotient Minimum Degree algorithm */
257.36 +
257.37 +#define qmdrch _glp_qmd_qmdrch
257.38 +void qmdrch(int *root, int xadj[], int adjncy[], int deg[],
257.39 + int marker[], int *rchsze, int rchset[], int *nhdsze,
257.40 + int nbrhd[]);
257.41 +/* Quotient MD ReaCHable set */
257.42 +
257.43 +#define qmdqt _glp_qmd_qmdqt
257.44 +void qmdqt(int *root, int xadj[], int adjncy[], int marker[],
257.45 + int *rchsze, int rchset[], int nbrhd[]);
257.46 +/* Quotient MD Quotient graph Transformation */
257.47 +
257.48 +#define qmdupd _glp_qmd_qmdupd
257.49 +void qmdupd(int xadj[], int adjncy[], int *nlist, int list[],
257.50 + int deg[], int qsize[], int qlink[], int marker[], int rchset[],
257.51 + int nbrhd[]);
257.52 +/* Quotient MD UPDate */
257.53 +
257.54 +#define qmdmrg _glp_qmd_qmdmrg
257.55 +void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[],
257.56 + int qlink[], int marker[], int *deg0, int *nhdsze, int nbrhd[],
257.57 + int rchset[], int ovrlp[]);
257.58 +/* Quotient MD MeRGe */
257.59 +
257.60 +#endif
257.61 +
257.62 +/* eof */
258.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
258.2 +++ b/src/glprgr.c Mon Dec 06 13:09:21 2010 +0100
258.3 @@ -0,0 +1,165 @@
258.4 +/* glprgr.c */
258.5 +
258.6 +/***********************************************************************
258.7 +* This code is part of GLPK (GNU Linear Programming Kit).
258.8 +*
258.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
258.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
258.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
258.12 +* E-mail: <mao@gnu.org>.
258.13 +*
258.14 +* GLPK is free software: you can redistribute it and/or modify it
258.15 +* under the terms of the GNU General Public License as published by
258.16 +* the Free Software Foundation, either version 3 of the License, or
258.17 +* (at your option) any later version.
258.18 +*
258.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
258.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
258.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
258.22 +* License for more details.
258.23 +*
258.24 +* You should have received a copy of the GNU General Public License
258.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
258.26 +***********************************************************************/
258.27 +
258.28 +#define _GLPSTD_ERRNO
258.29 +#define _GLPSTD_STDIO
258.30 +#include "glpenv.h"
258.31 +#include "glprgr.h"
258.32 +#define xfault xerror
258.33 +
258.34 +/***********************************************************************
258.35 +* NAME
258.36 +*
258.37 +* rgr_write_bmp16 - write 16-color raster image in BMP file format
258.38 +*
258.39 +* SYNOPSIS
258.40 +*
258.41 +* #include "glprgr.h"
258.42 +* int rgr_write_bmp16(const char *fname, int m, int n, const char
258.43 +* map[]);
258.44 +*
258.45 +* DESCRIPTION
258.46 +*
258.47 +* The routine rgr_write_bmp16 writes 16-color raster image in
258.48 +* uncompressed BMP file format (Windows bitmap) to a binary file whose
258.49 +* name is specified by the character string fname.
258.50 +*
258.51 +* The parameters m and n specify, respectively, the number of rows and
258.52 +* the numbers of columns (i.e. height and width) of the raster image.
258.53 +*
258.54 +* The character array map has m*n elements. Elements map[0, ..., n-1]
258.55 +* correspond to the first (top) scanline, elements map[n, ..., 2*n-1]
258.56 +* correspond to the second scanline, etc.
258.57 +*
258.58 +* Each element of the array map specifies a color of the corresponding
258.59 +* pixel as 8-bit binary number XXXXIRGB, where four high-order bits (X)
258.60 +* are ignored, I is high intensity bit, R is red color bit, G is green
258.61 +* color bit, and B is blue color bit. Thus, all 16 possible colors are
258.62 +* coded as following hexadecimal numbers:
258.63 +*
258.64 +* 0x00 = black 0x08 = dark gray
258.65 +* 0x01 = blue 0x09 = bright blue
258.66 +* 0x02 = green 0x0A = bright green
258.67 +* 0x03 = cyan 0x0B = bright cyan
258.68 +* 0x04 = red 0x0C = bright red
258.69 +* 0x05 = magenta 0x0D = bright magenta
258.70 +* 0x06 = brown 0x0E = yellow
258.71 +* 0x07 = light gray 0x0F = white
258.72 +*
258.73 +* RETURNS
258.74 +*
258.75 +* If no error occured, the routine returns zero; otherwise, it prints
258.76 +* an appropriate error message and returns non-zero. */
258.77 +
258.78 +static void put_byte(FILE *fp, int c)
258.79 +{ fputc(c, fp);
258.80 + return;
258.81 +}
258.82 +
258.83 +static void put_word(FILE *fp, int w)
258.84 +{ /* big endian */
258.85 + put_byte(fp, w);
258.86 + put_byte(fp, w >> 8);
258.87 + return;
258.88 +}
258.89 +
258.90 +static void put_dword(FILE *fp, int d)
258.91 +{ /* big endian */
258.92 + put_word(fp, d);
258.93 + put_word(fp, d >> 16);
258.94 + return;
258.95 +}
258.96 +
258.97 +int rgr_write_bmp16(const char *fname, int m, int n, const char map[])
258.98 +{ FILE *fp;
258.99 + int offset, bmsize, i, j, b, ret = 0;
258.100 + if (!(1 <= m && m <= 32767))
258.101 + xfault("rgr_write_bmp16: m = %d; invalid height\n", m);
258.102 + if (!(1 <= n && n <= 32767))
258.103 + xfault("rgr_write_bmp16: n = %d; invalid width\n", n);
258.104 + fp = fopen(fname, "wb");
258.105 + if (fp == NULL)
258.106 + { xprintf("rgr_write_bmp16: unable to create `%s' - %s\n",
258.107 + fname, strerror(errno));
258.108 + ret = 1;
258.109 + goto fini;
258.110 + }
258.111 + offset = 14 + 40 + 16 * 4;
258.112 + bmsize = (4 * n + 31) / 32;
258.113 + /* struct BMPFILEHEADER (14 bytes) */
258.114 + /* UINT bfType */ put_byte(fp, 'B'), put_byte(fp, 'M');
258.115 + /* DWORD bfSize */ put_dword(fp, offset + bmsize * 4);
258.116 + /* UINT bfReserved1 */ put_word(fp, 0);
258.117 + /* UNIT bfReserved2 */ put_word(fp, 0);
258.118 + /* DWORD bfOffBits */ put_dword(fp, offset);
258.119 + /* struct BMPINFOHEADER (40 bytes) */
258.120 + /* DWORD biSize */ put_dword(fp, 40);
258.121 + /* LONG biWidth */ put_dword(fp, n);
258.122 + /* LONG biHeight */ put_dword(fp, m);
258.123 + /* WORD biPlanes */ put_word(fp, 1);
258.124 + /* WORD biBitCount */ put_word(fp, 4);
258.125 + /* DWORD biCompression */ put_dword(fp, 0 /* BI_RGB */);
258.126 + /* DWORD biSizeImage */ put_dword(fp, 0);
258.127 + /* LONG biXPelsPerMeter */ put_dword(fp, 2953 /* 75 dpi */);
258.128 + /* LONG biYPelsPerMeter */ put_dword(fp, 2953 /* 75 dpi */);
258.129 + /* DWORD biClrUsed */ put_dword(fp, 0);
258.130 + /* DWORD biClrImportant */ put_dword(fp, 0);
258.131 + /* struct RGBQUAD (16 * 4 = 64 bytes) */
258.132 + /* CGA-compatible colors: */
258.133 + /* 0x00 = black */ put_dword(fp, 0x000000);
258.134 + /* 0x01 = blue */ put_dword(fp, 0x000080);
258.135 + /* 0x02 = green */ put_dword(fp, 0x008000);
258.136 + /* 0x03 = cyan */ put_dword(fp, 0x008080);
258.137 + /* 0x04 = red */ put_dword(fp, 0x800000);
258.138 + /* 0x05 = magenta */ put_dword(fp, 0x800080);
258.139 + /* 0x06 = brown */ put_dword(fp, 0x808000);
258.140 + /* 0x07 = light gray */ put_dword(fp, 0xC0C0C0);
258.141 + /* 0x08 = dark gray */ put_dword(fp, 0x808080);
258.142 + /* 0x09 = bright blue */ put_dword(fp, 0x0000FF);
258.143 + /* 0x0A = bright green */ put_dword(fp, 0x00FF00);
258.144 + /* 0x0B = bright cyan */ put_dword(fp, 0x00FFFF);
258.145 + /* 0x0C = bright red */ put_dword(fp, 0xFF0000);
258.146 + /* 0x0D = bright magenta */ put_dword(fp, 0xFF00FF);
258.147 + /* 0x0E = yellow */ put_dword(fp, 0xFFFF00);
258.148 + /* 0x0F = white */ put_dword(fp, 0xFFFFFF);
258.149 + /* pixel data bits */
258.150 + b = 0;
258.151 + for (i = m - 1; i >= 0; i--)
258.152 + { for (j = 0; j < ((n + 7) / 8) * 8; j++)
258.153 + { b <<= 4;
258.154 + b |= (j < n ? map[i * n + j] & 15 : 0);
258.155 + if (j & 1) put_byte(fp, b);
258.156 + }
258.157 + }
258.158 + fflush(fp);
258.159 + if (ferror(fp))
258.160 + { xprintf("rgr_write_bmp16: write error on `%s' - %s\n",
258.161 + fname, strerror(errno));
258.162 + ret = 1;
258.163 + }
258.164 +fini: if (fp != NULL) fclose(fp);
258.165 + return ret;
258.166 +}
258.167 +
258.168 +/* eof */
259.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
259.2 +++ b/src/glprgr.h Mon Dec 06 13:09:21 2010 +0100
259.3 @@ -0,0 +1,34 @@
259.4 +/* glprgr.h (raster graphics) */
259.5 +
259.6 +/***********************************************************************
259.7 +* This code is part of GLPK (GNU Linear Programming Kit).
259.8 +*
259.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
259.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
259.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
259.12 +* E-mail: <mao@gnu.org>.
259.13 +*
259.14 +* GLPK is free software: you can redistribute it and/or modify it
259.15 +* under the terms of the GNU General Public License as published by
259.16 +* the Free Software Foundation, either version 3 of the License, or
259.17 +* (at your option) any later version.
259.18 +*
259.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
259.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
259.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
259.22 +* License for more details.
259.23 +*
259.24 +* You should have received a copy of the GNU General Public License
259.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
259.26 +***********************************************************************/
259.27 +
259.28 +#ifndef GLPRGR_H
259.29 +#define GLPRGR_H
259.30 +
259.31 +#define rgr_write_bmp16 _glp_rgr_write_bmp16
259.32 +int rgr_write_bmp16(const char *fname, int m, int n, const char map[]);
259.33 +/* write 16-color raster image in BMP file format */
259.34 +
259.35 +#endif
259.36 +
259.37 +/* eof */
260.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
260.2 +++ b/src/glprng.h Mon Dec 06 13:09:21 2010 +0100
260.3 @@ -0,0 +1,68 @@
260.4 +/* glprng.h (pseudo-random number generator) */
260.5 +
260.6 +/***********************************************************************
260.7 +* This code is part of GLPK (GNU Linear Programming Kit).
260.8 +*
260.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
260.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
260.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
260.12 +* E-mail: <mao@gnu.org>.
260.13 +*
260.14 +* GLPK is free software: you can redistribute it and/or modify it
260.15 +* under the terms of the GNU General Public License as published by
260.16 +* the Free Software Foundation, either version 3 of the License, or
260.17 +* (at your option) any later version.
260.18 +*
260.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
260.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
260.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
260.22 +* License for more details.
260.23 +*
260.24 +* You should have received a copy of the GNU General Public License
260.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
260.26 +***********************************************************************/
260.27 +
260.28 +#ifndef GLPRNG_H
260.29 +#define GLPRNG_H
260.30 +
260.31 +typedef struct RNG RNG;
260.32 +
260.33 +struct RNG
260.34 +{ /* Knuth's portable pseudo-random number generator */
260.35 + int A[56];
260.36 + /* pseudo-random values */
260.37 + int *fptr;
260.38 + /* the next A value to be exported */
260.39 +};
260.40 +
260.41 +#define rng_create_rand _glp_rng_create_rand
260.42 +RNG *rng_create_rand(void);
260.43 +/* create pseudo-random number generator */
260.44 +
260.45 +#define rng_init_rand _glp_rng_init_rand
260.46 +void rng_init_rand(RNG *rand, int seed);
260.47 +/* initialize pseudo-random number generator */
260.48 +
260.49 +#define rng_next_rand _glp_rng_next_rand
260.50 +int rng_next_rand(RNG *rand);
260.51 +/* obtain pseudo-random integer in the range [0, 2^31-1] */
260.52 +
260.53 +#define rng_unif_rand _glp_rng_unif_rand
260.54 +int rng_unif_rand(RNG *rand, int m);
260.55 +/* obtain pseudo-random integer in the range [0, m-1] */
260.56 +
260.57 +#define rng_delete_rand _glp_rng_delete_rand
260.58 +void rng_delete_rand(RNG *rand);
260.59 +/* delete pseudo-random number generator */
260.60 +
260.61 +#define rng_unif_01 _glp_rng_unif_01
260.62 +double rng_unif_01(RNG *rand);
260.63 +/* obtain pseudo-random number in the range [0, 1] */
260.64 +
260.65 +#define rng_uniform _glp_rng_uniform
260.66 +double rng_uniform(RNG *rand, double a, double b);
260.67 +/* obtain pseudo-random number in the range [a, b] */
260.68 +
260.69 +#endif
260.70 +
260.71 +/* eof */
261.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
261.2 +++ b/src/glprng01.c Mon Dec 06 13:09:21 2010 +0100
261.3 @@ -0,0 +1,227 @@
261.4 +/* glprng01.c */
261.5 +
261.6 +/***********************************************************************
261.7 +* This code is part of GLPK (GNU Linear Programming Kit).
261.8 +*
261.9 +* This code is a modified version of the module GB_FLIP, a portable
261.10 +* pseudo-random number generator. The original version of GB_FLIP is
261.11 +* a part of The Stanford GraphBase developed by Donald E. Knuth (see
261.12 +* http://www-cs-staff.stanford.edu/~knuth/sgb.html).
261.13 +*
261.14 +* Note that all changes concern only external names, so this modified
261.15 +* version produces exactly the same results as the original version.
261.16 +*
261.17 +* Changes were made by Andrew Makhorin <mao@gnu.org>.
261.18 +*
261.19 +* GLPK is free software: you can redistribute it and/or modify it
261.20 +* under the terms of the GNU General Public License as published by
261.21 +* the Free Software Foundation, either version 3 of the License, or
261.22 +* (at your option) any later version.
261.23 +*
261.24 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
261.25 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
261.26 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
261.27 +* License for more details.
261.28 +*
261.29 +* You should have received a copy of the GNU General Public License
261.30 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
261.31 +***********************************************************************/
261.32 +
261.33 +#include "glpenv.h"
261.34 +#include "glprng.h"
261.35 +
261.36 +#if 0
261.37 +int A[56] = { -1 };
261.38 +#else
261.39 +#define A (rand->A)
261.40 +#endif
261.41 +/* pseudo-random values */
261.42 +
261.43 +#if 0
261.44 +int *fptr = A;
261.45 +#else
261.46 +#define fptr (rand->fptr)
261.47 +#endif
261.48 +/* the next A value to be exported */
261.49 +
261.50 +#define mod_diff(x, y) (((x) - (y)) & 0x7FFFFFFF)
261.51 +/* difference modulo 2^31 */
261.52 +
261.53 +static int flip_cycle(RNG *rand)
261.54 +{ /* this is an auxiliary routine to do 55 more steps of the basic
261.55 + recurrence, at high speed, and to reset fptr */
261.56 + int *ii, *jj;
261.57 + for (ii = &A[1], jj = &A[32]; jj <= &A[55]; ii++, jj++)
261.58 + *ii = mod_diff(*ii, *jj);
261.59 + for (jj = &A[1]; ii <= &A[55]; ii++, jj++)
261.60 + *ii = mod_diff(*ii, *jj);
261.61 + fptr = &A[54];
261.62 + return A[55];
261.63 +}
261.64 +
261.65 +/***********************************************************************
261.66 +* NAME
261.67 +*
261.68 +* rng_create_rand - create pseudo-random number generator
261.69 +*
261.70 +* SYNOPSIS
261.71 +*
261.72 +* #include "glprng.h"
261.73 +* RNG *rng_create_rand(void);
261.74 +*
261.75 +* DESCRIPTION
261.76 +*
261.77 +* The routine rng_create_rand creates and initializes a pseudo-random
261.78 +* number generator.
261.79 +*
261.80 +* RETURNS
261.81 +*
261.82 +* The routine returns a pointer to the generator created. */
261.83 +
261.84 +RNG *rng_create_rand(void)
261.85 +{ RNG *rand;
261.86 + int i;
261.87 + rand = xmalloc(sizeof(RNG));
261.88 + A[0] = -1;
261.89 + for (i = 1; i <= 55; i++) A[i] = 0;
261.90 + fptr = A;
261.91 + rng_init_rand(rand, 1);
261.92 + return rand;
261.93 +}
261.94 +
261.95 +/***********************************************************************
261.96 +* NAME
261.97 +*
261.98 +* rng_init_rand - initialize pseudo-random number generator
261.99 +*
261.100 +* SYNOPSIS
261.101 +*
261.102 +* #include "glprng.h"
261.103 +* void rng_init_rand(RNG *rand, int seed);
261.104 +*
261.105 +* DESCRIPTION
261.106 +*
261.107 +* The routine rng_init_rand initializes the pseudo-random number
261.108 +* generator. The parameter seed may be any integer number. Note that
261.109 +* on creating the generator this routine is called with the parameter
261.110 +* seed equal to 1. */
261.111 +
261.112 +void rng_init_rand(RNG *rand, int seed)
261.113 +{ int i;
261.114 + int prev = seed, next = 1;
261.115 + seed = prev = mod_diff(prev, 0);
261.116 + A[55] = prev;
261.117 + for (i = 21; i; i = (i + 21) % 55)
261.118 + { A[i] = next;
261.119 + next = mod_diff(prev, next);
261.120 + if (seed & 1)
261.121 + seed = 0x40000000 + (seed >> 1);
261.122 + else
261.123 + seed >>= 1;
261.124 + next = mod_diff(next, seed);
261.125 + prev = A[i];
261.126 + }
261.127 + flip_cycle(rand);
261.128 + flip_cycle(rand);
261.129 + flip_cycle(rand);
261.130 + flip_cycle(rand);
261.131 + flip_cycle(rand);
261.132 + return;
261.133 +}
261.134 +
261.135 +/***********************************************************************
261.136 +* NAME
261.137 +*
261.138 +* rng_next_rand - obtain pseudo-random integer in the range [0, 2^31-1]
261.139 +*
261.140 +* SYNOPSIS
261.141 +*
261.142 +* #include "glprng.h"
261.143 +* int rng_next_rand(RNG *rand);
261.144 +*
261.145 +* RETURNS
261.146 +*
261.147 +* The routine rng_next_rand returns a next pseudo-random integer which
261.148 +* is uniformly distributed between 0 and 2^31-1, inclusive. The period
261.149 +* length of the generated numbers is 2^85 - 2^30. The low order bits of
261.150 +* the generated numbers are just as random as the high-order bits. */
261.151 +
261.152 +int rng_next_rand(RNG *rand)
261.153 +{ return
261.154 + *fptr >= 0 ? *fptr-- : flip_cycle(rand);
261.155 +}
261.156 +
261.157 +/***********************************************************************
261.158 +* NAME
261.159 +*
261.160 +* rng_unif_rand - obtain pseudo-random integer in the range [0, m-1]
261.161 +*
261.162 +* SYNOPSIS
261.163 +*
261.164 +* #include "glprng.h"
261.165 +* int rng_unif_rand(RNG *rand, int m);
261.166 +*
261.167 +* RETURNS
261.168 +*
261.169 +* The routine rng_unif_rand returns a next pseudo-random integer which
261.170 +* is uniformly distributed between 0 and m-1, inclusive, where m is any
261.171 +* positive integer less than 2^31. */
261.172 +
261.173 +#define two_to_the_31 ((unsigned int)0x80000000)
261.174 +
261.175 +int rng_unif_rand(RNG *rand, int m)
261.176 +{ unsigned int t = two_to_the_31 - (two_to_the_31 % m);
261.177 + int r;
261.178 + xassert(m > 0);
261.179 + do { r = rng_next_rand(rand); } while (t <= (unsigned int)r);
261.180 + return r % m;
261.181 +}
261.182 +
261.183 +/***********************************************************************
261.184 +* NAME
261.185 +*
261.186 +* rng_delete_rand - delete pseudo-random number generator
261.187 +*
261.188 +* SYNOPSIS
261.189 +*
261.190 +* #include "glprng.h"
261.191 +* void rng_delete_rand(RNG *rand);
261.192 +*
261.193 +* DESCRIPTION
261.194 +*
261.195 +* The routine rng_delete_rand frees all the memory allocated to the
261.196 +* specified pseudo-random number generator. */
261.197 +
261.198 +void rng_delete_rand(RNG *rand)
261.199 +{ xfree(rand);
261.200 + return;
261.201 +}
261.202 +
261.203 +/**********************************************************************/
261.204 +
261.205 +#if 0
261.206 +/* To be sure that this modified version produces the same results as
261.207 + the original version, run this validation program. */
261.208 +
261.209 +int main(void)
261.210 +{ RNG *rand;
261.211 + int j;
261.212 + rand = rng_create_rand();
261.213 + rng_init_rand(rand, -314159);
261.214 + if (rng_next_rand(rand) != 119318998)
261.215 + { fprintf(stderr, "Failure on the first try!\n");
261.216 + return -1;
261.217 + }
261.218 + for (j = 1; j <= 133; j++) rng_next_rand(rand);
261.219 + if (rng_unif_rand(rand, 0x55555555) != 748103812)
261.220 + { fprintf(stderr, "Failure on the second try!\n");
261.221 + return -2;
261.222 + }
261.223 + fprintf(stderr, "OK, the random-number generator routines seem to"
261.224 + " work!\n");
261.225 + rng_delete_rand(rand);
261.226 + return 0;
261.227 +}
261.228 +#endif
261.229 +
261.230 +/* eof */
262.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
262.2 +++ b/src/glprng02.c Mon Dec 06 13:09:21 2010 +0100
262.3 @@ -0,0 +1,76 @@
262.4 +/* glprng02.c */
262.5 +
262.6 +/***********************************************************************
262.7 +* This code is part of GLPK (GNU Linear Programming Kit).
262.8 +*
262.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
262.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
262.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
262.12 +* E-mail: <mao@gnu.org>.
262.13 +*
262.14 +* GLPK is free software: you can redistribute it and/or modify it
262.15 +* under the terms of the GNU General Public License as published by
262.16 +* the Free Software Foundation, either version 3 of the License, or
262.17 +* (at your option) any later version.
262.18 +*
262.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
262.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
262.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
262.22 +* License for more details.
262.23 +*
262.24 +* You should have received a copy of the GNU General Public License
262.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
262.26 +***********************************************************************/
262.27 +
262.28 +#include "glpenv.h"
262.29 +#include "glprng.h"
262.30 +#define xfault xerror
262.31 +
262.32 +/***********************************************************************
262.33 +* NAME
262.34 +*
262.35 +* rng_unif_01 - obtain pseudo-random number in the range [0, 1]
262.36 +*
262.37 +* SYNOPSIS
262.38 +*
262.39 +* #include "glprng.h"
262.40 +* double rng_unif_01(RNG *rand);
262.41 +*
262.42 +* RETURNS
262.43 +*
262.44 +* The routine rng_unif_01 returns a next pseudo-random number which is
262.45 +* uniformly distributed in the range [0, 1]. */
262.46 +
262.47 +double rng_unif_01(RNG *rand)
262.48 +{ double x;
262.49 + x = (double)rng_next_rand(rand) / 2147483647.0;
262.50 + xassert(0.0 <= x && x <= 1.0);
262.51 + return x;
262.52 +}
262.53 +
262.54 +/***********************************************************************
262.55 +* NAME
262.56 +*
262.57 +* rng_uniform - obtain pseudo-random number in the range [a, b]
262.58 +*
262.59 +* SYNOPSIS
262.60 +*
262.61 +* #include "glprng.h"
262.62 +* double rng_uniform(RNG *rand, double a, double b);
262.63 +*
262.64 +* RETURNS
262.65 +*
262.66 +* The routine rng_uniform returns a next pseudo-random number which is
262.67 +* uniformly distributed in the range [a, b]. */
262.68 +
262.69 +double rng_uniform(RNG *rand, double a, double b)
262.70 +{ double x;
262.71 + if (a >= b)
262.72 + xfault("rng_uniform: a = %g, b = %g; invalid range\n", a, b);
262.73 + x = rng_unif_01(rand);
262.74 + x = a * (1.0 - x) + b * x;
262.75 + xassert(a <= x && x <= b);
262.76 + return x;
262.77 +}
262.78 +
262.79 +/* eof */
263.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
263.2 +++ b/src/glpscf.c Mon Dec 06 13:09:21 2010 +0100
263.3 @@ -0,0 +1,634 @@
263.4 +/* glpscf.c (Schur complement factorization) */
263.5 +
263.6 +/***********************************************************************
263.7 +* This code is part of GLPK (GNU Linear Programming Kit).
263.8 +*
263.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
263.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
263.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
263.12 +* E-mail: <mao@gnu.org>.
263.13 +*
263.14 +* GLPK is free software: you can redistribute it and/or modify it
263.15 +* under the terms of the GNU General Public License as published by
263.16 +* the Free Software Foundation, either version 3 of the License, or
263.17 +* (at your option) any later version.
263.18 +*
263.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
263.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
263.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
263.22 +* License for more details.
263.23 +*
263.24 +* You should have received a copy of the GNU General Public License
263.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
263.26 +***********************************************************************/
263.27 +
263.28 +#include "glpenv.h"
263.29 +#include "glpscf.h"
263.30 +#define xfault xerror
263.31 +
263.32 +#define _GLPSCF_DEBUG 0
263.33 +
263.34 +#define eps 1e-10
263.35 +
263.36 +/***********************************************************************
263.37 +* NAME
263.38 +*
263.39 +* scf_create_it - create Schur complement factorization
263.40 +*
263.41 +* SYNOPSIS
263.42 +*
263.43 +* #include "glpscf.h"
263.44 +* SCF *scf_create_it(int n_max);
263.45 +*
263.46 +* DESCRIPTION
263.47 +*
263.48 +* The routine scf_create_it creates the factorization of matrix C,
263.49 +* which initially has no rows and columns.
263.50 +*
263.51 +* The parameter n_max specifies the maximal order of matrix C to be
263.52 +* factorized, 1 <= n_max <= 32767.
263.53 +*
263.54 +* RETURNS
263.55 +*
263.56 +* The routine scf_create_it returns a pointer to the structure SCF,
263.57 +* which defines the factorization. */
263.58 +
263.59 +SCF *scf_create_it(int n_max)
263.60 +{ SCF *scf;
263.61 +#if _GLPSCF_DEBUG
263.62 + xprintf("scf_create_it: warning: debug mode enabled\n");
263.63 +#endif
263.64 + if (!(1 <= n_max && n_max <= 32767))
263.65 + xfault("scf_create_it: n_max = %d; invalid parameter\n",
263.66 + n_max);
263.67 + scf = xmalloc(sizeof(SCF));
263.68 + scf->n_max = n_max;
263.69 + scf->n = 0;
263.70 + scf->f = xcalloc(1 + n_max * n_max, sizeof(double));
263.71 + scf->u = xcalloc(1 + n_max * (n_max + 1) / 2, sizeof(double));
263.72 + scf->p = xcalloc(1 + n_max, sizeof(int));
263.73 + scf->t_opt = SCF_TBG;
263.74 + scf->rank = 0;
263.75 +#if _GLPSCF_DEBUG
263.76 + scf->c = xcalloc(1 + n_max * n_max, sizeof(double));
263.77 +#else
263.78 + scf->c = NULL;
263.79 +#endif
263.80 + scf->w = xcalloc(1 + n_max, sizeof(double));
263.81 + return scf;
263.82 +}
263.83 +
263.84 +/***********************************************************************
263.85 +* The routine f_loc determines location of matrix element F[i,j] in
263.86 +* the one-dimensional array f. */
263.87 +
263.88 +static int f_loc(SCF *scf, int i, int j)
263.89 +{ int n_max = scf->n_max;
263.90 + int n = scf->n;
263.91 + xassert(1 <= i && i <= n);
263.92 + xassert(1 <= j && j <= n);
263.93 + return (i - 1) * n_max + j;
263.94 +}
263.95 +
263.96 +/***********************************************************************
263.97 +* The routine u_loc determines location of matrix element U[i,j] in
263.98 +* the one-dimensional array u. */
263.99 +
263.100 +static int u_loc(SCF *scf, int i, int j)
263.101 +{ int n_max = scf->n_max;
263.102 + int n = scf->n;
263.103 + xassert(1 <= i && i <= n);
263.104 + xassert(i <= j && j <= n);
263.105 + return (i - 1) * n_max + j - i * (i - 1) / 2;
263.106 +}
263.107 +
263.108 +/***********************************************************************
263.109 +* The routine bg_transform applies Bartels-Golub version of gaussian
263.110 +* elimination to restore triangular structure of matrix U.
263.111 +*
263.112 +* On entry matrix U has the following structure:
263.113 +*
263.114 +* 1 k n
263.115 +* 1 * * * * * * * * * *
263.116 +* . * * * * * * * * *
263.117 +* . . * * * * * * * *
263.118 +* . . . * * * * * * *
263.119 +* k . . . . * * * * * *
263.120 +* . . . . . * * * * *
263.121 +* . . . . . . * * * *
263.122 +* . . . . . . . * * *
263.123 +* . . . . . . . . * *
263.124 +* n . . . . # # # # # #
263.125 +*
263.126 +* where '#' is a row spike to be eliminated.
263.127 +*
263.128 +* Elements of n-th row are passed separately in locations un[k], ...,
263.129 +* un[n]. On exit the content of the array un is destroyed.
263.130 +*
263.131 +* REFERENCES
263.132 +*
263.133 +* R.H.Bartels, G.H.Golub, "The Simplex Method of Linear Programming
263.134 +* Using LU-decomposition", Comm. ACM, 12, pp. 266-68, 1969. */
263.135 +
263.136 +static void bg_transform(SCF *scf, int k, double un[])
263.137 +{ int n = scf->n;
263.138 + double *f = scf->f;
263.139 + double *u = scf->u;
263.140 + int j, k1, kj, kk, n1, nj;
263.141 + double t;
263.142 + xassert(1 <= k && k <= n);
263.143 + /* main elimination loop */
263.144 + for (k = k; k < n; k++)
263.145 + { /* determine location of U[k,k] */
263.146 + kk = u_loc(scf, k, k);
263.147 + /* determine location of F[k,1] */
263.148 + k1 = f_loc(scf, k, 1);
263.149 + /* determine location of F[n,1] */
263.150 + n1 = f_loc(scf, n, 1);
263.151 + /* if |U[k,k]| < |U[n,k]|, interchange k-th and n-th rows to
263.152 + provide |U[k,k]| >= |U[n,k]| */
263.153 + if (fabs(u[kk]) < fabs(un[k]))
263.154 + { /* interchange k-th and n-th rows of matrix U */
263.155 + for (j = k, kj = kk; j <= n; j++, kj++)
263.156 + t = u[kj], u[kj] = un[j], un[j] = t;
263.157 + /* interchange k-th and n-th rows of matrix F to keep the
263.158 + main equality F * C = U * P */
263.159 + for (j = 1, kj = k1, nj = n1; j <= n; j++, kj++, nj++)
263.160 + t = f[kj], f[kj] = f[nj], f[nj] = t;
263.161 + }
263.162 + /* now |U[k,k]| >= |U[n,k]| */
263.163 + /* if U[k,k] is too small in the magnitude, replace U[k,k] and
263.164 + U[n,k] by exact zero */
263.165 + if (fabs(u[kk]) < eps) u[kk] = un[k] = 0.0;
263.166 + /* if U[n,k] is already zero, elimination is not needed */
263.167 + if (un[k] == 0.0) continue;
263.168 + /* compute gaussian multiplier t = U[n,k] / U[k,k] */
263.169 + t = un[k] / u[kk];
263.170 + /* apply gaussian elimination to nullify U[n,k] */
263.171 + /* (n-th row of U) := (n-th row of U) - t * (k-th row of U) */
263.172 + for (j = k+1, kj = kk+1; j <= n; j++, kj++)
263.173 + un[j] -= t * u[kj];
263.174 + /* (n-th row of F) := (n-th row of F) - t * (k-th row of F)
263.175 + to keep the main equality F * C = U * P */
263.176 + for (j = 1, kj = k1, nj = n1; j <= n; j++, kj++, nj++)
263.177 + f[nj] -= t * f[kj];
263.178 + }
263.179 + /* if U[n,n] is too small in the magnitude, replace it by exact
263.180 + zero */
263.181 + if (fabs(un[n]) < eps) un[n] = 0.0;
263.182 + /* store U[n,n] in a proper location */
263.183 + u[u_loc(scf, n, n)] = un[n];
263.184 + return;
263.185 +}
263.186 +
263.187 +/***********************************************************************
263.188 +* The routine givens computes the parameters of Givens plane rotation
263.189 +* c = cos(teta) and s = sin(teta) such that:
263.190 +*
263.191 +* ( c -s ) ( a ) ( r )
263.192 +* ( ) ( ) = ( ) ,
263.193 +* ( s c ) ( b ) ( 0 )
263.194 +*
263.195 +* where a and b are given scalars.
263.196 +*
263.197 +* REFERENCES
263.198 +*
263.199 +* G.H.Golub, C.F.Van Loan, "Matrix Computations", 2nd ed. */
263.200 +
263.201 +static void givens(double a, double b, double *c, double *s)
263.202 +{ double t;
263.203 + if (b == 0.0)
263.204 + (*c) = 1.0, (*s) = 0.0;
263.205 + else if (fabs(a) <= fabs(b))
263.206 + t = - a / b, (*s) = 1.0 / sqrt(1.0 + t * t), (*c) = (*s) * t;
263.207 + else
263.208 + t = - b / a, (*c) = 1.0 / sqrt(1.0 + t * t), (*s) = (*c) * t;
263.209 + return;
263.210 +}
263.211 +
263.212 +/*----------------------------------------------------------------------
263.213 +* The routine gr_transform applies Givens plane rotations to restore
263.214 +* triangular structure of matrix U.
263.215 +*
263.216 +* On entry matrix U has the following structure:
263.217 +*
263.218 +* 1 k n
263.219 +* 1 * * * * * * * * * *
263.220 +* . * * * * * * * * *
263.221 +* . . * * * * * * * *
263.222 +* . . . * * * * * * *
263.223 +* k . . . . * * * * * *
263.224 +* . . . . . * * * * *
263.225 +* . . . . . . * * * *
263.226 +* . . . . . . . * * *
263.227 +* . . . . . . . . * *
263.228 +* n . . . . # # # # # #
263.229 +*
263.230 +* where '#' is a row spike to be eliminated.
263.231 +*
263.232 +* Elements of n-th row are passed separately in locations un[k], ...,
263.233 +* un[n]. On exit the content of the array un is destroyed.
263.234 +*
263.235 +* REFERENCES
263.236 +*
263.237 +* R.H.Bartels, G.H.Golub, "The Simplex Method of Linear Programming
263.238 +* Using LU-decomposition", Comm. ACM, 12, pp. 266-68, 1969. */
263.239 +
263.240 +static void gr_transform(SCF *scf, int k, double un[])
263.241 +{ int n = scf->n;
263.242 + double *f = scf->f;
263.243 + double *u = scf->u;
263.244 + int j, k1, kj, kk, n1, nj;
263.245 + double c, s;
263.246 + xassert(1 <= k && k <= n);
263.247 + /* main elimination loop */
263.248 + for (k = k; k < n; k++)
263.249 + { /* determine location of U[k,k] */
263.250 + kk = u_loc(scf, k, k);
263.251 + /* determine location of F[k,1] */
263.252 + k1 = f_loc(scf, k, 1);
263.253 + /* determine location of F[n,1] */
263.254 + n1 = f_loc(scf, n, 1);
263.255 + /* if both U[k,k] and U[n,k] are too small in the magnitude,
263.256 + replace them by exact zero */
263.257 + if (fabs(u[kk]) < eps && fabs(un[k]) < eps)
263.258 + u[kk] = un[k] = 0.0;
263.259 + /* if U[n,k] is already zero, elimination is not needed */
263.260 + if (un[k] == 0.0) continue;
263.261 + /* compute the parameters of Givens plane rotation */
263.262 + givens(u[kk], un[k], &c, &s);
263.263 + /* apply Givens rotation to k-th and n-th rows of matrix U */
263.264 + for (j = k, kj = kk; j <= n; j++, kj++)
263.265 + { double ukj = u[kj], unj = un[j];
263.266 + u[kj] = c * ukj - s * unj;
263.267 + un[j] = s * ukj + c * unj;
263.268 + }
263.269 + /* apply Givens rotation to k-th and n-th rows of matrix F
263.270 + to keep the main equality F * C = U * P */
263.271 + for (j = 1, kj = k1, nj = n1; j <= n; j++, kj++, nj++)
263.272 + { double fkj = f[kj], fnj = f[nj];
263.273 + f[kj] = c * fkj - s * fnj;
263.274 + f[nj] = s * fkj + c * fnj;
263.275 + }
263.276 + }
263.277 + /* if U[n,n] is too small in the magnitude, replace it by exact
263.278 + zero */
263.279 + if (fabs(un[n]) < eps) un[n] = 0.0;
263.280 + /* store U[n,n] in a proper location */
263.281 + u[u_loc(scf, n, n)] = un[n];
263.282 + return;
263.283 +}
263.284 +
263.285 +/***********************************************************************
263.286 +* The routine transform restores triangular structure of matrix U.
263.287 +* It is a driver to the routines bg_transform and gr_transform (see
263.288 +* comments to these routines above). */
263.289 +
263.290 +static void transform(SCF *scf, int k, double un[])
263.291 +{ switch (scf->t_opt)
263.292 + { case SCF_TBG:
263.293 + bg_transform(scf, k, un);
263.294 + break;
263.295 + case SCF_TGR:
263.296 + gr_transform(scf, k, un);
263.297 + break;
263.298 + default:
263.299 + xassert(scf != scf);
263.300 + }
263.301 + return;
263.302 +}
263.303 +
263.304 +/***********************************************************************
263.305 +* The routine estimate_rank estimates the rank of matrix C.
263.306 +*
263.307 +* Since all transformations applied to matrix F are non-singular,
263.308 +* and F is assumed to be well conditioned, from the main equaility
263.309 +* F * C = U * P it follows that rank(C) = rank(U), where rank(U) is
263.310 +* estimated as the number of non-zero diagonal elements of U. */
263.311 +
263.312 +static int estimate_rank(SCF *scf)
263.313 +{ int n_max = scf->n_max;
263.314 + int n = scf->n;
263.315 + double *u = scf->u;
263.316 + int i, ii, inc, rank = 0;
263.317 + for (i = 1, ii = u_loc(scf, i, i), inc = n_max; i <= n;
263.318 + i++, ii += inc, inc--)
263.319 + if (u[ii] != 0.0) rank++;
263.320 + return rank;
263.321 +}
263.322 +
263.323 +#if _GLPSCF_DEBUG
263.324 +/***********************************************************************
263.325 +* The routine check_error computes the maximal relative error between
263.326 +* left- and right-hand sides of the main equality F * C = U * P. (This
263.327 +* routine is intended only for debugging.) */
263.328 +
263.329 +static void check_error(SCF *scf, const char *func)
263.330 +{ int n = scf->n;
263.331 + double *f = scf->f;
263.332 + double *u = scf->u;
263.333 + int *p = scf->p;
263.334 + double *c = scf->c;
263.335 + int i, j, k;
263.336 + double d, dmax = 0.0, s, t;
263.337 + xassert(c != NULL);
263.338 + for (i = 1; i <= n; i++)
263.339 + { for (j = 1; j <= n; j++)
263.340 + { /* compute element (i,j) of product F * C */
263.341 + s = 0.0;
263.342 + for (k = 1; k <= n; k++)
263.343 + s += f[f_loc(scf, i, k)] * c[f_loc(scf, k, j)];
263.344 + /* compute element (i,j) of product U * P */
263.345 + k = p[j];
263.346 + t = (i <= k ? u[u_loc(scf, i, k)] : 0.0);
263.347 + /* compute the maximal relative error */
263.348 + d = fabs(s - t) / (1.0 + fabs(t));
263.349 + if (dmax < d) dmax = d;
263.350 + }
263.351 + }
263.352 + if (dmax > 1e-8)
263.353 + xprintf("%s: dmax = %g; relative error too large\n", func,
263.354 + dmax);
263.355 + return;
263.356 +}
263.357 +#endif
263.358 +
263.359 +/***********************************************************************
263.360 +* NAME
263.361 +*
263.362 +* scf_update_exp - update factorization on expanding C
263.363 +*
263.364 +* SYNOPSIS
263.365 +*
263.366 +* #include "glpscf.h"
263.367 +* int scf_update_exp(SCF *scf, const double x[], const double y[],
263.368 +* double z);
263.369 +*
263.370 +* DESCRIPTION
263.371 +*
263.372 +* The routine scf_update_exp updates the factorization of matrix C on
263.373 +* expanding it by adding a new row and column as follows:
263.374 +*
263.375 +* ( C x )
263.376 +* new C = ( )
263.377 +* ( y' z )
263.378 +*
263.379 +* where x[1,...,n] is a new column, y[1,...,n] is a new row, and z is
263.380 +* a new diagonal element.
263.381 +*
263.382 +* If on entry the factorization is empty, the parameters x and y can
263.383 +* be specified as NULL.
263.384 +*
263.385 +* RETURNS
263.386 +*
263.387 +* 0 The factorization has been successfully updated.
263.388 +*
263.389 +* SCF_ESING
263.390 +* The factorization has been successfully updated, however, new
263.391 +* matrix C is singular within working precision. Note that the new
263.392 +* factorization remains valid.
263.393 +*
263.394 +* SCF_ELIMIT
263.395 +* There is not enough room to expand the factorization, because
263.396 +* n = n_max. The factorization remains unchanged.
263.397 +*
263.398 +* ALGORITHM
263.399 +*
263.400 +* We can see that:
263.401 +*
263.402 +* ( F 0 ) ( C x ) ( FC Fx ) ( UP Fx )
263.403 +* ( ) ( ) = ( ) = ( ) =
263.404 +* ( 0 1 ) ( y' z ) ( y' z ) ( y' z )
263.405 +*
263.406 +* ( U Fx ) ( P 0 )
263.407 +* = ( ) ( ),
263.408 +* ( y'P' z ) ( 0 1 )
263.409 +*
263.410 +* therefore to keep the main equality F * C = U * P we can take:
263.411 +*
263.412 +* ( F 0 ) ( U Fx ) ( P 0 )
263.413 +* new F = ( ), new U = ( ), new P = ( ),
263.414 +* ( 0 1 ) ( y'P' z ) ( 0 1 )
263.415 +*
263.416 +* and eliminate the row spike y'P' in the last row of new U to restore
263.417 +* its upper triangular structure. */
263.418 +
263.419 +int scf_update_exp(SCF *scf, const double x[], const double y[],
263.420 + double z)
263.421 +{ int n_max = scf->n_max;
263.422 + int n = scf->n;
263.423 + double *f = scf->f;
263.424 + double *u = scf->u;
263.425 + int *p = scf->p;
263.426 +#if _GLPSCF_DEBUG
263.427 + double *c = scf->c;
263.428 +#endif
263.429 + double *un = scf->w;
263.430 + int i, ij, in, j, k, nj, ret = 0;
263.431 + double t;
263.432 + /* check if the factorization can be expanded */
263.433 + if (n == n_max)
263.434 + { /* there is not enough room */
263.435 + ret = SCF_ELIMIT;
263.436 + goto done;
263.437 + }
263.438 + /* increase the order of the factorization */
263.439 + scf->n = ++n;
263.440 + /* fill new zero column of matrix F */
263.441 + for (i = 1, in = f_loc(scf, i, n); i < n; i++, in += n_max)
263.442 + f[in] = 0.0;
263.443 + /* fill new zero row of matrix F */
263.444 + for (j = 1, nj = f_loc(scf, n, j); j < n; j++, nj++)
263.445 + f[nj] = 0.0;
263.446 + /* fill new unity diagonal element of matrix F */
263.447 + f[f_loc(scf, n, n)] = 1.0;
263.448 + /* compute new column of matrix U, which is (old F) * x */
263.449 + for (i = 1; i < n; i++)
263.450 + { /* u[i,n] := (i-th row of old F) * x */
263.451 + t = 0.0;
263.452 + for (j = 1, ij = f_loc(scf, i, 1); j < n; j++, ij++)
263.453 + t += f[ij] * x[j];
263.454 + u[u_loc(scf, i, n)] = t;
263.455 + }
263.456 + /* compute new (spiked) row of matrix U, which is (old P) * y */
263.457 + for (j = 1; j < n; j++) un[j] = y[p[j]];
263.458 + /* store new diagonal element of matrix U, which is z */
263.459 + un[n] = z;
263.460 + /* expand matrix P */
263.461 + p[n] = n;
263.462 +#if _GLPSCF_DEBUG
263.463 + /* expand matrix C */
263.464 + /* fill its new column, which is x */
263.465 + for (i = 1, in = f_loc(scf, i, n); i < n; i++, in += n_max)
263.466 + c[in] = x[i];
263.467 + /* fill its new row, which is y */
263.468 + for (j = 1, nj = f_loc(scf, n, j); j < n; j++, nj++)
263.469 + c[nj] = y[j];
263.470 + /* fill its new diagonal element, which is z */
263.471 + c[f_loc(scf, n, n)] = z;
263.472 +#endif
263.473 + /* restore upper triangular structure of matrix U */
263.474 + for (k = 1; k < n; k++)
263.475 + if (un[k] != 0.0) break;
263.476 + transform(scf, k, un);
263.477 + /* estimate the rank of matrices C and U */
263.478 + scf->rank = estimate_rank(scf);
263.479 + if (scf->rank != n) ret = SCF_ESING;
263.480 +#if _GLPSCF_DEBUG
263.481 + /* check that the factorization is accurate enough */
263.482 + check_error(scf, "scf_update_exp");
263.483 +#endif
263.484 +done: return ret;
263.485 +}
263.486 +
263.487 +/***********************************************************************
263.488 +* The routine solve solves the system C * x = b.
263.489 +*
263.490 +* From the main equation F * C = U * P it follows that:
263.491 +*
263.492 +* C * x = b => F * C * x = F * b => U * P * x = F * b =>
263.493 +*
263.494 +* P * x = inv(U) * F * b => x = P' * inv(U) * F * b.
263.495 +*
263.496 +* On entry the array x contains right-hand side vector b. On exit this
263.497 +* array contains solution vector x. */
263.498 +
263.499 +static void solve(SCF *scf, double x[])
263.500 +{ int n = scf->n;
263.501 + double *f = scf->f;
263.502 + double *u = scf->u;
263.503 + int *p = scf->p;
263.504 + double *y = scf->w;
263.505 + int i, j, ij;
263.506 + double t;
263.507 + /* y := F * b */
263.508 + for (i = 1; i <= n; i++)
263.509 + { /* y[i] = (i-th row of F) * b */
263.510 + t = 0.0;
263.511 + for (j = 1, ij = f_loc(scf, i, 1); j <= n; j++, ij++)
263.512 + t += f[ij] * x[j];
263.513 + y[i] = t;
263.514 + }
263.515 + /* y := inv(U) * y */
263.516 + for (i = n; i >= 1; i--)
263.517 + { t = y[i];
263.518 + for (j = n, ij = u_loc(scf, i, n); j > i; j--, ij--)
263.519 + t -= u[ij] * y[j];
263.520 + y[i] = t / u[ij];
263.521 + }
263.522 + /* x := P' * y */
263.523 + for (i = 1; i <= n; i++) x[p[i]] = y[i];
263.524 + return;
263.525 +}
263.526 +
263.527 +/***********************************************************************
263.528 +* The routine tsolve solves the transposed system C' * x = b.
263.529 +*
263.530 +* From the main equation F * C = U * P it follows that:
263.531 +*
263.532 +* C' * F' = P' * U',
263.533 +*
263.534 +* therefore:
263.535 +*
263.536 +* C' * x = b => C' * F' * inv(F') * x = b =>
263.537 +*
263.538 +* P' * U' * inv(F') * x = b => U' * inv(F') * x = P * b =>
263.539 +*
263.540 +* inv(F') * x = inv(U') * P * b => x = F' * inv(U') * P * b.
263.541 +*
263.542 +* On entry the array x contains right-hand side vector b. On exit this
263.543 +* array contains solution vector x. */
263.544 +
263.545 +static void tsolve(SCF *scf, double x[])
263.546 +{ int n = scf->n;
263.547 + double *f = scf->f;
263.548 + double *u = scf->u;
263.549 + int *p = scf->p;
263.550 + double *y = scf->w;
263.551 + int i, j, ij;
263.552 + double t;
263.553 + /* y := P * b */
263.554 + for (i = 1; i <= n; i++) y[i] = x[p[i]];
263.555 + /* y := inv(U') * y */
263.556 + for (i = 1; i <= n; i++)
263.557 + { /* compute y[i] */
263.558 + ij = u_loc(scf, i, i);
263.559 + t = (y[i] /= u[ij]);
263.560 + /* substitute y[i] in other equations */
263.561 + for (j = i+1, ij++; j <= n; j++, ij++)
263.562 + y[j] -= u[ij] * t;
263.563 + }
263.564 + /* x := F' * y (computed as linear combination of rows of F) */
263.565 + for (j = 1; j <= n; j++) x[j] = 0.0;
263.566 + for (i = 1; i <= n; i++)
263.567 + { t = y[i]; /* coefficient of linear combination */
263.568 + for (j = 1, ij = f_loc(scf, i, 1); j <= n; j++, ij++)
263.569 + x[j] += f[ij] * t;
263.570 + }
263.571 + return;
263.572 +}
263.573 +
263.574 +/***********************************************************************
263.575 +* NAME
263.576 +*
263.577 +* scf_solve_it - solve either system C * x = b or C' * x = b
263.578 +*
263.579 +* SYNOPSIS
263.580 +*
263.581 +* #include "glpscf.h"
263.582 +* void scf_solve_it(SCF *scf, int tr, double x[]);
263.583 +*
263.584 +* DESCRIPTION
263.585 +*
263.586 +* The routine scf_solve_it solves either the system C * x = b (if tr
263.587 +* is zero) or the system C' * x = b, where C' is a matrix transposed
263.588 +* to C (if tr is non-zero). C is assumed to be non-singular.
263.589 +*
263.590 +* On entry the array x should contain the right-hand side vector b in
263.591 +* locations x[1], ..., x[n], where n is the order of matrix C. On exit
263.592 +* the array x contains the solution vector x in the same locations. */
263.593 +
263.594 +void scf_solve_it(SCF *scf, int tr, double x[])
263.595 +{ if (scf->rank < scf->n)
263.596 + xfault("scf_solve_it: singular matrix\n");
263.597 + if (!tr)
263.598 + solve(scf, x);
263.599 + else
263.600 + tsolve(scf, x);
263.601 + return;
263.602 +}
263.603 +
263.604 +void scf_reset_it(SCF *scf)
263.605 +{ /* reset factorization for empty matrix C */
263.606 + scf->n = scf->rank = 0;
263.607 + return;
263.608 +}
263.609 +
263.610 +/***********************************************************************
263.611 +* NAME
263.612 +*
263.613 +* scf_delete_it - delete Schur complement factorization
263.614 +*
263.615 +* SYNOPSIS
263.616 +*
263.617 +* #include "glpscf.h"
263.618 +* void scf_delete_it(SCF *scf);
263.619 +*
263.620 +* DESCRIPTION
263.621 +*
263.622 +* The routine scf_delete_it deletes the specified factorization and
263.623 +* frees all the memory allocated to this object. */
263.624 +
263.625 +void scf_delete_it(SCF *scf)
263.626 +{ xfree(scf->f);
263.627 + xfree(scf->u);
263.628 + xfree(scf->p);
263.629 +#if _GLPSCF_DEBUG
263.630 + xfree(scf->c);
263.631 +#endif
263.632 + xfree(scf->w);
263.633 + xfree(scf);
263.634 + return;
263.635 +}
263.636 +
263.637 +/* eof */
264.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
264.2 +++ b/src/glpscf.h Mon Dec 06 13:09:21 2010 +0100
264.3 @@ -0,0 +1,126 @@
264.4 +/* glpscf.h (Schur complement factorization) */
264.5 +
264.6 +/***********************************************************************
264.7 +* This code is part of GLPK (GNU Linear Programming Kit).
264.8 +*
264.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
264.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
264.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
264.12 +* E-mail: <mao@gnu.org>.
264.13 +*
264.14 +* GLPK is free software: you can redistribute it and/or modify it
264.15 +* under the terms of the GNU General Public License as published by
264.16 +* the Free Software Foundation, either version 3 of the License, or
264.17 +* (at your option) any later version.
264.18 +*
264.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
264.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
264.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
264.22 +* License for more details.
264.23 +*
264.24 +* You should have received a copy of the GNU General Public License
264.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
264.26 +***********************************************************************/
264.27 +
264.28 +#ifndef GLPSCF_H
264.29 +#define GLPSCF_H
264.30 +
264.31 +/***********************************************************************
264.32 +* The structure SCF defines the following factorization of a square
264.33 +* nxn matrix C (which is the Schur complement):
264.34 +*
264.35 +* F * C = U * P,
264.36 +*
264.37 +* where F is a square transforming matrix, U is an upper triangular
264.38 +* matrix, P is a permutation matrix.
264.39 +*
264.40 +* It is assumed that matrix C is small and dense, so matrices F and U
264.41 +* are stored in the dense format by rows as follows:
264.42 +*
264.43 +* 1 n n_max 1 n n_max
264.44 +* 1 * * * * * * x x x x 1 * * * * * * x x x x
264.45 +* * * * * * * x x x x . * * * * * x x x x
264.46 +* * * * * * * x x x x . . * * * * x x x x
264.47 +* * * * * * * x x x x . . . * * * x x x x
264.48 +* * * * * * * x x x x . . . . * * x x x x
264.49 +* n * * * * * * x x x x n . . . . . * x x x x
264.50 +* x x x x x x x x x x . . . . . . x x x x
264.51 +* x x x x x x x x x x . . . . . . . x x x
264.52 +* x x x x x x x x x x . . . . . . . . x x
264.53 +* n_max x x x x x x x x x x n_max . . . . . . . . . x
264.54 +*
264.55 +* matrix F matrix U
264.56 +*
264.57 +* where '*' are matrix elements, 'x' are reserved locations.
264.58 +*
264.59 +* Permutation matrix P is stored in row-like format.
264.60 +*
264.61 +* Matrix C normally is not stored.
264.62 +*
264.63 +* REFERENCES
264.64 +*
264.65 +* 1. M.A.Saunders, "LUSOL: A basis package for constrained optimiza-
264.66 +* tion," SCCM, Stanford University, 2006.
264.67 +*
264.68 +* 2. M.A.Saunders, "Notes 5: Basis Updates," CME 318, Stanford Univer-
264.69 +* sity, Spring 2006.
264.70 +*
264.71 +* 3. M.A.Saunders, "Notes 6: LUSOL---a Basis Factorization Package,"
264.72 +* ibid. */
264.73 +
264.74 +typedef struct SCF SCF;
264.75 +
264.76 +struct SCF
264.77 +{ /* Schur complement factorization */
264.78 + int n_max;
264.79 + /* maximal order of matrices C, F, U, P; n_max >= 1 */
264.80 + int n;
264.81 + /* current order of matrices C, F, U, P; n >= 0 */
264.82 + double *f; /* double f[1+n_max*n_max]; */
264.83 + /* matrix F stored by rows */
264.84 + double *u; /* double u[1+n_max*(n_max+1)/2]; */
264.85 + /* upper triangle of matrix U stored by rows */
264.86 + int *p; /* int p[1+n_max]; */
264.87 + /* matrix P; p[i] = j means that P[i,j] = 1 */
264.88 + int t_opt;
264.89 + /* type of transformation used to restore triangular structure of
264.90 + matrix U: */
264.91 +#define SCF_TBG 1 /* Bartels-Golub elimination */
264.92 +#define SCF_TGR 2 /* Givens plane rotation */
264.93 + int rank;
264.94 + /* estimated rank of matrices C and U */
264.95 + double *c; /* double c[1+n_max*n_max]; */
264.96 + /* matrix C stored in the same format as matrix F and used only
264.97 + for debugging; normally this array is not allocated */
264.98 + double *w; /* double w[1+n_max]; */
264.99 + /* working array */
264.100 +};
264.101 +
264.102 +/* return codes: */
264.103 +#define SCF_ESING 1 /* singular matrix */
264.104 +#define SCF_ELIMIT 2 /* update limit reached */
264.105 +
264.106 +#define scf_create_it _glp_scf_create_it
264.107 +SCF *scf_create_it(int n_max);
264.108 +/* create Schur complement factorization */
264.109 +
264.110 +#define scf_update_exp _glp_scf_update_exp
264.111 +int scf_update_exp(SCF *scf, const double x[], const double y[],
264.112 + double z);
264.113 +/* update factorization on expanding C */
264.114 +
264.115 +#define scf_solve_it _glp_scf_solve_it
264.116 +void scf_solve_it(SCF *scf, int tr, double x[]);
264.117 +/* solve either system C * x = b or C' * x = b */
264.118 +
264.119 +#define scf_reset_it _glp_scf_reset_it
264.120 +void scf_reset_it(SCF *scf);
264.121 +/* reset factorization for empty matrix C */
264.122 +
264.123 +#define scf_delete_it _glp_scf_delete_it
264.124 +void scf_delete_it(SCF *scf);
264.125 +/* delete Schur complement factorization */
264.126 +
264.127 +#endif
264.128 +
264.129 +/* eof */
265.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
265.2 +++ b/src/glpscl.c Mon Dec 06 13:09:21 2010 +0100
265.3 @@ -0,0 +1,476 @@
265.4 +/* glpscl.c */
265.5 +
265.6 +/***********************************************************************
265.7 +* This code is part of GLPK (GNU Linear Programming Kit).
265.8 +*
265.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
265.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
265.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
265.12 +* E-mail: <mao@gnu.org>.
265.13 +*
265.14 +* GLPK is free software: you can redistribute it and/or modify it
265.15 +* under the terms of the GNU General Public License as published by
265.16 +* the Free Software Foundation, either version 3 of the License, or
265.17 +* (at your option) any later version.
265.18 +*
265.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
265.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
265.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
265.22 +* License for more details.
265.23 +*
265.24 +* You should have received a copy of the GNU General Public License
265.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
265.26 +***********************************************************************/
265.27 +
265.28 +#include "glpapi.h"
265.29 +
265.30 +/***********************************************************************
265.31 +* min_row_aij - determine minimal |a[i,j]| in i-th row
265.32 +*
265.33 +* This routine returns minimal magnitude of (non-zero) constraint
265.34 +* coefficients in i-th row of the constraint matrix.
265.35 +*
265.36 +* If the parameter scaled is zero, the original constraint matrix A is
265.37 +* assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
265.38 +*
265.39 +* If i-th row of the matrix is empty, the routine returns 1. */
265.40 +
265.41 +static double min_row_aij(glp_prob *lp, int i, int scaled)
265.42 +{ GLPAIJ *aij;
265.43 + double min_aij, temp;
265.44 + xassert(1 <= i && i <= lp->m);
265.45 + min_aij = 1.0;
265.46 + for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
265.47 + { temp = fabs(aij->val);
265.48 + if (scaled) temp *= (aij->row->rii * aij->col->sjj);
265.49 + if (aij->r_prev == NULL || min_aij > temp)
265.50 + min_aij = temp;
265.51 + }
265.52 + return min_aij;
265.53 +}
265.54 +
265.55 +/***********************************************************************
265.56 +* max_row_aij - determine maximal |a[i,j]| in i-th row
265.57 +*
265.58 +* This routine returns maximal magnitude of (non-zero) constraint
265.59 +* coefficients in i-th row of the constraint matrix.
265.60 +*
265.61 +* If the parameter scaled is zero, the original constraint matrix A is
265.62 +* assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
265.63 +*
265.64 +* If i-th row of the matrix is empty, the routine returns 1. */
265.65 +
265.66 +static double max_row_aij(glp_prob *lp, int i, int scaled)
265.67 +{ GLPAIJ *aij;
265.68 + double max_aij, temp;
265.69 + xassert(1 <= i && i <= lp->m);
265.70 + max_aij = 1.0;
265.71 + for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
265.72 + { temp = fabs(aij->val);
265.73 + if (scaled) temp *= (aij->row->rii * aij->col->sjj);
265.74 + if (aij->r_prev == NULL || max_aij < temp)
265.75 + max_aij = temp;
265.76 + }
265.77 + return max_aij;
265.78 +}
265.79 +
265.80 +/***********************************************************************
265.81 +* min_col_aij - determine minimal |a[i,j]| in j-th column
265.82 +*
265.83 +* This routine returns minimal magnitude of (non-zero) constraint
265.84 +* coefficients in j-th column of the constraint matrix.
265.85 +*
265.86 +* If the parameter scaled is zero, the original constraint matrix A is
265.87 +* assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
265.88 +*
265.89 +* If j-th column of the matrix is empty, the routine returns 1. */
265.90 +
265.91 +static double min_col_aij(glp_prob *lp, int j, int scaled)
265.92 +{ GLPAIJ *aij;
265.93 + double min_aij, temp;
265.94 + xassert(1 <= j && j <= lp->n);
265.95 + min_aij = 1.0;
265.96 + for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
265.97 + { temp = fabs(aij->val);
265.98 + if (scaled) temp *= (aij->row->rii * aij->col->sjj);
265.99 + if (aij->c_prev == NULL || min_aij > temp)
265.100 + min_aij = temp;
265.101 + }
265.102 + return min_aij;
265.103 +}
265.104 +
265.105 +/***********************************************************************
265.106 +* max_col_aij - determine maximal |a[i,j]| in j-th column
265.107 +*
265.108 +* This routine returns maximal magnitude of (non-zero) constraint
265.109 +* coefficients in j-th column of the constraint matrix.
265.110 +*
265.111 +* If the parameter scaled is zero, the original constraint matrix A is
265.112 +* assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
265.113 +*
265.114 +* If j-th column of the matrix is empty, the routine returns 1. */
265.115 +
265.116 +static double max_col_aij(glp_prob *lp, int j, int scaled)
265.117 +{ GLPAIJ *aij;
265.118 + double max_aij, temp;
265.119 + xassert(1 <= j && j <= lp->n);
265.120 + max_aij = 1.0;
265.121 + for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
265.122 + { temp = fabs(aij->val);
265.123 + if (scaled) temp *= (aij->row->rii * aij->col->sjj);
265.124 + if (aij->c_prev == NULL || max_aij < temp)
265.125 + max_aij = temp;
265.126 + }
265.127 + return max_aij;
265.128 +}
265.129 +
265.130 +/***********************************************************************
265.131 +* min_mat_aij - determine minimal |a[i,j]| in constraint matrix
265.132 +*
265.133 +* This routine returns minimal magnitude of (non-zero) constraint
265.134 +* coefficients in the constraint matrix.
265.135 +*
265.136 +* If the parameter scaled is zero, the original constraint matrix A is
265.137 +* assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
265.138 +*
265.139 +* If the matrix is empty, the routine returns 1. */
265.140 +
265.141 +static double min_mat_aij(glp_prob *lp, int scaled)
265.142 +{ int i;
265.143 + double min_aij, temp;
265.144 + min_aij = 1.0;
265.145 + for (i = 1; i <= lp->m; i++)
265.146 + { temp = min_row_aij(lp, i, scaled);
265.147 + if (i == 1 || min_aij > temp)
265.148 + min_aij = temp;
265.149 + }
265.150 + return min_aij;
265.151 +}
265.152 +
265.153 +/***********************************************************************
265.154 +* max_mat_aij - determine maximal |a[i,j]| in constraint matrix
265.155 +*
265.156 +* This routine returns maximal magnitude of (non-zero) constraint
265.157 +* coefficients in the constraint matrix.
265.158 +*
265.159 +* If the parameter scaled is zero, the original constraint matrix A is
265.160 +* assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
265.161 +*
265.162 +* If the matrix is empty, the routine returns 1. */
265.163 +
265.164 +static double max_mat_aij(glp_prob *lp, int scaled)
265.165 +{ int i;
265.166 + double max_aij, temp;
265.167 + max_aij = 1.0;
265.168 + for (i = 1; i <= lp->m; i++)
265.169 + { temp = max_row_aij(lp, i, scaled);
265.170 + if (i == 1 || max_aij < temp)
265.171 + max_aij = temp;
265.172 + }
265.173 + return max_aij;
265.174 +}
265.175 +
265.176 +/***********************************************************************
265.177 +* eq_scaling - perform equilibration scaling
265.178 +*
265.179 +* This routine performs equilibration scaling of rows and columns of
265.180 +* the constraint matrix.
265.181 +*
265.182 +* If the parameter flag is zero, the routine scales rows at first and
265.183 +* then columns. Otherwise, the routine scales columns and then rows.
265.184 +*
265.185 +* Rows are scaled as follows:
265.186 +*
265.187 +* n
265.188 +* a'[i,j] = a[i,j] / max |a[i,j]|, i = 1,...,m.
265.189 +* j=1
265.190 +*
265.191 +* This makes the infinity (maximum) norm of each row of the matrix
265.192 +* equal to 1.
265.193 +*
265.194 +* Columns are scaled as follows:
265.195 +*
265.196 +* n
265.197 +* a'[i,j] = a[i,j] / max |a[i,j]|, j = 1,...,n.
265.198 +* i=1
265.199 +*
265.200 +* This makes the infinity (maximum) norm of each column of the matrix
265.201 +* equal to 1. */
265.202 +
265.203 +static void eq_scaling(glp_prob *lp, int flag)
265.204 +{ int i, j, pass;
265.205 + double temp;
265.206 + xassert(flag == 0 || flag == 1);
265.207 + for (pass = 0; pass <= 1; pass++)
265.208 + { if (pass == flag)
265.209 + { /* scale rows */
265.210 + for (i = 1; i <= lp->m; i++)
265.211 + { temp = max_row_aij(lp, i, 1);
265.212 + glp_set_rii(lp, i, glp_get_rii(lp, i) / temp);
265.213 + }
265.214 + }
265.215 + else
265.216 + { /* scale columns */
265.217 + for (j = 1; j <= lp->n; j++)
265.218 + { temp = max_col_aij(lp, j, 1);
265.219 + glp_set_sjj(lp, j, glp_get_sjj(lp, j) / temp);
265.220 + }
265.221 + }
265.222 + }
265.223 + return;
265.224 +}
265.225 +
265.226 +/***********************************************************************
265.227 +* gm_scaling - perform geometric mean scaling
265.228 +*
265.229 +* This routine performs geometric mean scaling of rows and columns of
265.230 +* the constraint matrix.
265.231 +*
265.232 +* If the parameter flag is zero, the routine scales rows at first and
265.233 +* then columns. Otherwise, the routine scales columns and then rows.
265.234 +*
265.235 +* Rows are scaled as follows:
265.236 +*
265.237 +* a'[i,j] = a[i,j] / sqrt(alfa[i] * beta[i]), i = 1,...,m,
265.238 +*
265.239 +* where:
265.240 +* n n
265.241 +* alfa[i] = min |a[i,j]|, beta[i] = max |a[i,j]|.
265.242 +* j=1 j=1
265.243 +*
265.244 +* This allows decreasing the ratio beta[i] / alfa[i] for each row of
265.245 +* the matrix.
265.246 +*
265.247 +* Columns are scaled as follows:
265.248 +*
265.249 +* a'[i,j] = a[i,j] / sqrt(alfa[j] * beta[j]), j = 1,...,n,
265.250 +*
265.251 +* where:
265.252 +* m m
265.253 +* alfa[j] = min |a[i,j]|, beta[j] = max |a[i,j]|.
265.254 +* i=1 i=1
265.255 +*
265.256 +* This allows decreasing the ratio beta[j] / alfa[j] for each column
265.257 +* of the matrix. */
265.258 +
265.259 +static void gm_scaling(glp_prob *lp, int flag)
265.260 +{ int i, j, pass;
265.261 + double temp;
265.262 + xassert(flag == 0 || flag == 1);
265.263 + for (pass = 0; pass <= 1; pass++)
265.264 + { if (pass == flag)
265.265 + { /* scale rows */
265.266 + for (i = 1; i <= lp->m; i++)
265.267 + { temp = min_row_aij(lp, i, 1) * max_row_aij(lp, i, 1);
265.268 + glp_set_rii(lp, i, glp_get_rii(lp, i) / sqrt(temp));
265.269 + }
265.270 + }
265.271 + else
265.272 + { /* scale columns */
265.273 + for (j = 1; j <= lp->n; j++)
265.274 + { temp = min_col_aij(lp, j, 1) * max_col_aij(lp, j, 1);
265.275 + glp_set_sjj(lp, j, glp_get_sjj(lp, j) / sqrt(temp));
265.276 + }
265.277 + }
265.278 + }
265.279 + return;
265.280 +}
265.281 +
265.282 +/***********************************************************************
265.283 +* max_row_ratio - determine worst scaling "quality" for rows
265.284 +*
265.285 +* This routine returns the worst scaling "quality" for rows of the
265.286 +* currently scaled constraint matrix:
265.287 +*
265.288 +* m
265.289 +* ratio = max ratio[i],
265.290 +* i=1
265.291 +* where:
265.292 +* n n
265.293 +* ratio[i] = max |a[i,j]| / min |a[i,j]|, 1 <= i <= m,
265.294 +* j=1 j=1
265.295 +*
265.296 +* is the scaling "quality" of i-th row. */
265.297 +
265.298 +static double max_row_ratio(glp_prob *lp)
265.299 +{ int i;
265.300 + double ratio, temp;
265.301 + ratio = 1.0;
265.302 + for (i = 1; i <= lp->m; i++)
265.303 + { temp = max_row_aij(lp, i, 1) / min_row_aij(lp, i, 1);
265.304 + if (i == 1 || ratio < temp) ratio = temp;
265.305 + }
265.306 + return ratio;
265.307 +}
265.308 +
265.309 +/***********************************************************************
265.310 +* max_col_ratio - determine worst scaling "quality" for columns
265.311 +*
265.312 +* This routine returns the worst scaling "quality" for columns of the
265.313 +* currently scaled constraint matrix:
265.314 +*
265.315 +* n
265.316 +* ratio = max ratio[j],
265.317 +* j=1
265.318 +* where:
265.319 +* m m
265.320 +* ratio[j] = max |a[i,j]| / min |a[i,j]|, 1 <= j <= n,
265.321 +* i=1 i=1
265.322 +*
265.323 +* is the scaling "quality" of j-th column. */
265.324 +
265.325 +static double max_col_ratio(glp_prob *lp)
265.326 +{ int j;
265.327 + double ratio, temp;
265.328 + ratio = 1.0;
265.329 + for (j = 1; j <= lp->n; j++)
265.330 + { temp = max_col_aij(lp, j, 1) / min_col_aij(lp, j, 1);
265.331 + if (j == 1 || ratio < temp) ratio = temp;
265.332 + }
265.333 + return ratio;
265.334 +}
265.335 +
265.336 +/***********************************************************************
265.337 +* gm_iterate - perform iterative geometric mean scaling
265.338 +*
265.339 +* This routine performs iterative geometric mean scaling of rows and
265.340 +* columns of the constraint matrix.
265.341 +*
265.342 +* The parameter it_max specifies the maximal number of iterations.
265.343 +* Recommended value of it_max is 15.
265.344 +*
265.345 +* The parameter tau specifies a minimal improvement of the scaling
265.346 +* "quality" on each iteration, 0 < tau < 1. It means than the scaling
265.347 +* process continues while the following condition is satisfied:
265.348 +*
265.349 +* ratio[k] <= tau * ratio[k-1],
265.350 +*
265.351 +* where ratio = max |a[i,j]| / min |a[i,j]| is the scaling "quality"
265.352 +* to be minimized, k is the iteration number. Recommended value of tau
265.353 +* is 0.90. */
265.354 +
265.355 +static void gm_iterate(glp_prob *lp, int it_max, double tau)
265.356 +{ int k, flag;
265.357 + double ratio = 0.0, r_old;
265.358 + /* if the scaling "quality" for rows is better than for columns,
265.359 + the rows are scaled first; otherwise, the columns are scaled
265.360 + first */
265.361 + flag = (max_row_ratio(lp) > max_col_ratio(lp));
265.362 + for (k = 1; k <= it_max; k++)
265.363 + { /* save the scaling "quality" from previous iteration */
265.364 + r_old = ratio;
265.365 + /* determine the current scaling "quality" */
265.366 + ratio = max_mat_aij(lp, 1) / min_mat_aij(lp, 1);
265.367 +#if 0
265.368 + xprintf("k = %d; ratio = %g\n", k, ratio);
265.369 +#endif
265.370 + /* if improvement is not enough, terminate scaling */
265.371 + if (k > 1 && ratio > tau * r_old) break;
265.372 + /* otherwise, perform another iteration */
265.373 + gm_scaling(lp, flag);
265.374 + }
265.375 + return;
265.376 +}
265.377 +
265.378 +/***********************************************************************
265.379 +* NAME
265.380 +*
265.381 +* scale_prob - scale problem data
265.382 +*
265.383 +* SYNOPSIS
265.384 +*
265.385 +* #include "glpscl.h"
265.386 +* void scale_prob(glp_prob *lp, int flags);
265.387 +*
265.388 +* DESCRIPTION
265.389 +*
265.390 +* The routine scale_prob performs automatic scaling of problem data
265.391 +* for the specified problem object. */
265.392 +
265.393 +static void scale_prob(glp_prob *lp, int flags)
265.394 +{ static const char *fmt =
265.395 + "%s: min|aij| = %10.3e max|aij| = %10.3e ratio = %10.3e\n";
265.396 + double min_aij, max_aij, ratio;
265.397 + xprintf("Scaling...\n");
265.398 + /* cancel the current scaling effect */
265.399 + glp_unscale_prob(lp);
265.400 + /* report original scaling "quality" */
265.401 + min_aij = min_mat_aij(lp, 1);
265.402 + max_aij = max_mat_aij(lp, 1);
265.403 + ratio = max_aij / min_aij;
265.404 + xprintf(fmt, " A", min_aij, max_aij, ratio);
265.405 + /* check if the problem is well scaled */
265.406 + if (min_aij >= 0.10 && max_aij <= 10.0)
265.407 + { xprintf("Problem data seem to be well scaled\n");
265.408 + /* skip scaling, if required */
265.409 + if (flags & GLP_SF_SKIP) goto done;
265.410 + }
265.411 + /* perform iterative geometric mean scaling, if required */
265.412 + if (flags & GLP_SF_GM)
265.413 + { gm_iterate(lp, 15, 0.90);
265.414 + min_aij = min_mat_aij(lp, 1);
265.415 + max_aij = max_mat_aij(lp, 1);
265.416 + ratio = max_aij / min_aij;
265.417 + xprintf(fmt, "GM", min_aij, max_aij, ratio);
265.418 + }
265.419 + /* perform equilibration scaling, if required */
265.420 + if (flags & GLP_SF_EQ)
265.421 + { eq_scaling(lp, max_row_ratio(lp) > max_col_ratio(lp));
265.422 + min_aij = min_mat_aij(lp, 1);
265.423 + max_aij = max_mat_aij(lp, 1);
265.424 + ratio = max_aij / min_aij;
265.425 + xprintf(fmt, "EQ", min_aij, max_aij, ratio);
265.426 + }
265.427 + /* round scale factors to nearest power of two, if required */
265.428 + if (flags & GLP_SF_2N)
265.429 + { int i, j;
265.430 + for (i = 1; i <= lp->m; i++)
265.431 + glp_set_rii(lp, i, round2n(glp_get_rii(lp, i)));
265.432 + for (j = 1; j <= lp->n; j++)
265.433 + glp_set_sjj(lp, j, round2n(glp_get_sjj(lp, j)));
265.434 + min_aij = min_mat_aij(lp, 1);
265.435 + max_aij = max_mat_aij(lp, 1);
265.436 + ratio = max_aij / min_aij;
265.437 + xprintf(fmt, "2N", min_aij, max_aij, ratio);
265.438 + }
265.439 +done: return;
265.440 +}
265.441 +
265.442 +/***********************************************************************
265.443 +* NAME
265.444 +*
265.445 +* glp_scale_prob - scale problem data
265.446 +*
265.447 +* SYNOPSIS
265.448 +*
265.449 +* void glp_scale_prob(glp_prob *lp, int flags);
265.450 +*
265.451 +* DESCRIPTION
265.452 +*
265.453 +* The routine glp_scale_prob performs automatic scaling of problem
265.454 +* data for the specified problem object.
265.455 +*
265.456 +* The parameter flags specifies scaling options used by the routine.
265.457 +* Options can be combined with the bitwise OR operator and may be the
265.458 +* following:
265.459 +*
265.460 +* GLP_SF_GM perform geometric mean scaling;
265.461 +* GLP_SF_EQ perform equilibration scaling;
265.462 +* GLP_SF_2N round scale factors to nearest power of two;
265.463 +* GLP_SF_SKIP skip scaling, if the problem is well scaled.
265.464 +*
265.465 +* The parameter flags may be specified as GLP_SF_AUTO, in which case
265.466 +* the routine chooses scaling options automatically. */
265.467 +
265.468 +void glp_scale_prob(glp_prob *lp, int flags)
265.469 +{ if (flags & ~(GLP_SF_GM | GLP_SF_EQ | GLP_SF_2N | GLP_SF_SKIP |
265.470 + GLP_SF_AUTO))
265.471 + xerror("glp_scale_prob: flags = 0x%02X; invalid scaling option"
265.472 + "s\n", flags);
265.473 + if (flags & GLP_SF_AUTO)
265.474 + flags = (GLP_SF_GM | GLP_SF_EQ | GLP_SF_SKIP);
265.475 + scale_prob(lp, flags);
265.476 + return;
265.477 +}
265.478 +
265.479 +/* eof */
266.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
266.2 +++ b/src/glpsdf.c Mon Dec 06 13:09:21 2010 +0100
266.3 @@ -0,0 +1,262 @@
266.4 +/* glpsdf.c (plain data file reading routines) */
266.5 +
266.6 +/***********************************************************************
266.7 +* This code is part of GLPK (GNU Linear Programming Kit).
266.8 +*
266.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
266.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
266.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
266.12 +* E-mail: <mao@gnu.org>.
266.13 +*
266.14 +* GLPK is free software: you can redistribute it and/or modify it
266.15 +* under the terms of the GNU General Public License as published by
266.16 +* the Free Software Foundation, either version 3 of the License, or
266.17 +* (at your option) any later version.
266.18 +*
266.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
266.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
266.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
266.22 +* License for more details.
266.23 +*
266.24 +* You should have received a copy of the GNU General Public License
266.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
266.26 +***********************************************************************/
266.27 +
266.28 +#define GLPSDF_H
266.29 +
266.30 +#define GLP_DATA_DEFINED
266.31 +typedef struct glp_data glp_data;
266.32 +
266.33 +#include "glpapi.h"
266.34 +
266.35 +struct glp_data
266.36 +{ /* plain data file */
266.37 + char *fname;
266.38 + /* name of data file */
266.39 + XFILE *fp;
266.40 + /* stream assigned to data file */
266.41 + void *jump; /* jmp_buf jump; */
266.42 + /* label for go to in case of error */
266.43 + int count;
266.44 + /* line count */
266.45 + int c;
266.46 + /* current character of XEOF */
266.47 + char item[255+1];
266.48 + /* current data item */
266.49 +};
266.50 +
266.51 +static void next_char(glp_data *data);
266.52 +
266.53 +glp_data *glp_sdf_open_file(const char *fname)
266.54 +{ /* open plain data file */
266.55 + glp_data *data = NULL;
266.56 + XFILE *fp;
266.57 + jmp_buf jump;
266.58 + fp = xfopen(fname, "r");
266.59 + if (fp == NULL)
266.60 + { xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
266.61 + goto done;
266.62 + }
266.63 + data = xmalloc(sizeof(glp_data));
266.64 + data->fname = xmalloc(strlen(fname)+1);
266.65 + strcpy(data->fname, fname);
266.66 + data->fp = fp;
266.67 + data->jump = NULL;
266.68 + data->count = 0;
266.69 + data->c = '\n';
266.70 + data->item[0] = '\0';
266.71 + /* read the very first character */
266.72 + if (setjmp(jump))
266.73 + { glp_sdf_close_file(data);
266.74 + data = NULL;
266.75 + goto done;
266.76 + }
266.77 + data->jump = jump;
266.78 + next_char(data);
266.79 + data->jump = NULL;
266.80 +done: return data;
266.81 +}
266.82 +
266.83 +void glp_sdf_set_jump(glp_data *data, void *jump)
266.84 +{ /* set up error handling */
266.85 + data->jump = jump;
266.86 + return;
266.87 +}
266.88 +
266.89 +void glp_sdf_error(glp_data *data, const char *fmt, ...)
266.90 +{ /* print error message */
266.91 + va_list arg;
266.92 + xprintf("%s:%d: ", data->fname, data->count);
266.93 + va_start(arg, fmt);
266.94 + xvprintf(fmt, arg);
266.95 + va_end(arg);
266.96 + if (data->jump == NULL)
266.97 + xerror("");
266.98 + else
266.99 + longjmp(data->jump, 1);
266.100 + /* no return */
266.101 +}
266.102 +
266.103 +void glp_sdf_warning(glp_data *data, const char *fmt, ...)
266.104 +{ /* print warning message */
266.105 + va_list arg;
266.106 + xprintf("%s:%d: warning: ", data->fname, data->count);
266.107 + va_start(arg, fmt);
266.108 + xvprintf(fmt, arg);
266.109 + va_end(arg);
266.110 + return;
266.111 +}
266.112 +
266.113 +static void next_char(glp_data *data)
266.114 +{ /* read next character */
266.115 + int c;
266.116 + if (data->c == XEOF)
266.117 + glp_sdf_error(data, "unexpected end of file\n");
266.118 + else if (data->c == '\n')
266.119 + data->count++;
266.120 + c = xfgetc(data->fp);
266.121 + if (c < 0)
266.122 + { if (xferror(data->fp))
266.123 + glp_sdf_error(data, "read error - %s\n", xerrmsg());
266.124 + else if (data->c == '\n')
266.125 + c = XEOF;
266.126 + else
266.127 + { glp_sdf_warning(data, "missing final end of line\n");
266.128 + c = '\n';
266.129 + }
266.130 + }
266.131 + else if (c == '\n')
266.132 + ;
266.133 + else if (isspace(c))
266.134 + c = ' ';
266.135 + else if (iscntrl(c))
266.136 + glp_sdf_error(data, "invalid control character 0x%02X\n", c);
266.137 + data->c = c;
266.138 + return;
266.139 +}
266.140 +
266.141 +static void skip_pad(glp_data *data)
266.142 +{ /* skip uninteresting characters and comments */
266.143 +loop: while (data->c == ' ' || data->c == '\n')
266.144 + next_char(data);
266.145 + if (data->c == '/')
266.146 + { next_char(data);
266.147 + if (data->c != '*')
266.148 + glp_sdf_error(data, "invalid use of slash\n");
266.149 + next_char(data);
266.150 + for (;;)
266.151 + { if (data->c == '*')
266.152 + { next_char(data);
266.153 + if (data->c == '/')
266.154 + { next_char(data);
266.155 + break;
266.156 + }
266.157 + }
266.158 + next_char(data);
266.159 + }
266.160 + goto loop;
266.161 + }
266.162 + return;
266.163 +}
266.164 +
266.165 +static void next_item(glp_data *data)
266.166 +{ /* read next item */
266.167 + int len;
266.168 + skip_pad(data);
266.169 + len = 0;
266.170 + while (!(data->c == ' ' || data->c == '\n'))
266.171 + { data->item[len++] = (char)data->c;
266.172 + if (len == sizeof(data->item))
266.173 + glp_sdf_error(data, "data item `%.31s...' too long\n",
266.174 + data->item);
266.175 + next_char(data);
266.176 + }
266.177 + data->item[len] = '\0';
266.178 + return;
266.179 +}
266.180 +
266.181 +int glp_sdf_read_int(glp_data *data)
266.182 +{ /* read integer number */
266.183 + int x;
266.184 + next_item(data);
266.185 + switch (str2int(data->item, &x))
266.186 + { case 0:
266.187 + break;
266.188 + case 1:
266.189 + glp_sdf_error(data, "integer `%s' out of range\n",
266.190 + data->item);
266.191 + case 2:
266.192 + glp_sdf_error(data, "cannot convert `%s' to integer\n",
266.193 + data->item);
266.194 + default:
266.195 + xassert(data != data);
266.196 + }
266.197 + return x;
266.198 +}
266.199 +
266.200 +double glp_sdf_read_num(glp_data *data)
266.201 +{ /* read floating-point number */
266.202 + double x;
266.203 + next_item(data);
266.204 + switch (str2num(data->item, &x))
266.205 + { case 0:
266.206 + break;
266.207 + case 1:
266.208 + glp_sdf_error(data, "number `%s' out of range\n",
266.209 + data->item);
266.210 + case 2:
266.211 + glp_sdf_error(data, "cannot convert `%s' to number\n",
266.212 + data->item);
266.213 + default:
266.214 + xassert(data != data);
266.215 + }
266.216 + return x;
266.217 +}
266.218 +
266.219 +const char *glp_sdf_read_item(glp_data *data)
266.220 +{ /* read data item */
266.221 + next_item(data);
266.222 + return data->item;
266.223 +}
266.224 +
266.225 +const char *glp_sdf_read_text(glp_data *data)
266.226 +{ /* read text until end of line */
266.227 + int c, len = 0;
266.228 + for (;;)
266.229 + { c = data->c;
266.230 + next_char(data);
266.231 + if (c == ' ')
266.232 + { /* ignore initial spaces */
266.233 + if (len == 0) continue;
266.234 + /* and multiple ones */
266.235 + if (data->item[len-1] == ' ') continue;
266.236 + }
266.237 + else if (c == '\n')
266.238 + { /* remove trailing space */
266.239 + if (len > 0 && data->item[len-1] == ' ') len--;
266.240 + /* and stop reading */
266.241 + break;
266.242 + }
266.243 + /* add current character to the buffer */
266.244 + data->item[len++] = (char)c;
266.245 + if (len == sizeof(data->item))
266.246 + glp_sdf_error(data, "line too long\n", data->item);
266.247 + }
266.248 + data->item[len] = '\0';
266.249 + return data->item;
266.250 +}
266.251 +
266.252 +int glp_sdf_line(glp_data *data)
266.253 +{ /* determine current line number */
266.254 + return data->count;
266.255 +}
266.256 +
266.257 +void glp_sdf_close_file(glp_data *data)
266.258 +{ /* close plain data file */
266.259 + xfclose(data->fp);
266.260 + xfree(data->fname);
266.261 + xfree(data);
266.262 + return;
266.263 +}
266.264 +
266.265 +/* eof */
267.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
267.2 +++ b/src/glpspm.c Mon Dec 06 13:09:21 2010 +0100
267.3 @@ -0,0 +1,846 @@
267.4 +/* glpspm.c */
267.5 +
267.6 +/***********************************************************************
267.7 +* This code is part of GLPK (GNU Linear Programming Kit).
267.8 +*
267.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
267.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
267.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
267.12 +* E-mail: <mao@gnu.org>.
267.13 +*
267.14 +* GLPK is free software: you can redistribute it and/or modify it
267.15 +* under the terms of the GNU General Public License as published by
267.16 +* the Free Software Foundation, either version 3 of the License, or
267.17 +* (at your option) any later version.
267.18 +*
267.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
267.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
267.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
267.22 +* License for more details.
267.23 +*
267.24 +* You should have received a copy of the GNU General Public License
267.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
267.26 +***********************************************************************/
267.27 +
267.28 +#include "glphbm.h"
267.29 +#include "glprgr.h"
267.30 +#include "glpspm.h"
267.31 +
267.32 +/***********************************************************************
267.33 +* NAME
267.34 +*
267.35 +* spm_create_mat - create general sparse matrix
267.36 +*
267.37 +* SYNOPSIS
267.38 +*
267.39 +* #include "glpspm.h"
267.40 +* SPM *spm_create_mat(int m, int n);
267.41 +*
267.42 +* DESCRIPTION
267.43 +*
267.44 +* The routine spm_create_mat creates a general sparse matrix having
267.45 +* m rows and n columns. Being created the matrix is zero (empty), i.e.
267.46 +* has no elements.
267.47 +*
267.48 +* RETURNS
267.49 +*
267.50 +* The routine returns a pointer to the matrix created. */
267.51 +
267.52 +SPM *spm_create_mat(int m, int n)
267.53 +{ SPM *A;
267.54 + xassert(0 <= m && m < INT_MAX);
267.55 + xassert(0 <= n && n < INT_MAX);
267.56 + A = xmalloc(sizeof(SPM));
267.57 + A->m = m;
267.58 + A->n = n;
267.59 + if (m == 0 || n == 0)
267.60 + { A->pool = NULL;
267.61 + A->row = NULL;
267.62 + A->col = NULL;
267.63 + }
267.64 + else
267.65 + { int i, j;
267.66 + A->pool = dmp_create_pool();
267.67 + A->row = xcalloc(1+m, sizeof(SPME *));
267.68 + for (i = 1; i <= m; i++) A->row[i] = NULL;
267.69 + A->col = xcalloc(1+n, sizeof(SPME *));
267.70 + for (j = 1; j <= n; j++) A->col[j] = NULL;
267.71 + }
267.72 + return A;
267.73 +}
267.74 +
267.75 +/***********************************************************************
267.76 +* NAME
267.77 +*
267.78 +* spm_new_elem - add new element to sparse matrix
267.79 +*
267.80 +* SYNOPSIS
267.81 +*
267.82 +* #include "glpspm.h"
267.83 +* SPME *spm_new_elem(SPM *A, int i, int j, double val);
267.84 +*
267.85 +* DESCRIPTION
267.86 +*
267.87 +* The routine spm_new_elem adds a new element to the specified sparse
267.88 +* matrix. Parameters i, j, and val specify the row number, the column
267.89 +* number, and a numerical value of the element, respectively.
267.90 +*
267.91 +* RETURNS
267.92 +*
267.93 +* The routine returns a pointer to the new element added. */
267.94 +
267.95 +SPME *spm_new_elem(SPM *A, int i, int j, double val)
267.96 +{ SPME *e;
267.97 + xassert(1 <= i && i <= A->m);
267.98 + xassert(1 <= j && j <= A->n);
267.99 + e = dmp_get_atom(A->pool, sizeof(SPME));
267.100 + e->i = i;
267.101 + e->j = j;
267.102 + e->val = val;
267.103 + e->r_prev = NULL;
267.104 + e->r_next = A->row[i];
267.105 + if (e->r_next != NULL) e->r_next->r_prev = e;
267.106 + e->c_prev = NULL;
267.107 + e->c_next = A->col[j];
267.108 + if (e->c_next != NULL) e->c_next->c_prev = e;
267.109 + A->row[i] = A->col[j] = e;
267.110 + return e;
267.111 +}
267.112 +
267.113 +/***********************************************************************
267.114 +* NAME
267.115 +*
267.116 +* spm_delete_mat - delete general sparse matrix
267.117 +*
267.118 +* SYNOPSIS
267.119 +*
267.120 +* #include "glpspm.h"
267.121 +* void spm_delete_mat(SPM *A);
267.122 +*
267.123 +* DESCRIPTION
267.124 +*
267.125 +* The routine deletes the specified general sparse matrix freeing all
267.126 +* the memory allocated to this object. */
267.127 +
267.128 +void spm_delete_mat(SPM *A)
267.129 +{ /* delete sparse matrix */
267.130 + if (A->pool != NULL) dmp_delete_pool(A->pool);
267.131 + if (A->row != NULL) xfree(A->row);
267.132 + if (A->col != NULL) xfree(A->col);
267.133 + xfree(A);
267.134 + return;
267.135 +}
267.136 +
267.137 +/***********************************************************************
267.138 +* NAME
267.139 +*
267.140 +* spm_test_mat_e - create test sparse matrix of E(n,c) class
267.141 +*
267.142 +* SYNOPSIS
267.143 +*
267.144 +* #include "glpspm.h"
267.145 +* SPM *spm_test_mat_e(int n, int c);
267.146 +*
267.147 +* DESCRIPTION
267.148 +*
267.149 +* The routine spm_test_mat_e creates a test sparse matrix of E(n,c)
267.150 +* class as described in the book: Ole 0sterby, Zahari Zlatev. Direct
267.151 +* Methods for Sparse Matrices. Springer-Verlag, 1983.
267.152 +*
267.153 +* Matrix of E(n,c) class is a symmetric positive definite matrix of
267.154 +* the order n. It has the number 4 on its main diagonal and the number
267.155 +* -1 on its four co-diagonals, two of which are neighbour to the main
267.156 +* diagonal and two others are shifted from the main diagonal on the
267.157 +* distance c.
267.158 +*
267.159 +* It is necessary that n >= 3 and 2 <= c <= n-1.
267.160 +*
267.161 +* RETURNS
267.162 +*
267.163 +* The routine returns a pointer to the matrix created. */
267.164 +
267.165 +SPM *spm_test_mat_e(int n, int c)
267.166 +{ SPM *A;
267.167 + int i;
267.168 + xassert(n >= 3 && 2 <= c && c <= n-1);
267.169 + A = spm_create_mat(n, n);
267.170 + for (i = 1; i <= n; i++)
267.171 + spm_new_elem(A, i, i, 4.0);
267.172 + for (i = 1; i <= n-1; i++)
267.173 + { spm_new_elem(A, i, i+1, -1.0);
267.174 + spm_new_elem(A, i+1, i, -1.0);
267.175 + }
267.176 + for (i = 1; i <= n-c; i++)
267.177 + { spm_new_elem(A, i, i+c, -1.0);
267.178 + spm_new_elem(A, i+c, i, -1.0);
267.179 + }
267.180 + return A;
267.181 +}
267.182 +
267.183 +/***********************************************************************
267.184 +* NAME
267.185 +*
267.186 +* spm_test_mat_d - create test sparse matrix of D(n,c) class
267.187 +*
267.188 +* SYNOPSIS
267.189 +*
267.190 +* #include "glpspm.h"
267.191 +* SPM *spm_test_mat_d(int n, int c);
267.192 +*
267.193 +* DESCRIPTION
267.194 +*
267.195 +* The routine spm_test_mat_d creates a test sparse matrix of D(n,c)
267.196 +* class as described in the book: Ole 0sterby, Zahari Zlatev. Direct
267.197 +* Methods for Sparse Matrices. Springer-Verlag, 1983.
267.198 +*
267.199 +* Matrix of D(n,c) class is a non-singular matrix of the order n. It
267.200 +* has unity main diagonal, three co-diagonals above the main diagonal
267.201 +* on the distance c, which are cyclically continued below the main
267.202 +* diagonal, and a triangle block of the size 10x10 in the upper right
267.203 +* corner.
267.204 +*
267.205 +* It is necessary that n >= 14 and 1 <= c <= n-13.
267.206 +*
267.207 +* RETURNS
267.208 +*
267.209 +* The routine returns a pointer to the matrix created. */
267.210 +
267.211 +SPM *spm_test_mat_d(int n, int c)
267.212 +{ SPM *A;
267.213 + int i, j;
267.214 + xassert(n >= 14 && 1 <= c && c <= n-13);
267.215 + A = spm_create_mat(n, n);
267.216 + for (i = 1; i <= n; i++)
267.217 + spm_new_elem(A, i, i, 1.0);
267.218 + for (i = 1; i <= n-c; i++)
267.219 + spm_new_elem(A, i, i+c, (double)(i+1));
267.220 + for (i = n-c+1; i <= n; i++)
267.221 + spm_new_elem(A, i, i-n+c, (double)(i+1));
267.222 + for (i = 1; i <= n-c-1; i++)
267.223 + spm_new_elem(A, i, i+c+1, (double)(-i));
267.224 + for (i = n-c; i <= n; i++)
267.225 + spm_new_elem(A, i, i-n+c+1, (double)(-i));
267.226 + for (i = 1; i <= n-c-2; i++)
267.227 + spm_new_elem(A, i, i+c+2, 16.0);
267.228 + for (i = n-c-1; i <= n; i++)
267.229 + spm_new_elem(A, i, i-n+c+2, 16.0);
267.230 + for (j = 1; j <= 10; j++)
267.231 + for (i = 1; i <= 11-j; i++)
267.232 + spm_new_elem(A, i, n-11+i+j, 100.0 * (double)j);
267.233 + return A;
267.234 +}
267.235 +
267.236 +/***********************************************************************
267.237 +* NAME
267.238 +*
267.239 +* spm_show_mat - write sparse matrix pattern in BMP file format
267.240 +*
267.241 +* SYNOPSIS
267.242 +*
267.243 +* #include "glpspm.h"
267.244 +* int spm_show_mat(const SPM *A, const char *fname);
267.245 +*
267.246 +* DESCRIPTION
267.247 +*
267.248 +* The routine spm_show_mat writes pattern of the specified sparse
267.249 +* matrix in uncompressed BMP file format (Windows bitmap) to a binary
267.250 +* file whose name is specified by the character string fname.
267.251 +*
267.252 +* Each pixel corresponds to one matrix element. The pixel colors have
267.253 +* the following meaning:
267.254 +*
267.255 +* Black structurally zero element
267.256 +* White positive element
267.257 +* Cyan negative element
267.258 +* Green zero element
267.259 +* Red duplicate element
267.260 +*
267.261 +* RETURNS
267.262 +*
267.263 +* If no error occured, the routine returns zero. Otherwise, it prints
267.264 +* an appropriate error message and returns non-zero. */
267.265 +
267.266 +int spm_show_mat(const SPM *A, const char *fname)
267.267 +{ int m = A->m;
267.268 + int n = A->n;
267.269 + int i, j, k, ret;
267.270 + char *map;
267.271 + xprintf("spm_show_mat: writing matrix pattern to `%s'...\n",
267.272 + fname);
267.273 + xassert(1 <= m && m <= 32767);
267.274 + xassert(1 <= n && n <= 32767);
267.275 + map = xmalloc(m * n);
267.276 + memset(map, 0x08, m * n);
267.277 + for (i = 1; i <= m; i++)
267.278 + { SPME *e;
267.279 + for (e = A->row[i]; e != NULL; e = e->r_next)
267.280 + { j = e->j;
267.281 + xassert(1 <= j && j <= n);
267.282 + k = n * (i - 1) + (j - 1);
267.283 + if (map[k] != 0x08)
267.284 + map[k] = 0x0C;
267.285 + else if (e->val > 0.0)
267.286 + map[k] = 0x0F;
267.287 + else if (e->val < 0.0)
267.288 + map[k] = 0x0B;
267.289 + else
267.290 + map[k] = 0x0A;
267.291 + }
267.292 + }
267.293 + ret = rgr_write_bmp16(fname, m, n, map);
267.294 + xfree(map);
267.295 + return ret;
267.296 +}
267.297 +
267.298 +/***********************************************************************
267.299 +* NAME
267.300 +*
267.301 +* spm_read_hbm - read sparse matrix in Harwell-Boeing format
267.302 +*
267.303 +* SYNOPSIS
267.304 +*
267.305 +* #include "glpspm.h"
267.306 +* SPM *spm_read_hbm(const char *fname);
267.307 +*
267.308 +* DESCRIPTION
267.309 +*
267.310 +* The routine spm_read_hbm reads a sparse matrix in the Harwell-Boeing
267.311 +* format from a text file whose name is the character string fname.
267.312 +*
267.313 +* Detailed description of the Harwell-Boeing format recognised by this
267.314 +* routine can be found in the following report:
267.315 +*
267.316 +* I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the Harwell-Boeing
267.317 +* Sparse Matrix Collection (Release I), TR/PA/92/86, October 1992.
267.318 +*
267.319 +* NOTE
267.320 +*
267.321 +* The routine spm_read_hbm reads the matrix "as is", due to which zero
267.322 +* and/or duplicate elements can appear in the matrix.
267.323 +*
267.324 +* RETURNS
267.325 +*
267.326 +* If no error occured, the routine returns a pointer to the matrix
267.327 +* created. Otherwise, the routine prints an appropriate error message
267.328 +* and returns NULL. */
267.329 +
267.330 +SPM *spm_read_hbm(const char *fname)
267.331 +{ SPM *A = NULL;
267.332 + HBM *hbm;
267.333 + int nrow, ncol, nnzero, i, j, beg, end, ptr, *colptr, *rowind;
267.334 + double val, *values;
267.335 + char *mxtype;
267.336 + hbm = hbm_read_mat(fname);
267.337 + if (hbm == NULL)
267.338 + { xprintf("spm_read_hbm: unable to read matrix\n");
267.339 + goto fini;
267.340 + }
267.341 + mxtype = hbm->mxtype;
267.342 + nrow = hbm->nrow;
267.343 + ncol = hbm->ncol;
267.344 + nnzero = hbm->nnzero;
267.345 + colptr = hbm->colptr;
267.346 + rowind = hbm->rowind;
267.347 + values = hbm->values;
267.348 + if (!(strcmp(mxtype, "RSA") == 0 || strcmp(mxtype, "PSA") == 0 ||
267.349 + strcmp(mxtype, "RUA") == 0 || strcmp(mxtype, "PUA") == 0 ||
267.350 + strcmp(mxtype, "RRA") == 0 || strcmp(mxtype, "PRA") == 0))
267.351 + { xprintf("spm_read_hbm: matrix type `%s' not supported\n",
267.352 + mxtype);
267.353 + goto fini;
267.354 + }
267.355 + A = spm_create_mat(nrow, ncol);
267.356 + if (mxtype[1] == 'S' || mxtype[1] == 'U')
267.357 + xassert(nrow == ncol);
267.358 + for (j = 1; j <= ncol; j++)
267.359 + { beg = colptr[j];
267.360 + end = colptr[j+1];
267.361 + xassert(1 <= beg && beg <= end && end <= nnzero + 1);
267.362 + for (ptr = beg; ptr < end; ptr++)
267.363 + { i = rowind[ptr];
267.364 + xassert(1 <= i && i <= nrow);
267.365 + if (mxtype[0] == 'R')
267.366 + val = values[ptr];
267.367 + else
267.368 + val = 1.0;
267.369 + spm_new_elem(A, i, j, val);
267.370 + if (mxtype[1] == 'S' && i != j)
267.371 + spm_new_elem(A, j, i, val);
267.372 + }
267.373 + }
267.374 +fini: if (hbm != NULL) hbm_free_mat(hbm);
267.375 + return A;
267.376 +}
267.377 +
267.378 +/***********************************************************************
267.379 +* NAME
267.380 +*
267.381 +* spm_count_nnz - determine number of non-zeros in sparse matrix
267.382 +*
267.383 +* SYNOPSIS
267.384 +*
267.385 +* #include "glpspm.h"
267.386 +* int spm_count_nnz(const SPM *A);
267.387 +*
267.388 +* RETURNS
267.389 +*
267.390 +* The routine spm_count_nnz returns the number of structural non-zero
267.391 +* elements in the specified sparse matrix. */
267.392 +
267.393 +int spm_count_nnz(const SPM *A)
267.394 +{ SPME *e;
267.395 + int i, nnz = 0;
267.396 + for (i = 1; i <= A->m; i++)
267.397 + for (e = A->row[i]; e != NULL; e = e->r_next) nnz++;
267.398 + return nnz;
267.399 +}
267.400 +
267.401 +/***********************************************************************
267.402 +* NAME
267.403 +*
267.404 +* spm_drop_zeros - remove zero elements from sparse matrix
267.405 +*
267.406 +* SYNOPSIS
267.407 +*
267.408 +* #include "glpspm.h"
267.409 +* int spm_drop_zeros(SPM *A, double eps);
267.410 +*
267.411 +* DESCRIPTION
267.412 +*
267.413 +* The routine spm_drop_zeros removes all elements from the specified
267.414 +* sparse matrix, whose absolute value is less than eps.
267.415 +*
267.416 +* If the parameter eps is 0, only zero elements are removed from the
267.417 +* matrix.
267.418 +*
267.419 +* RETURNS
267.420 +*
267.421 +* The routine returns the number of elements removed. */
267.422 +
267.423 +int spm_drop_zeros(SPM *A, double eps)
267.424 +{ SPME *e, *next;
267.425 + int i, count = 0;
267.426 + for (i = 1; i <= A->m; i++)
267.427 + { for (e = A->row[i]; e != NULL; e = next)
267.428 + { next = e->r_next;
267.429 + if (e->val == 0.0 || fabs(e->val) < eps)
267.430 + { /* remove element from the row list */
267.431 + if (e->r_prev == NULL)
267.432 + A->row[e->i] = e->r_next;
267.433 + else
267.434 + e->r_prev->r_next = e->r_next;
267.435 + if (e->r_next == NULL)
267.436 + ;
267.437 + else
267.438 + e->r_next->r_prev = e->r_prev;
267.439 + /* remove element from the column list */
267.440 + if (e->c_prev == NULL)
267.441 + A->col[e->j] = e->c_next;
267.442 + else
267.443 + e->c_prev->c_next = e->c_next;
267.444 + if (e->c_next == NULL)
267.445 + ;
267.446 + else
267.447 + e->c_next->c_prev = e->c_prev;
267.448 + /* return element to the memory pool */
267.449 + dmp_free_atom(A->pool, e, sizeof(SPME));
267.450 + count++;
267.451 + }
267.452 + }
267.453 + }
267.454 + return count;
267.455 +}
267.456 +
267.457 +/***********************************************************************
267.458 +* NAME
267.459 +*
267.460 +* spm_read_mat - read sparse matrix from text file
267.461 +*
267.462 +* SYNOPSIS
267.463 +*
267.464 +* #include "glpspm.h"
267.465 +* SPM *spm_read_mat(const char *fname);
267.466 +*
267.467 +* DESCRIPTION
267.468 +*
267.469 +* The routine reads a sparse matrix from a text file whose name is
267.470 +* specified by the parameter fname.
267.471 +*
267.472 +* For the file format see description of the routine spm_write_mat.
267.473 +*
267.474 +* RETURNS
267.475 +*
267.476 +* On success the routine returns a pointer to the matrix created,
267.477 +* otherwise NULL. */
267.478 +
267.479 +#if 1
267.480 +SPM *spm_read_mat(const char *fname)
267.481 +{ xassert(fname != fname);
267.482 + return NULL;
267.483 +}
267.484 +#else
267.485 +SPM *spm_read_mat(const char *fname)
267.486 +{ SPM *A = NULL;
267.487 + PDS *pds;
267.488 + jmp_buf jump;
267.489 + int i, j, k, m, n, nnz, fail = 0;
267.490 + double val;
267.491 + xprintf("spm_read_mat: reading matrix from `%s'...\n", fname);
267.492 + pds = pds_open_file(fname);
267.493 + if (pds == NULL)
267.494 + { xprintf("spm_read_mat: unable to open `%s' - %s\n", fname,
267.495 + strerror(errno));
267.496 + fail = 1;
267.497 + goto done;
267.498 + }
267.499 + if (setjmp(jump))
267.500 + { fail = 1;
267.501 + goto done;
267.502 + }
267.503 + pds_set_jump(pds, jump);
267.504 + /* number of rows, number of columns, number of non-zeros */
267.505 + m = pds_scan_int(pds);
267.506 + if (m < 0)
267.507 + pds_error(pds, "invalid number of rows\n");
267.508 + n = pds_scan_int(pds);
267.509 + if (n < 0)
267.510 + pds_error(pds, "invalid number of columns\n");
267.511 + nnz = pds_scan_int(pds);
267.512 + if (nnz < 0)
267.513 + pds_error(pds, "invalid number of non-zeros\n");
267.514 + /* create matrix */
267.515 + xprintf("spm_read_mat: %d rows, %d columns, %d non-zeros\n",
267.516 + m, n, nnz);
267.517 + A = spm_create_mat(m, n);
267.518 + /* read matrix elements */
267.519 + for (k = 1; k <= nnz; k++)
267.520 + { /* row index, column index, element value */
267.521 + i = pds_scan_int(pds);
267.522 + if (!(1 <= i && i <= m))
267.523 + pds_error(pds, "row index out of range\n");
267.524 + j = pds_scan_int(pds);
267.525 + if (!(1 <= j && j <= n))
267.526 + pds_error(pds, "column index out of range\n");
267.527 + val = pds_scan_num(pds);
267.528 + /* add new element to the matrix */
267.529 + spm_new_elem(A, i, j, val);
267.530 + }
267.531 + xprintf("spm_read_mat: %d lines were read\n", pds->count);
267.532 +done: if (pds != NULL) pds_close_file(pds);
267.533 + if (fail && A != NULL) spm_delete_mat(A), A = NULL;
267.534 + return A;
267.535 +}
267.536 +#endif
267.537 +
267.538 +/***********************************************************************
267.539 +* NAME
267.540 +*
267.541 +* spm_write_mat - write sparse matrix to text file
267.542 +*
267.543 +* SYNOPSIS
267.544 +*
267.545 +* #include "glpspm.h"
267.546 +* int spm_write_mat(const SPM *A, const char *fname);
267.547 +*
267.548 +* DESCRIPTION
267.549 +*
267.550 +* The routine spm_write_mat writes the specified sparse matrix to a
267.551 +* text file whose name is specified by the parameter fname. This file
267.552 +* can be read back with the routine spm_read_mat.
267.553 +*
267.554 +* RETURNS
267.555 +*
267.556 +* On success the routine returns zero, otherwise non-zero.
267.557 +*
267.558 +* FILE FORMAT
267.559 +*
267.560 +* The file created by the routine spm_write_mat is a plain text file,
267.561 +* which contains the following information:
267.562 +*
267.563 +* m n nnz
267.564 +* row[1] col[1] val[1]
267.565 +* row[2] col[2] val[2]
267.566 +* . . .
267.567 +* row[nnz] col[nnz] val[nnz]
267.568 +*
267.569 +* where:
267.570 +* m is the number of rows;
267.571 +* n is the number of columns;
267.572 +* nnz is the number of non-zeros;
267.573 +* row[k], k = 1,...,nnz, are row indices;
267.574 +* col[k], k = 1,...,nnz, are column indices;
267.575 +* val[k], k = 1,...,nnz, are element values. */
267.576 +
267.577 +#if 1
267.578 +int spm_write_mat(const SPM *A, const char *fname)
267.579 +{ xassert(A != A);
267.580 + xassert(fname != fname);
267.581 + return 0;
267.582 +}
267.583 +#else
267.584 +int spm_write_mat(const SPM *A, const char *fname)
267.585 +{ FILE *fp;
267.586 + int i, nnz, ret = 0;
267.587 + xprintf("spm_write_mat: writing matrix to `%s'...\n", fname);
267.588 + fp = fopen(fname, "w");
267.589 + if (fp == NULL)
267.590 + { xprintf("spm_write_mat: unable to create `%s' - %s\n", fname,
267.591 + strerror(errno));
267.592 + ret = 1;
267.593 + goto done;
267.594 + }
267.595 + /* number of rows, number of columns, number of non-zeros */
267.596 + nnz = spm_count_nnz(A);
267.597 + fprintf(fp, "%d %d %d\n", A->m, A->n, nnz);
267.598 + /* walk through rows of the matrix */
267.599 + for (i = 1; i <= A->m; i++)
267.600 + { SPME *e;
267.601 + /* walk through elements of i-th row */
267.602 + for (e = A->row[i]; e != NULL; e = e->r_next)
267.603 + { /* row index, column index, element value */
267.604 + fprintf(fp, "%d %d %.*g\n", e->i, e->j, DBL_DIG, e->val);
267.605 + }
267.606 + }
267.607 + fflush(fp);
267.608 + if (ferror(fp))
267.609 + { xprintf("spm_write_mat: writing error on `%s' - %s\n", fname,
267.610 + strerror(errno));
267.611 + ret = 1;
267.612 + goto done;
267.613 + }
267.614 + xprintf("spm_write_mat: %d lines were written\n", 1 + nnz);
267.615 +done: if (fp != NULL) fclose(fp);
267.616 + return ret;
267.617 +}
267.618 +#endif
267.619 +
267.620 +/***********************************************************************
267.621 +* NAME
267.622 +*
267.623 +* spm_transpose - transpose sparse matrix
267.624 +*
267.625 +* SYNOPSIS
267.626 +*
267.627 +* #include "glpspm.h"
267.628 +* SPM *spm_transpose(const SPM *A);
267.629 +*
267.630 +* RETURNS
267.631 +*
267.632 +* The routine computes and returns sparse matrix B, which is a matrix
267.633 +* transposed to sparse matrix A. */
267.634 +
267.635 +SPM *spm_transpose(const SPM *A)
267.636 +{ SPM *B;
267.637 + int i;
267.638 + B = spm_create_mat(A->n, A->m);
267.639 + for (i = 1; i <= A->m; i++)
267.640 + { SPME *e;
267.641 + for (e = A->row[i]; e != NULL; e = e->r_next)
267.642 + spm_new_elem(B, e->j, i, e->val);
267.643 + }
267.644 + return B;
267.645 +}
267.646 +
267.647 +SPM *spm_add_sym(const SPM *A, const SPM *B)
267.648 +{ /* add two sparse matrices (symbolic phase) */
267.649 + SPM *C;
267.650 + int i, j, *flag;
267.651 + xassert(A->m == B->m);
267.652 + xassert(A->n == B->n);
267.653 + /* create resultant matrix */
267.654 + C = spm_create_mat(A->m, A->n);
267.655 + /* allocate and clear the flag array */
267.656 + flag = xcalloc(1+C->n, sizeof(int));
267.657 + for (j = 1; j <= C->n; j++)
267.658 + flag[j] = 0;
267.659 + /* compute pattern of C = A + B */
267.660 + for (i = 1; i <= C->m; i++)
267.661 + { SPME *e;
267.662 + /* at the beginning i-th row of C is empty */
267.663 + /* (i-th row of C) := (i-th row of C) union (i-th row of A) */
267.664 + for (e = A->row[i]; e != NULL; e = e->r_next)
267.665 + { /* (note that i-th row of A may have duplicate elements) */
267.666 + j = e->j;
267.667 + if (!flag[j])
267.668 + { spm_new_elem(C, i, j, 0.0);
267.669 + flag[j] = 1;
267.670 + }
267.671 + }
267.672 + /* (i-th row of C) := (i-th row of C) union (i-th row of B) */
267.673 + for (e = B->row[i]; e != NULL; e = e->r_next)
267.674 + { /* (note that i-th row of B may have duplicate elements) */
267.675 + j = e->j;
267.676 + if (!flag[j])
267.677 + { spm_new_elem(C, i, j, 0.0);
267.678 + flag[j] = 1;
267.679 + }
267.680 + }
267.681 + /* reset the flag array */
267.682 + for (e = C->row[i]; e != NULL; e = e->r_next)
267.683 + flag[e->j] = 0;
267.684 + }
267.685 + /* check and deallocate the flag array */
267.686 + for (j = 1; j <= C->n; j++)
267.687 + xassert(!flag[j]);
267.688 + xfree(flag);
267.689 + return C;
267.690 +}
267.691 +
267.692 +void spm_add_num(SPM *C, double alfa, const SPM *A, double beta,
267.693 + const SPM *B)
267.694 +{ /* add two sparse matrices (numeric phase) */
267.695 + int i, j;
267.696 + double *work;
267.697 + /* allocate and clear the working array */
267.698 + work = xcalloc(1+C->n, sizeof(double));
267.699 + for (j = 1; j <= C->n; j++)
267.700 + work[j] = 0.0;
267.701 + /* compute matrix C = alfa * A + beta * B */
267.702 + for (i = 1; i <= C->n; i++)
267.703 + { SPME *e;
267.704 + /* work := alfa * (i-th row of A) + beta * (i-th row of B) */
267.705 + /* (note that A and/or B may have duplicate elements) */
267.706 + for (e = A->row[i]; e != NULL; e = e->r_next)
267.707 + work[e->j] += alfa * e->val;
267.708 + for (e = B->row[i]; e != NULL; e = e->r_next)
267.709 + work[e->j] += beta * e->val;
267.710 + /* (i-th row of C) := work, work := 0 */
267.711 + for (e = C->row[i]; e != NULL; e = e->r_next)
267.712 + { j = e->j;
267.713 + e->val = work[j];
267.714 + work[j] = 0.0;
267.715 + }
267.716 + }
267.717 + /* check and deallocate the working array */
267.718 + for (j = 1; j <= C->n; j++)
267.719 + xassert(work[j] == 0.0);
267.720 + xfree(work);
267.721 + return;
267.722 +}
267.723 +
267.724 +SPM *spm_add_mat(double alfa, const SPM *A, double beta, const SPM *B)
267.725 +{ /* add two sparse matrices (driver routine) */
267.726 + SPM *C;
267.727 + C = spm_add_sym(A, B);
267.728 + spm_add_num(C, alfa, A, beta, B);
267.729 + return C;
267.730 +}
267.731 +
267.732 +SPM *spm_mul_sym(const SPM *A, const SPM *B)
267.733 +{ /* multiply two sparse matrices (symbolic phase) */
267.734 + int i, j, k, *flag;
267.735 + SPM *C;
267.736 + xassert(A->n == B->m);
267.737 + /* create resultant matrix */
267.738 + C = spm_create_mat(A->m, B->n);
267.739 + /* allocate and clear the flag array */
267.740 + flag = xcalloc(1+C->n, sizeof(int));
267.741 + for (j = 1; j <= C->n; j++)
267.742 + flag[j] = 0;
267.743 + /* compute pattern of C = A * B */
267.744 + for (i = 1; i <= C->m; i++)
267.745 + { SPME *e, *ee;
267.746 + /* compute pattern of i-th row of C */
267.747 + for (e = A->row[i]; e != NULL; e = e->r_next)
267.748 + { k = e->j;
267.749 + for (ee = B->row[k]; ee != NULL; ee = ee->r_next)
267.750 + { j = ee->j;
267.751 + /* if a[i,k] != 0 and b[k,j] != 0 then c[i,j] != 0 */
267.752 + if (!flag[j])
267.753 + { /* c[i,j] does not exist, so create it */
267.754 + spm_new_elem(C, i, j, 0.0);
267.755 + flag[j] = 1;
267.756 + }
267.757 + }
267.758 + }
267.759 + /* reset the flag array */
267.760 + for (e = C->row[i]; e != NULL; e = e->r_next)
267.761 + flag[e->j] = 0;
267.762 + }
267.763 + /* check and deallocate the flag array */
267.764 + for (j = 1; j <= C->n; j++)
267.765 + xassert(!flag[j]);
267.766 + xfree(flag);
267.767 + return C;
267.768 +}
267.769 +
267.770 +void spm_mul_num(SPM *C, const SPM *A, const SPM *B)
267.771 +{ /* multiply two sparse matrices (numeric phase) */
267.772 + int i, j;
267.773 + double *work;
267.774 + /* allocate and clear the working array */
267.775 + work = xcalloc(1+A->n, sizeof(double));
267.776 + for (j = 1; j <= A->n; j++)
267.777 + work[j] = 0.0;
267.778 + /* compute matrix C = A * B */
267.779 + for (i = 1; i <= C->m; i++)
267.780 + { SPME *e, *ee;
267.781 + double temp;
267.782 + /* work := (i-th row of A) */
267.783 + /* (note that A may have duplicate elements) */
267.784 + for (e = A->row[i]; e != NULL; e = e->r_next)
267.785 + work[e->j] += e->val;
267.786 + /* compute i-th row of C */
267.787 + for (e = C->row[i]; e != NULL; e = e->r_next)
267.788 + { j = e->j;
267.789 + /* c[i,j] := work * (j-th column of B) */
267.790 + temp = 0.0;
267.791 + for (ee = B->col[j]; ee != NULL; ee = ee->c_next)
267.792 + temp += work[ee->i] * ee->val;
267.793 + e->val = temp;
267.794 + }
267.795 + /* reset the working array */
267.796 + for (e = A->row[i]; e != NULL; e = e->r_next)
267.797 + work[e->j] = 0.0;
267.798 + }
267.799 + /* check and deallocate the working array */
267.800 + for (j = 1; j <= A->n; j++)
267.801 + xassert(work[j] == 0.0);
267.802 + xfree(work);
267.803 + return;
267.804 +}
267.805 +
267.806 +SPM *spm_mul_mat(const SPM *A, const SPM *B)
267.807 +{ /* multiply two sparse matrices (driver routine) */
267.808 + SPM *C;
267.809 + C = spm_mul_sym(A, B);
267.810 + spm_mul_num(C, A, B);
267.811 + return C;
267.812 +}
267.813 +
267.814 +PER *spm_create_per(int n)
267.815 +{ /* create permutation matrix */
267.816 + PER *P;
267.817 + int k;
267.818 + xassert(n >= 0);
267.819 + P = xmalloc(sizeof(PER));
267.820 + P->n = n;
267.821 + P->row = xcalloc(1+n, sizeof(int));
267.822 + P->col = xcalloc(1+n, sizeof(int));
267.823 + /* initially it is identity matrix */
267.824 + for (k = 1; k <= n; k++)
267.825 + P->row[k] = P->col[k] = k;
267.826 + return P;
267.827 +}
267.828 +
267.829 +void spm_check_per(PER *P)
267.830 +{ /* check permutation matrix for correctness */
267.831 + int i, j;
267.832 + xassert(P->n >= 0);
267.833 + for (i = 1; i <= P->n; i++)
267.834 + { j = P->row[i];
267.835 + xassert(1 <= j && j <= P->n);
267.836 + xassert(P->col[j] == i);
267.837 + }
267.838 + return;
267.839 +}
267.840 +
267.841 +void spm_delete_per(PER *P)
267.842 +{ /* delete permutation matrix */
267.843 + xfree(P->row);
267.844 + xfree(P->col);
267.845 + xfree(P);
267.846 + return;
267.847 +}
267.848 +
267.849 +/* eof */
268.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
268.2 +++ b/src/glpspm.h Mon Dec 06 13:09:21 2010 +0100
268.3 @@ -0,0 +1,165 @@
268.4 +/* glpspm.h (general sparse matrix) */
268.5 +
268.6 +/***********************************************************************
268.7 +* This code is part of GLPK (GNU Linear Programming Kit).
268.8 +*
268.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
268.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
268.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
268.12 +* E-mail: <mao@gnu.org>.
268.13 +*
268.14 +* GLPK is free software: you can redistribute it and/or modify it
268.15 +* under the terms of the GNU General Public License as published by
268.16 +* the Free Software Foundation, either version 3 of the License, or
268.17 +* (at your option) any later version.
268.18 +*
268.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
268.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
268.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
268.22 +* License for more details.
268.23 +*
268.24 +* You should have received a copy of the GNU General Public License
268.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
268.26 +***********************************************************************/
268.27 +
268.28 +#ifndef GLPSPM_H
268.29 +#define GLPSPM_H
268.30 +
268.31 +#include "glpdmp.h"
268.32 +
268.33 +typedef struct SPM SPM;
268.34 +typedef struct SPME SPME;
268.35 +
268.36 +struct SPM
268.37 +{ /* general sparse matrix */
268.38 + int m;
268.39 + /* number of rows, m >= 0 */
268.40 + int n;
268.41 + /* number of columns, n >= 0 */
268.42 + DMP *pool;
268.43 + /* memory pool to store matrix elements */
268.44 + SPME **row; /* SPME *row[1+m]; */
268.45 + /* row[i], 1 <= i <= m, is a pointer to i-th row list */
268.46 + SPME **col; /* SPME *col[1+n]; */
268.47 + /* col[j], 1 <= j <= n, is a pointer to j-th column list */
268.48 +};
268.49 +
268.50 +struct SPME
268.51 +{ /* sparse matrix element */
268.52 + int i;
268.53 + /* row number */
268.54 + int j;
268.55 + /* column number */
268.56 + double val;
268.57 + /* element value */
268.58 + SPME *r_prev;
268.59 + /* pointer to previous element in the same row */
268.60 + SPME *r_next;
268.61 + /* pointer to next element in the same row */
268.62 + SPME *c_prev;
268.63 + /* pointer to previous element in the same column */
268.64 + SPME *c_next;
268.65 + /* pointer to next element in the same column */
268.66 +};
268.67 +
268.68 +typedef struct PER PER;
268.69 +
268.70 +struct PER
268.71 +{ /* permutation matrix */
268.72 + int n;
268.73 + /* matrix order, n >= 0 */
268.74 + int *row; /* int row[1+n]; */
268.75 + /* row[i] = j means p[i,j] = 1 */
268.76 + int *col; /* int col[1+n]; */
268.77 + /* col[j] = i means p[i,j] = 1 */
268.78 +};
268.79 +
268.80 +#define spm_create_mat _glp_spm_create_mat
268.81 +SPM *spm_create_mat(int m, int n);
268.82 +/* create general sparse matrix */
268.83 +
268.84 +#define spm_new_elem _glp_spm_new_elem
268.85 +SPME *spm_new_elem(SPM *A, int i, int j, double val);
268.86 +/* add new element to sparse matrix */
268.87 +
268.88 +#define spm_delete_mat _glp_spm_delete_mat
268.89 +void spm_delete_mat(SPM *A);
268.90 +/* delete general sparse matrix */
268.91 +
268.92 +#define spm_test_mat_e _glp_spm_test_mat_e
268.93 +SPM *spm_test_mat_e(int n, int c);
268.94 +/* create test sparse matrix of E(n,c) class */
268.95 +
268.96 +#define spm_test_mat_d _glp_spm_test_mat_d
268.97 +SPM *spm_test_mat_d(int n, int c);
268.98 +/* create test sparse matrix of D(n,c) class */
268.99 +
268.100 +#define spm_show_mat _glp_spm_show_mat
268.101 +int spm_show_mat(const SPM *A, const char *fname);
268.102 +/* write sparse matrix pattern in BMP file format */
268.103 +
268.104 +#define spm_read_hbm _glp_spm_read_hbm
268.105 +SPM *spm_read_hbm(const char *fname);
268.106 +/* read sparse matrix in Harwell-Boeing format */
268.107 +
268.108 +#define spm_count_nnz _glp_spm_count_nnz
268.109 +int spm_count_nnz(const SPM *A);
268.110 +/* determine number of non-zeros in sparse matrix */
268.111 +
268.112 +#define spm_drop_zeros _glp_spm_drop_zeros
268.113 +int spm_drop_zeros(SPM *A, double eps);
268.114 +/* remove zero elements from sparse matrix */
268.115 +
268.116 +#define spm_read_mat _glp_spm_read_mat
268.117 +SPM *spm_read_mat(const char *fname);
268.118 +/* read sparse matrix from text file */
268.119 +
268.120 +#define spm_write_mat _glp_spm_write_mat
268.121 +int spm_write_mat(const SPM *A, const char *fname);
268.122 +/* write sparse matrix to text file */
268.123 +
268.124 +#define spm_transpose _glp_spm_transpose
268.125 +SPM *spm_transpose(const SPM *A);
268.126 +/* transpose sparse matrix */
268.127 +
268.128 +#define spm_add_sym _glp_spm_add_sym
268.129 +SPM *spm_add_sym(const SPM *A, const SPM *B);
268.130 +/* add two sparse matrices (symbolic phase) */
268.131 +
268.132 +#define spm_add_num _glp_spm_add_num
268.133 +void spm_add_num(SPM *C, double alfa, const SPM *A, double beta,
268.134 + const SPM *B);
268.135 +/* add two sparse matrices (numeric phase) */
268.136 +
268.137 +#define spm_add_mat _glp_spm_add_mat
268.138 +SPM *spm_add_mat(double alfa, const SPM *A, double beta,
268.139 + const SPM *B);
268.140 +/* add two sparse matrices (driver routine) */
268.141 +
268.142 +#define spm_mul_sym _glp_spm_mul_sym
268.143 +SPM *spm_mul_sym(const SPM *A, const SPM *B);
268.144 +/* multiply two sparse matrices (symbolic phase) */
268.145 +
268.146 +#define spm_mul_num _glp_spm_mul_num
268.147 +void spm_mul_num(SPM *C, const SPM *A, const SPM *B);
268.148 +/* multiply two sparse matrices (numeric phase) */
268.149 +
268.150 +#define spm_mul_mat _glp_spm_mul_mat
268.151 +SPM *spm_mul_mat(const SPM *A, const SPM *B);
268.152 +/* multiply two sparse matrices (driver routine) */
268.153 +
268.154 +#define spm_create_per _glp_spm_create_per
268.155 +PER *spm_create_per(int n);
268.156 +/* create permutation matrix */
268.157 +
268.158 +#define spm_check_per _glp_spm_check_per
268.159 +void spm_check_per(PER *P);
268.160 +/* check permutation matrix for correctness */
268.161 +
268.162 +#define spm_delete_per _glp_spm_delete_per
268.163 +void spm_delete_per(PER *P);
268.164 +/* delete permutation matrix */
268.165 +
268.166 +#endif
268.167 +
268.168 +/* eof */
269.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
269.2 +++ b/src/glpspx.h Mon Dec 06 13:09:21 2010 +0100
269.3 @@ -0,0 +1,40 @@
269.4 +/* glpspx.h (core simplex solvers) */
269.5 +
269.6 +/***********************************************************************
269.7 +* This code is part of GLPK (GNU Linear Programming Kit).
269.8 +*
269.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
269.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
269.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
269.12 +* E-mail: <mao@gnu.org>.
269.13 +*
269.14 +* GLPK is free software: you can redistribute it and/or modify it
269.15 +* under the terms of the GNU General Public License as published by
269.16 +* the Free Software Foundation, either version 3 of the License, or
269.17 +* (at your option) any later version.
269.18 +*
269.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
269.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
269.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
269.22 +* License for more details.
269.23 +*
269.24 +* You should have received a copy of the GNU General Public License
269.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
269.26 +***********************************************************************/
269.27 +
269.28 +#ifndef GLPSPX_H
269.29 +#define GLPSPX_H
269.30 +
269.31 +#include "glpapi.h"
269.32 +
269.33 +#define spx_primal _glp_spx_primal
269.34 +int spx_primal(glp_prob *lp, const glp_smcp *parm);
269.35 +/* core LP solver based on the primal simplex method */
269.36 +
269.37 +#define spx_dual _glp_spx_dual
269.38 +int spx_dual(glp_prob *lp, const glp_smcp *parm);
269.39 +/* core LP solver based on the dual simplex method */
269.40 +
269.41 +#endif
269.42 +
269.43 +/* eof */
270.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
270.2 +++ b/src/glpspx01.c Mon Dec 06 13:09:21 2010 +0100
270.3 @@ -0,0 +1,2954 @@
270.4 +/* glpspx01.c (primal simplex method) */
270.5 +
270.6 +/***********************************************************************
270.7 +* This code is part of GLPK (GNU Linear Programming Kit).
270.8 +*
270.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
270.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
270.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
270.12 +* E-mail: <mao@gnu.org>.
270.13 +*
270.14 +* GLPK is free software: you can redistribute it and/or modify it
270.15 +* under the terms of the GNU General Public License as published by
270.16 +* the Free Software Foundation, either version 3 of the License, or
270.17 +* (at your option) any later version.
270.18 +*
270.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
270.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
270.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
270.22 +* License for more details.
270.23 +*
270.24 +* You should have received a copy of the GNU General Public License
270.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
270.26 +***********************************************************************/
270.27 +
270.28 +#include "glpspx.h"
270.29 +
270.30 +struct csa
270.31 +{ /* common storage area */
270.32 + /*--------------------------------------------------------------*/
270.33 + /* LP data */
270.34 + int m;
270.35 + /* number of rows (auxiliary variables), m > 0 */
270.36 + int n;
270.37 + /* number of columns (structural variables), n > 0 */
270.38 + char *type; /* char type[1+m+n]; */
270.39 + /* type[0] is not used;
270.40 + type[k], 1 <= k <= m+n, is the type of variable x[k]:
270.41 + GLP_FR - free variable
270.42 + GLP_LO - variable with lower bound
270.43 + GLP_UP - variable with upper bound
270.44 + GLP_DB - double-bounded variable
270.45 + GLP_FX - fixed variable */
270.46 + double *lb; /* double lb[1+m+n]; */
270.47 + /* lb[0] is not used;
270.48 + lb[k], 1 <= k <= m+n, is an lower bound of variable x[k];
270.49 + if x[k] has no lower bound, lb[k] is zero */
270.50 + double *ub; /* double ub[1+m+n]; */
270.51 + /* ub[0] is not used;
270.52 + ub[k], 1 <= k <= m+n, is an upper bound of variable x[k];
270.53 + if x[k] has no upper bound, ub[k] is zero;
270.54 + if x[k] is of fixed type, ub[k] is the same as lb[k] */
270.55 + double *coef; /* double coef[1+m+n]; */
270.56 + /* coef[0] is not used;
270.57 + coef[k], 1 <= k <= m+n, is an objective coefficient at
270.58 + variable x[k] (note that on phase I auxiliary variables also
270.59 + may have non-zero objective coefficients) */
270.60 + /*--------------------------------------------------------------*/
270.61 + /* original objective function */
270.62 + double *obj; /* double obj[1+n]; */
270.63 + /* obj[0] is a constant term of the original objective function;
270.64 + obj[j], 1 <= j <= n, is an original objective coefficient at
270.65 + structural variable x[m+j] */
270.66 + double zeta;
270.67 + /* factor used to scale original objective coefficients; its
270.68 + sign defines original optimization direction: zeta > 0 means
270.69 + minimization, zeta < 0 means maximization */
270.70 + /*--------------------------------------------------------------*/
270.71 + /* constraint matrix A; it has m rows and n columns and is stored
270.72 + by columns */
270.73 + int *A_ptr; /* int A_ptr[1+n+1]; */
270.74 + /* A_ptr[0] is not used;
270.75 + A_ptr[j], 1 <= j <= n, is starting position of j-th column in
270.76 + arrays A_ind and A_val; note that A_ptr[1] is always 1;
270.77 + A_ptr[n+1] indicates the position after the last element in
270.78 + arrays A_ind and A_val */
270.79 + int *A_ind; /* int A_ind[A_ptr[n+1]]; */
270.80 + /* row indices */
270.81 + double *A_val; /* double A_val[A_ptr[n+1]]; */
270.82 + /* non-zero element values */
270.83 + /*--------------------------------------------------------------*/
270.84 + /* basis header */
270.85 + int *head; /* int head[1+m+n]; */
270.86 + /* head[0] is not used;
270.87 + head[i], 1 <= i <= m, is the ordinal number of basic variable
270.88 + xB[i]; head[i] = k means that xB[i] = x[k] and i-th column of
270.89 + matrix B is k-th column of matrix (I|-A);
270.90 + head[m+j], 1 <= j <= n, is the ordinal number of non-basic
270.91 + variable xN[j]; head[m+j] = k means that xN[j] = x[k] and j-th
270.92 + column of matrix N is k-th column of matrix (I|-A) */
270.93 + char *stat; /* char stat[1+n]; */
270.94 + /* stat[0] is not used;
270.95 + stat[j], 1 <= j <= n, is the status of non-basic variable
270.96 + xN[j], which defines its active bound:
270.97 + GLP_NL - lower bound is active
270.98 + GLP_NU - upper bound is active
270.99 + GLP_NF - free variable
270.100 + GLP_NS - fixed variable */
270.101 + /*--------------------------------------------------------------*/
270.102 + /* matrix B is the basis matrix; it is composed from columns of
270.103 + the augmented constraint matrix (I|-A) corresponding to basic
270.104 + variables and stored in a factorized (invertable) form */
270.105 + int valid;
270.106 + /* factorization is valid only if this flag is set */
270.107 + BFD *bfd; /* BFD bfd[1:m,1:m]; */
270.108 + /* factorized (invertable) form of the basis matrix */
270.109 + /*--------------------------------------------------------------*/
270.110 + /* matrix N is a matrix composed from columns of the augmented
270.111 + constraint matrix (I|-A) corresponding to non-basic variables
270.112 + except fixed ones; it is stored by rows and changes every time
270.113 + the basis changes */
270.114 + int *N_ptr; /* int N_ptr[1+m+1]; */
270.115 + /* N_ptr[0] is not used;
270.116 + N_ptr[i], 1 <= i <= m, is starting position of i-th row in
270.117 + arrays N_ind and N_val; note that N_ptr[1] is always 1;
270.118 + N_ptr[m+1] indicates the position after the last element in
270.119 + arrays N_ind and N_val */
270.120 + int *N_len; /* int N_len[1+m]; */
270.121 + /* N_len[0] is not used;
270.122 + N_len[i], 1 <= i <= m, is length of i-th row (0 to n) */
270.123 + int *N_ind; /* int N_ind[N_ptr[m+1]]; */
270.124 + /* column indices */
270.125 + double *N_val; /* double N_val[N_ptr[m+1]]; */
270.126 + /* non-zero element values */
270.127 + /*--------------------------------------------------------------*/
270.128 + /* working parameters */
270.129 + int phase;
270.130 + /* search phase:
270.131 + 0 - not determined yet
270.132 + 1 - search for primal feasible solution
270.133 + 2 - search for optimal solution */
270.134 + glp_long tm_beg;
270.135 + /* time value at the beginning of the search */
270.136 + int it_beg;
270.137 + /* simplex iteration count at the beginning of the search */
270.138 + int it_cnt;
270.139 + /* simplex iteration count; it increases by one every time the
270.140 + basis changes (including the case when a non-basic variable
270.141 + jumps to its opposite bound) */
270.142 + int it_dpy;
270.143 + /* simplex iteration count at the most recent display output */
270.144 + /*--------------------------------------------------------------*/
270.145 + /* basic solution components */
270.146 + double *bbar; /* double bbar[1+m]; */
270.147 + /* bbar[0] is not used;
270.148 + bbar[i], 1 <= i <= m, is primal value of basic variable xB[i]
270.149 + (if xB[i] is free, its primal value is not updated) */
270.150 + double *cbar; /* double cbar[1+n]; */
270.151 + /* cbar[0] is not used;
270.152 + cbar[j], 1 <= j <= n, is reduced cost of non-basic variable
270.153 + xN[j] (if xN[j] is fixed, its reduced cost is not updated) */
270.154 + /*--------------------------------------------------------------*/
270.155 + /* the following pricing technique options may be used:
270.156 + GLP_PT_STD - standard ("textbook") pricing;
270.157 + GLP_PT_PSE - projected steepest edge;
270.158 + GLP_PT_DVX - Devex pricing (not implemented yet);
270.159 + in case of GLP_PT_STD the reference space is not used, and all
270.160 + steepest edge coefficients are set to 1 */
270.161 + int refct;
270.162 + /* this count is set to an initial value when the reference space
270.163 + is defined and decreases by one every time the basis changes;
270.164 + once this count reaches zero, the reference space is redefined
270.165 + again */
270.166 + char *refsp; /* char refsp[1+m+n]; */
270.167 + /* refsp[0] is not used;
270.168 + refsp[k], 1 <= k <= m+n, is the flag which means that variable
270.169 + x[k] belongs to the current reference space */
270.170 + double *gamma; /* double gamma[1+n]; */
270.171 + /* gamma[0] is not used;
270.172 + gamma[j], 1 <= j <= n, is the steepest edge coefficient for
270.173 + non-basic variable xN[j]; if xN[j] is fixed, gamma[j] is not
270.174 + used and just set to 1 */
270.175 + /*--------------------------------------------------------------*/
270.176 + /* non-basic variable xN[q] chosen to enter the basis */
270.177 + int q;
270.178 + /* index of the non-basic variable xN[q] chosen, 1 <= q <= n;
270.179 + if the set of eligible non-basic variables is empty and thus
270.180 + no variable has been chosen, q is set to 0 */
270.181 + /*--------------------------------------------------------------*/
270.182 + /* pivot column of the simplex table corresponding to non-basic
270.183 + variable xN[q] chosen is the following vector:
270.184 + T * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q],
270.185 + where B is the current basis matrix, N[q] is a column of the
270.186 + matrix (I|-A) corresponding to xN[q] */
270.187 + int tcol_nnz;
270.188 + /* number of non-zero components, 0 <= nnz <= m */
270.189 + int *tcol_ind; /* int tcol_ind[1+m]; */
270.190 + /* tcol_ind[0] is not used;
270.191 + tcol_ind[t], 1 <= t <= nnz, is an index of non-zero component,
270.192 + i.e. tcol_ind[t] = i means that tcol_vec[i] != 0 */
270.193 + double *tcol_vec; /* double tcol_vec[1+m]; */
270.194 + /* tcol_vec[0] is not used;
270.195 + tcol_vec[i], 1 <= i <= m, is a numeric value of i-th component
270.196 + of the column */
270.197 + double tcol_max;
270.198 + /* infinity (maximum) norm of the column (max |tcol_vec[i]|) */
270.199 + int tcol_num;
270.200 + /* number of significant non-zero components, which means that:
270.201 + |tcol_vec[i]| >= eps for i in tcol_ind[1,...,num],
270.202 + |tcol_vec[i]| < eps for i in tcol_ind[num+1,...,nnz],
270.203 + where eps is a pivot tolerance */
270.204 + /*--------------------------------------------------------------*/
270.205 + /* basic variable xB[p] chosen to leave the basis */
270.206 + int p;
270.207 + /* index of the basic variable xB[p] chosen, 1 <= p <= m;
270.208 + p = 0 means that no basic variable reaches its bound;
270.209 + p < 0 means that non-basic variable xN[q] reaches its opposite
270.210 + bound before any basic variable */
270.211 + int p_stat;
270.212 + /* new status (GLP_NL, GLP_NU, or GLP_NS) to be assigned to xB[p]
270.213 + once it has left the basis */
270.214 + double teta;
270.215 + /* change of non-basic variable xN[q] (see above), on which xB[p]
270.216 + (or, if p < 0, xN[q] itself) reaches its bound */
270.217 + /*--------------------------------------------------------------*/
270.218 + /* pivot row of the simplex table corresponding to basic variable
270.219 + xB[p] chosen is the following vector:
270.220 + T' * e[p] = - N' * inv(B') * e[p] = - N' * rho,
270.221 + where B' is a matrix transposed to the current basis matrix,
270.222 + N' is a matrix, whose rows are columns of the matrix (I|-A)
270.223 + corresponding to non-basic non-fixed variables */
270.224 + int trow_nnz;
270.225 + /* number of non-zero components, 0 <= nnz <= n */
270.226 + int *trow_ind; /* int trow_ind[1+n]; */
270.227 + /* trow_ind[0] is not used;
270.228 + trow_ind[t], 1 <= t <= nnz, is an index of non-zero component,
270.229 + i.e. trow_ind[t] = j means that trow_vec[j] != 0 */
270.230 + double *trow_vec; /* int trow_vec[1+n]; */
270.231 + /* trow_vec[0] is not used;
270.232 + trow_vec[j], 1 <= j <= n, is a numeric value of j-th component
270.233 + of the row */
270.234 + /*--------------------------------------------------------------*/
270.235 + /* working arrays */
270.236 + double *work1; /* double work1[1+m]; */
270.237 + double *work2; /* double work2[1+m]; */
270.238 + double *work3; /* double work3[1+m]; */
270.239 + double *work4; /* double work4[1+m]; */
270.240 +};
270.241 +
270.242 +static const double kappa = 0.10;
270.243 +
270.244 +/***********************************************************************
270.245 +* alloc_csa - allocate common storage area
270.246 +*
270.247 +* This routine allocates all arrays in the common storage area (CSA)
270.248 +* and returns a pointer to the CSA. */
270.249 +
270.250 +static struct csa *alloc_csa(glp_prob *lp)
270.251 +{ struct csa *csa;
270.252 + int m = lp->m;
270.253 + int n = lp->n;
270.254 + int nnz = lp->nnz;
270.255 + csa = xmalloc(sizeof(struct csa));
270.256 + xassert(m > 0 && n > 0);
270.257 + csa->m = m;
270.258 + csa->n = n;
270.259 + csa->type = xcalloc(1+m+n, sizeof(char));
270.260 + csa->lb = xcalloc(1+m+n, sizeof(double));
270.261 + csa->ub = xcalloc(1+m+n, sizeof(double));
270.262 + csa->coef = xcalloc(1+m+n, sizeof(double));
270.263 + csa->obj = xcalloc(1+n, sizeof(double));
270.264 + csa->A_ptr = xcalloc(1+n+1, sizeof(int));
270.265 + csa->A_ind = xcalloc(1+nnz, sizeof(int));
270.266 + csa->A_val = xcalloc(1+nnz, sizeof(double));
270.267 + csa->head = xcalloc(1+m+n, sizeof(int));
270.268 + csa->stat = xcalloc(1+n, sizeof(char));
270.269 + csa->N_ptr = xcalloc(1+m+1, sizeof(int));
270.270 + csa->N_len = xcalloc(1+m, sizeof(int));
270.271 + csa->N_ind = NULL; /* will be allocated later */
270.272 + csa->N_val = NULL; /* will be allocated later */
270.273 + csa->bbar = xcalloc(1+m, sizeof(double));
270.274 + csa->cbar = xcalloc(1+n, sizeof(double));
270.275 + csa->refsp = xcalloc(1+m+n, sizeof(char));
270.276 + csa->gamma = xcalloc(1+n, sizeof(double));
270.277 + csa->tcol_ind = xcalloc(1+m, sizeof(int));
270.278 + csa->tcol_vec = xcalloc(1+m, sizeof(double));
270.279 + csa->trow_ind = xcalloc(1+n, sizeof(int));
270.280 + csa->trow_vec = xcalloc(1+n, sizeof(double));
270.281 + csa->work1 = xcalloc(1+m, sizeof(double));
270.282 + csa->work2 = xcalloc(1+m, sizeof(double));
270.283 + csa->work3 = xcalloc(1+m, sizeof(double));
270.284 + csa->work4 = xcalloc(1+m, sizeof(double));
270.285 + return csa;
270.286 +}
270.287 +
270.288 +/***********************************************************************
270.289 +* init_csa - initialize common storage area
270.290 +*
270.291 +* This routine initializes all data structures in the common storage
270.292 +* area (CSA). */
270.293 +
270.294 +static void alloc_N(struct csa *csa);
270.295 +static void build_N(struct csa *csa);
270.296 +
270.297 +static void init_csa(struct csa *csa, glp_prob *lp)
270.298 +{ int m = csa->m;
270.299 + int n = csa->n;
270.300 + char *type = csa->type;
270.301 + double *lb = csa->lb;
270.302 + double *ub = csa->ub;
270.303 + double *coef = csa->coef;
270.304 + double *obj = csa->obj;
270.305 + int *A_ptr = csa->A_ptr;
270.306 + int *A_ind = csa->A_ind;
270.307 + double *A_val = csa->A_val;
270.308 + int *head = csa->head;
270.309 + char *stat = csa->stat;
270.310 + char *refsp = csa->refsp;
270.311 + double *gamma = csa->gamma;
270.312 + int i, j, k, loc;
270.313 + double cmax;
270.314 + /* auxiliary variables */
270.315 + for (i = 1; i <= m; i++)
270.316 + { GLPROW *row = lp->row[i];
270.317 + type[i] = (char)row->type;
270.318 + lb[i] = row->lb * row->rii;
270.319 + ub[i] = row->ub * row->rii;
270.320 + coef[i] = 0.0;
270.321 + }
270.322 + /* structural variables */
270.323 + for (j = 1; j <= n; j++)
270.324 + { GLPCOL *col = lp->col[j];
270.325 + type[m+j] = (char)col->type;
270.326 + lb[m+j] = col->lb / col->sjj;
270.327 + ub[m+j] = col->ub / col->sjj;
270.328 + coef[m+j] = col->coef * col->sjj;
270.329 + }
270.330 + /* original objective function */
270.331 + obj[0] = lp->c0;
270.332 + memcpy(&obj[1], &coef[m+1], n * sizeof(double));
270.333 + /* factor used to scale original objective coefficients */
270.334 + cmax = 0.0;
270.335 + for (j = 1; j <= n; j++)
270.336 + if (cmax < fabs(obj[j])) cmax = fabs(obj[j]);
270.337 + if (cmax == 0.0) cmax = 1.0;
270.338 + switch (lp->dir)
270.339 + { case GLP_MIN:
270.340 + csa->zeta = + 1.0 / cmax;
270.341 + break;
270.342 + case GLP_MAX:
270.343 + csa->zeta = - 1.0 / cmax;
270.344 + break;
270.345 + default:
270.346 + xassert(lp != lp);
270.347 + }
270.348 +#if 1
270.349 + if (fabs(csa->zeta) < 1.0) csa->zeta *= 1000.0;
270.350 +#endif
270.351 + /* matrix A (by columns) */
270.352 + loc = 1;
270.353 + for (j = 1; j <= n; j++)
270.354 + { GLPAIJ *aij;
270.355 + A_ptr[j] = loc;
270.356 + for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
270.357 + { A_ind[loc] = aij->row->i;
270.358 + A_val[loc] = aij->row->rii * aij->val * aij->col->sjj;
270.359 + loc++;
270.360 + }
270.361 + }
270.362 + A_ptr[n+1] = loc;
270.363 + xassert(loc == lp->nnz+1);
270.364 + /* basis header */
270.365 + xassert(lp->valid);
270.366 + memcpy(&head[1], &lp->head[1], m * sizeof(int));
270.367 + k = 0;
270.368 + for (i = 1; i <= m; i++)
270.369 + { GLPROW *row = lp->row[i];
270.370 + if (row->stat != GLP_BS)
270.371 + { k++;
270.372 + xassert(k <= n);
270.373 + head[m+k] = i;
270.374 + stat[k] = (char)row->stat;
270.375 + }
270.376 + }
270.377 + for (j = 1; j <= n; j++)
270.378 + { GLPCOL *col = lp->col[j];
270.379 + if (col->stat != GLP_BS)
270.380 + { k++;
270.381 + xassert(k <= n);
270.382 + head[m+k] = m + j;
270.383 + stat[k] = (char)col->stat;
270.384 + }
270.385 + }
270.386 + xassert(k == n);
270.387 + /* factorization of matrix B */
270.388 + csa->valid = 1, lp->valid = 0;
270.389 + csa->bfd = lp->bfd, lp->bfd = NULL;
270.390 + /* matrix N (by rows) */
270.391 + alloc_N(csa);
270.392 + build_N(csa);
270.393 + /* working parameters */
270.394 + csa->phase = 0;
270.395 + csa->tm_beg = xtime();
270.396 + csa->it_beg = csa->it_cnt = lp->it_cnt;
270.397 + csa->it_dpy = -1;
270.398 + /* reference space and steepest edge coefficients */
270.399 + csa->refct = 0;
270.400 + memset(&refsp[1], 0, (m+n) * sizeof(char));
270.401 + for (j = 1; j <= n; j++) gamma[j] = 1.0;
270.402 + return;
270.403 +}
270.404 +
270.405 +/***********************************************************************
270.406 +* invert_B - compute factorization of the basis matrix
270.407 +*
270.408 +* This routine computes factorization of the current basis matrix B.
270.409 +*
270.410 +* If the operation is successful, the routine returns zero, otherwise
270.411 +* non-zero. */
270.412 +
270.413 +static int inv_col(void *info, int i, int ind[], double val[])
270.414 +{ /* this auxiliary routine returns row indices and numeric values
270.415 + of non-zero elements of i-th column of the basis matrix */
270.416 + struct csa *csa = info;
270.417 + int m = csa->m;
270.418 +#ifdef GLP_DEBUG
270.419 + int n = csa->n;
270.420 +#endif
270.421 + int *A_ptr = csa->A_ptr;
270.422 + int *A_ind = csa->A_ind;
270.423 + double *A_val = csa->A_val;
270.424 + int *head = csa->head;
270.425 + int k, len, ptr, t;
270.426 +#ifdef GLP_DEBUG
270.427 + xassert(1 <= i && i <= m);
270.428 +#endif
270.429 + k = head[i]; /* B[i] is k-th column of (I|-A) */
270.430 +#ifdef GLP_DEBUG
270.431 + xassert(1 <= k && k <= m+n);
270.432 +#endif
270.433 + if (k <= m)
270.434 + { /* B[i] is k-th column of submatrix I */
270.435 + len = 1;
270.436 + ind[1] = k;
270.437 + val[1] = 1.0;
270.438 + }
270.439 + else
270.440 + { /* B[i] is (k-m)-th column of submatrix (-A) */
270.441 + ptr = A_ptr[k-m];
270.442 + len = A_ptr[k-m+1] - ptr;
270.443 + memcpy(&ind[1], &A_ind[ptr], len * sizeof(int));
270.444 + memcpy(&val[1], &A_val[ptr], len * sizeof(double));
270.445 + for (t = 1; t <= len; t++) val[t] = - val[t];
270.446 + }
270.447 + return len;
270.448 +}
270.449 +
270.450 +static int invert_B(struct csa *csa)
270.451 +{ int ret;
270.452 + ret = bfd_factorize(csa->bfd, csa->m, NULL, inv_col, csa);
270.453 + csa->valid = (ret == 0);
270.454 + return ret;
270.455 +}
270.456 +
270.457 +/***********************************************************************
270.458 +* update_B - update factorization of the basis matrix
270.459 +*
270.460 +* This routine replaces i-th column of the basis matrix B by k-th
270.461 +* column of the augmented constraint matrix (I|-A) and then updates
270.462 +* the factorization of B.
270.463 +*
270.464 +* If the factorization has been successfully updated, the routine
270.465 +* returns zero, otherwise non-zero. */
270.466 +
270.467 +static int update_B(struct csa *csa, int i, int k)
270.468 +{ int m = csa->m;
270.469 +#ifdef GLP_DEBUG
270.470 + int n = csa->n;
270.471 +#endif
270.472 + int ret;
270.473 +#ifdef GLP_DEBUG
270.474 + xassert(1 <= i && i <= m);
270.475 + xassert(1 <= k && k <= m+n);
270.476 +#endif
270.477 + if (k <= m)
270.478 + { /* new i-th column of B is k-th column of I */
270.479 + int ind[1+1];
270.480 + double val[1+1];
270.481 + ind[1] = k;
270.482 + val[1] = 1.0;
270.483 + xassert(csa->valid);
270.484 + ret = bfd_update_it(csa->bfd, i, 0, 1, ind, val);
270.485 + }
270.486 + else
270.487 + { /* new i-th column of B is (k-m)-th column of (-A) */
270.488 + int *A_ptr = csa->A_ptr;
270.489 + int *A_ind = csa->A_ind;
270.490 + double *A_val = csa->A_val;
270.491 + double *val = csa->work1;
270.492 + int beg, end, ptr, len;
270.493 + beg = A_ptr[k-m];
270.494 + end = A_ptr[k-m+1];
270.495 + len = 0;
270.496 + for (ptr = beg; ptr < end; ptr++)
270.497 + val[++len] = - A_val[ptr];
270.498 + xassert(csa->valid);
270.499 + ret = bfd_update_it(csa->bfd, i, 0, len, &A_ind[beg-1], val);
270.500 + }
270.501 + csa->valid = (ret == 0);
270.502 + return ret;
270.503 +}
270.504 +
270.505 +/***********************************************************************
270.506 +* error_ftran - compute residual vector r = h - B * x
270.507 +*
270.508 +* This routine computes the residual vector r = h - B * x, where B is
270.509 +* the current basis matrix, h is the vector of right-hand sides, x is
270.510 +* the solution vector. */
270.511 +
270.512 +static void error_ftran(struct csa *csa, double h[], double x[],
270.513 + double r[])
270.514 +{ int m = csa->m;
270.515 +#ifdef GLP_DEBUG
270.516 + int n = csa->n;
270.517 +#endif
270.518 + int *A_ptr = csa->A_ptr;
270.519 + int *A_ind = csa->A_ind;
270.520 + double *A_val = csa->A_val;
270.521 + int *head = csa->head;
270.522 + int i, k, beg, end, ptr;
270.523 + double temp;
270.524 + /* compute the residual vector:
270.525 + r = h - B * x = h - B[1] * x[1] - ... - B[m] * x[m],
270.526 + where B[1], ..., B[m] are columns of matrix B */
270.527 + memcpy(&r[1], &h[1], m * sizeof(double));
270.528 + for (i = 1; i <= m; i++)
270.529 + { temp = x[i];
270.530 + if (temp == 0.0) continue;
270.531 + k = head[i]; /* B[i] is k-th column of (I|-A) */
270.532 +#ifdef GLP_DEBUG
270.533 + xassert(1 <= k && k <= m+n);
270.534 +#endif
270.535 + if (k <= m)
270.536 + { /* B[i] is k-th column of submatrix I */
270.537 + r[k] -= temp;
270.538 + }
270.539 + else
270.540 + { /* B[i] is (k-m)-th column of submatrix (-A) */
270.541 + beg = A_ptr[k-m];
270.542 + end = A_ptr[k-m+1];
270.543 + for (ptr = beg; ptr < end; ptr++)
270.544 + r[A_ind[ptr]] += A_val[ptr] * temp;
270.545 + }
270.546 + }
270.547 + return;
270.548 +}
270.549 +
270.550 +/***********************************************************************
270.551 +* refine_ftran - refine solution of B * x = h
270.552 +*
270.553 +* This routine performs one iteration to refine the solution of
270.554 +* the system B * x = h, where B is the current basis matrix, h is the
270.555 +* vector of right-hand sides, x is the solution vector. */
270.556 +
270.557 +static void refine_ftran(struct csa *csa, double h[], double x[])
270.558 +{ int m = csa->m;
270.559 + double *r = csa->work1;
270.560 + double *d = csa->work1;
270.561 + int i;
270.562 + /* compute the residual vector r = h - B * x */
270.563 + error_ftran(csa, h, x, r);
270.564 + /* compute the correction vector d = inv(B) * r */
270.565 + xassert(csa->valid);
270.566 + bfd_ftran(csa->bfd, d);
270.567 + /* refine the solution vector (new x) = (old x) + d */
270.568 + for (i = 1; i <= m; i++) x[i] += d[i];
270.569 + return;
270.570 +}
270.571 +
270.572 +/***********************************************************************
270.573 +* error_btran - compute residual vector r = h - B'* x
270.574 +*
270.575 +* This routine computes the residual vector r = h - B'* x, where B'
270.576 +* is a matrix transposed to the current basis matrix, h is the vector
270.577 +* of right-hand sides, x is the solution vector. */
270.578 +
270.579 +static void error_btran(struct csa *csa, double h[], double x[],
270.580 + double r[])
270.581 +{ int m = csa->m;
270.582 +#ifdef GLP_DEBUG
270.583 + int n = csa->n;
270.584 +#endif
270.585 + int *A_ptr = csa->A_ptr;
270.586 + int *A_ind = csa->A_ind;
270.587 + double *A_val = csa->A_val;
270.588 + int *head = csa->head;
270.589 + int i, k, beg, end, ptr;
270.590 + double temp;
270.591 + /* compute the residual vector r = b - B'* x */
270.592 + for (i = 1; i <= m; i++)
270.593 + { /* r[i] := b[i] - (i-th column of B)'* x */
270.594 + k = head[i]; /* B[i] is k-th column of (I|-A) */
270.595 +#ifdef GLP_DEBUG
270.596 + xassert(1 <= k && k <= m+n);
270.597 +#endif
270.598 + temp = h[i];
270.599 + if (k <= m)
270.600 + { /* B[i] is k-th column of submatrix I */
270.601 + temp -= x[k];
270.602 + }
270.603 + else
270.604 + { /* B[i] is (k-m)-th column of submatrix (-A) */
270.605 + beg = A_ptr[k-m];
270.606 + end = A_ptr[k-m+1];
270.607 + for (ptr = beg; ptr < end; ptr++)
270.608 + temp += A_val[ptr] * x[A_ind[ptr]];
270.609 + }
270.610 + r[i] = temp;
270.611 + }
270.612 + return;
270.613 +}
270.614 +
270.615 +/***********************************************************************
270.616 +* refine_btran - refine solution of B'* x = h
270.617 +*
270.618 +* This routine performs one iteration to refine the solution of the
270.619 +* system B'* x = h, where B' is a matrix transposed to the current
270.620 +* basis matrix, h is the vector of right-hand sides, x is the solution
270.621 +* vector. */
270.622 +
270.623 +static void refine_btran(struct csa *csa, double h[], double x[])
270.624 +{ int m = csa->m;
270.625 + double *r = csa->work1;
270.626 + double *d = csa->work1;
270.627 + int i;
270.628 + /* compute the residual vector r = h - B'* x */
270.629 + error_btran(csa, h, x, r);
270.630 + /* compute the correction vector d = inv(B') * r */
270.631 + xassert(csa->valid);
270.632 + bfd_btran(csa->bfd, d);
270.633 + /* refine the solution vector (new x) = (old x) + d */
270.634 + for (i = 1; i <= m; i++) x[i] += d[i];
270.635 + return;
270.636 +}
270.637 +
270.638 +/***********************************************************************
270.639 +* alloc_N - allocate matrix N
270.640 +*
270.641 +* This routine determines maximal row lengths of matrix N, sets its
270.642 +* row pointers, and then allocates arrays N_ind and N_val.
270.643 +*
270.644 +* Note that some fixed structural variables may temporarily become
270.645 +* double-bounded, so corresponding columns of matrix A should not be
270.646 +* ignored on calculating maximal row lengths of matrix N. */
270.647 +
270.648 +static void alloc_N(struct csa *csa)
270.649 +{ int m = csa->m;
270.650 + int n = csa->n;
270.651 + int *A_ptr = csa->A_ptr;
270.652 + int *A_ind = csa->A_ind;
270.653 + int *N_ptr = csa->N_ptr;
270.654 + int *N_len = csa->N_len;
270.655 + int i, j, beg, end, ptr;
270.656 + /* determine number of non-zeros in each row of the augmented
270.657 + constraint matrix (I|-A) */
270.658 + for (i = 1; i <= m; i++)
270.659 + N_len[i] = 1;
270.660 + for (j = 1; j <= n; j++)
270.661 + { beg = A_ptr[j];
270.662 + end = A_ptr[j+1];
270.663 + for (ptr = beg; ptr < end; ptr++)
270.664 + N_len[A_ind[ptr]]++;
270.665 + }
270.666 + /* determine maximal row lengths of matrix N and set its row
270.667 + pointers */
270.668 + N_ptr[1] = 1;
270.669 + for (i = 1; i <= m; i++)
270.670 + { /* row of matrix N cannot have more than n non-zeros */
270.671 + if (N_len[i] > n) N_len[i] = n;
270.672 + N_ptr[i+1] = N_ptr[i] + N_len[i];
270.673 + }
270.674 + /* now maximal number of non-zeros in matrix N is known */
270.675 + csa->N_ind = xcalloc(N_ptr[m+1], sizeof(int));
270.676 + csa->N_val = xcalloc(N_ptr[m+1], sizeof(double));
270.677 + return;
270.678 +}
270.679 +
270.680 +/***********************************************************************
270.681 +* add_N_col - add column of matrix (I|-A) to matrix N
270.682 +*
270.683 +* This routine adds j-th column to matrix N which is k-th column of
270.684 +* the augmented constraint matrix (I|-A). (It is assumed that old j-th
270.685 +* column was previously removed from matrix N.) */
270.686 +
270.687 +static void add_N_col(struct csa *csa, int j, int k)
270.688 +{ int m = csa->m;
270.689 +#ifdef GLP_DEBUG
270.690 + int n = csa->n;
270.691 +#endif
270.692 + int *N_ptr = csa->N_ptr;
270.693 + int *N_len = csa->N_len;
270.694 + int *N_ind = csa->N_ind;
270.695 + double *N_val = csa->N_val;
270.696 + int pos;
270.697 +#ifdef GLP_DEBUG
270.698 + xassert(1 <= j && j <= n);
270.699 + xassert(1 <= k && k <= m+n);
270.700 +#endif
270.701 + if (k <= m)
270.702 + { /* N[j] is k-th column of submatrix I */
270.703 + pos = N_ptr[k] + (N_len[k]++);
270.704 +#ifdef GLP_DEBUG
270.705 + xassert(pos < N_ptr[k+1]);
270.706 +#endif
270.707 + N_ind[pos] = j;
270.708 + N_val[pos] = 1.0;
270.709 + }
270.710 + else
270.711 + { /* N[j] is (k-m)-th column of submatrix (-A) */
270.712 + int *A_ptr = csa->A_ptr;
270.713 + int *A_ind = csa->A_ind;
270.714 + double *A_val = csa->A_val;
270.715 + int i, beg, end, ptr;
270.716 + beg = A_ptr[k-m];
270.717 + end = A_ptr[k-m+1];
270.718 + for (ptr = beg; ptr < end; ptr++)
270.719 + { i = A_ind[ptr]; /* row number */
270.720 + pos = N_ptr[i] + (N_len[i]++);
270.721 +#ifdef GLP_DEBUG
270.722 + xassert(pos < N_ptr[i+1]);
270.723 +#endif
270.724 + N_ind[pos] = j;
270.725 + N_val[pos] = - A_val[ptr];
270.726 + }
270.727 + }
270.728 + return;
270.729 +}
270.730 +
270.731 +/***********************************************************************
270.732 +* del_N_col - remove column of matrix (I|-A) from matrix N
270.733 +*
270.734 +* This routine removes j-th column from matrix N which is k-th column
270.735 +* of the augmented constraint matrix (I|-A). */
270.736 +
270.737 +static void del_N_col(struct csa *csa, int j, int k)
270.738 +{ int m = csa->m;
270.739 +#ifdef GLP_DEBUG
270.740 + int n = csa->n;
270.741 +#endif
270.742 + int *N_ptr = csa->N_ptr;
270.743 + int *N_len = csa->N_len;
270.744 + int *N_ind = csa->N_ind;
270.745 + double *N_val = csa->N_val;
270.746 + int pos, head, tail;
270.747 +#ifdef GLP_DEBUG
270.748 + xassert(1 <= j && j <= n);
270.749 + xassert(1 <= k && k <= m+n);
270.750 +#endif
270.751 + if (k <= m)
270.752 + { /* N[j] is k-th column of submatrix I */
270.753 + /* find element in k-th row of N */
270.754 + head = N_ptr[k];
270.755 + for (pos = head; N_ind[pos] != j; pos++) /* nop */;
270.756 + /* and remove it from the row list */
270.757 + tail = head + (--N_len[k]);
270.758 +#ifdef GLP_DEBUG
270.759 + xassert(pos <= tail);
270.760 +#endif
270.761 + N_ind[pos] = N_ind[tail];
270.762 + N_val[pos] = N_val[tail];
270.763 + }
270.764 + else
270.765 + { /* N[j] is (k-m)-th column of submatrix (-A) */
270.766 + int *A_ptr = csa->A_ptr;
270.767 + int *A_ind = csa->A_ind;
270.768 + int i, beg, end, ptr;
270.769 + beg = A_ptr[k-m];
270.770 + end = A_ptr[k-m+1];
270.771 + for (ptr = beg; ptr < end; ptr++)
270.772 + { i = A_ind[ptr]; /* row number */
270.773 + /* find element in i-th row of N */
270.774 + head = N_ptr[i];
270.775 + for (pos = head; N_ind[pos] != j; pos++) /* nop */;
270.776 + /* and remove it from the row list */
270.777 + tail = head + (--N_len[i]);
270.778 +#ifdef GLP_DEBUG
270.779 + xassert(pos <= tail);
270.780 +#endif
270.781 + N_ind[pos] = N_ind[tail];
270.782 + N_val[pos] = N_val[tail];
270.783 + }
270.784 + }
270.785 + return;
270.786 +}
270.787 +
270.788 +/***********************************************************************
270.789 +* build_N - build matrix N for current basis
270.790 +*
270.791 +* This routine builds matrix N for the current basis from columns
270.792 +* of the augmented constraint matrix (I|-A) corresponding to non-basic
270.793 +* non-fixed variables. */
270.794 +
270.795 +static void build_N(struct csa *csa)
270.796 +{ int m = csa->m;
270.797 + int n = csa->n;
270.798 + int *head = csa->head;
270.799 + char *stat = csa->stat;
270.800 + int *N_len = csa->N_len;
270.801 + int j, k;
270.802 + /* N := empty matrix */
270.803 + memset(&N_len[1], 0, m * sizeof(int));
270.804 + /* go through non-basic columns of matrix (I|-A) */
270.805 + for (j = 1; j <= n; j++)
270.806 + { if (stat[j] != GLP_NS)
270.807 + { /* xN[j] is non-fixed; add j-th column to matrix N which is
270.808 + k-th column of matrix (I|-A) */
270.809 + k = head[m+j]; /* x[k] = xN[j] */
270.810 +#ifdef GLP_DEBUG
270.811 + xassert(1 <= k && k <= m+n);
270.812 +#endif
270.813 + add_N_col(csa, j, k);
270.814 + }
270.815 + }
270.816 + return;
270.817 +}
270.818 +
270.819 +/***********************************************************************
270.820 +* get_xN - determine current value of non-basic variable xN[j]
270.821 +*
270.822 +* This routine returns the current value of non-basic variable xN[j],
270.823 +* which is a value of its active bound. */
270.824 +
270.825 +static double get_xN(struct csa *csa, int j)
270.826 +{ int m = csa->m;
270.827 +#ifdef GLP_DEBUG
270.828 + int n = csa->n;
270.829 +#endif
270.830 + double *lb = csa->lb;
270.831 + double *ub = csa->ub;
270.832 + int *head = csa->head;
270.833 + char *stat = csa->stat;
270.834 + int k;
270.835 + double xN;
270.836 +#ifdef GLP_DEBUG
270.837 + xassert(1 <= j && j <= n);
270.838 +#endif
270.839 + k = head[m+j]; /* x[k] = xN[j] */
270.840 +#ifdef GLP_DEBUG
270.841 + xassert(1 <= k && k <= m+n);
270.842 +#endif
270.843 + switch (stat[j])
270.844 + { case GLP_NL:
270.845 + /* x[k] is on its lower bound */
270.846 + xN = lb[k]; break;
270.847 + case GLP_NU:
270.848 + /* x[k] is on its upper bound */
270.849 + xN = ub[k]; break;
270.850 + case GLP_NF:
270.851 + /* x[k] is free non-basic variable */
270.852 + xN = 0.0; break;
270.853 + case GLP_NS:
270.854 + /* x[k] is fixed non-basic variable */
270.855 + xN = lb[k]; break;
270.856 + default:
270.857 + xassert(stat != stat);
270.858 + }
270.859 + return xN;
270.860 +}
270.861 +
270.862 +/***********************************************************************
270.863 +* eval_beta - compute primal values of basic variables
270.864 +*
270.865 +* This routine computes current primal values of all basic variables:
270.866 +*
270.867 +* beta = - inv(B) * N * xN,
270.868 +*
270.869 +* where B is the current basis matrix, N is a matrix built of columns
270.870 +* of matrix (I|-A) corresponding to non-basic variables, and xN is the
270.871 +* vector of current values of non-basic variables. */
270.872 +
270.873 +static void eval_beta(struct csa *csa, double beta[])
270.874 +{ int m = csa->m;
270.875 + int n = csa->n;
270.876 + int *A_ptr = csa->A_ptr;
270.877 + int *A_ind = csa->A_ind;
270.878 + double *A_val = csa->A_val;
270.879 + int *head = csa->head;
270.880 + double *h = csa->work2;
270.881 + int i, j, k, beg, end, ptr;
270.882 + double xN;
270.883 + /* compute the right-hand side vector:
270.884 + h := - N * xN = - N[1] * xN[1] - ... - N[n] * xN[n],
270.885 + where N[1], ..., N[n] are columns of matrix N */
270.886 + for (i = 1; i <= m; i++)
270.887 + h[i] = 0.0;
270.888 + for (j = 1; j <= n; j++)
270.889 + { k = head[m+j]; /* x[k] = xN[j] */
270.890 +#ifdef GLP_DEBUG
270.891 + xassert(1 <= k && k <= m+n);
270.892 +#endif
270.893 + /* determine current value of xN[j] */
270.894 + xN = get_xN(csa, j);
270.895 + if (xN == 0.0) continue;
270.896 + if (k <= m)
270.897 + { /* N[j] is k-th column of submatrix I */
270.898 + h[k] -= xN;
270.899 + }
270.900 + else
270.901 + { /* N[j] is (k-m)-th column of submatrix (-A) */
270.902 + beg = A_ptr[k-m];
270.903 + end = A_ptr[k-m+1];
270.904 + for (ptr = beg; ptr < end; ptr++)
270.905 + h[A_ind[ptr]] += xN * A_val[ptr];
270.906 + }
270.907 + }
270.908 + /* solve system B * beta = h */
270.909 + memcpy(&beta[1], &h[1], m * sizeof(double));
270.910 + xassert(csa->valid);
270.911 + bfd_ftran(csa->bfd, beta);
270.912 + /* and refine the solution */
270.913 + refine_ftran(csa, h, beta);
270.914 + return;
270.915 +}
270.916 +
270.917 +/***********************************************************************
270.918 +* eval_pi - compute vector of simplex multipliers
270.919 +*
270.920 +* This routine computes the vector of current simplex multipliers:
270.921 +*
270.922 +* pi = inv(B') * cB,
270.923 +*
270.924 +* where B' is a matrix transposed to the current basis matrix, cB is
270.925 +* a subvector of objective coefficients at basic variables. */
270.926 +
270.927 +static void eval_pi(struct csa *csa, double pi[])
270.928 +{ int m = csa->m;
270.929 + double *c = csa->coef;
270.930 + int *head = csa->head;
270.931 + double *cB = csa->work2;
270.932 + int i;
270.933 + /* construct the right-hand side vector cB */
270.934 + for (i = 1; i <= m; i++)
270.935 + cB[i] = c[head[i]];
270.936 + /* solve system B'* pi = cB */
270.937 + memcpy(&pi[1], &cB[1], m * sizeof(double));
270.938 + xassert(csa->valid);
270.939 + bfd_btran(csa->bfd, pi);
270.940 + /* and refine the solution */
270.941 + refine_btran(csa, cB, pi);
270.942 + return;
270.943 +}
270.944 +
270.945 +/***********************************************************************
270.946 +* eval_cost - compute reduced cost of non-basic variable xN[j]
270.947 +*
270.948 +* This routine computes the current reduced cost of non-basic variable
270.949 +* xN[j]:
270.950 +*
270.951 +* d[j] = cN[j] - N'[j] * pi,
270.952 +*
270.953 +* where cN[j] is the objective coefficient at variable xN[j], N[j] is
270.954 +* a column of the augmented constraint matrix (I|-A) corresponding to
270.955 +* xN[j], pi is the vector of simplex multipliers. */
270.956 +
270.957 +static double eval_cost(struct csa *csa, double pi[], int j)
270.958 +{ int m = csa->m;
270.959 +#ifdef GLP_DEBUG
270.960 + int n = csa->n;
270.961 +#endif
270.962 + double *coef = csa->coef;
270.963 + int *head = csa->head;
270.964 + int k;
270.965 + double dj;
270.966 +#ifdef GLP_DEBUG
270.967 + xassert(1 <= j && j <= n);
270.968 +#endif
270.969 + k = head[m+j]; /* x[k] = xN[j] */
270.970 +#ifdef GLP_DEBUG
270.971 + xassert(1 <= k && k <= m+n);
270.972 +#endif
270.973 + dj = coef[k];
270.974 + if (k <= m)
270.975 + { /* N[j] is k-th column of submatrix I */
270.976 + dj -= pi[k];
270.977 + }
270.978 + else
270.979 + { /* N[j] is (k-m)-th column of submatrix (-A) */
270.980 + int *A_ptr = csa->A_ptr;
270.981 + int *A_ind = csa->A_ind;
270.982 + double *A_val = csa->A_val;
270.983 + int beg, end, ptr;
270.984 + beg = A_ptr[k-m];
270.985 + end = A_ptr[k-m+1];
270.986 + for (ptr = beg; ptr < end; ptr++)
270.987 + dj += A_val[ptr] * pi[A_ind[ptr]];
270.988 + }
270.989 + return dj;
270.990 +}
270.991 +
270.992 +/***********************************************************************
270.993 +* eval_bbar - compute and store primal values of basic variables
270.994 +*
270.995 +* This routine computes primal values of all basic variables and then
270.996 +* stores them in the solution array. */
270.997 +
270.998 +static void eval_bbar(struct csa *csa)
270.999 +{ eval_beta(csa, csa->bbar);
270.1000 + return;
270.1001 +}
270.1002 +
270.1003 +/***********************************************************************
270.1004 +* eval_cbar - compute and store reduced costs of non-basic variables
270.1005 +*
270.1006 +* This routine computes reduced costs of all non-basic variables and
270.1007 +* then stores them in the solution array. */
270.1008 +
270.1009 +static void eval_cbar(struct csa *csa)
270.1010 +{
270.1011 +#ifdef GLP_DEBUG
270.1012 + int m = csa->m;
270.1013 +#endif
270.1014 + int n = csa->n;
270.1015 +#ifdef GLP_DEBUG
270.1016 + int *head = csa->head;
270.1017 +#endif
270.1018 + double *cbar = csa->cbar;
270.1019 + double *pi = csa->work3;
270.1020 + int j;
270.1021 +#ifdef GLP_DEBUG
270.1022 + int k;
270.1023 +#endif
270.1024 + /* compute simplex multipliers */
270.1025 + eval_pi(csa, pi);
270.1026 + /* compute and store reduced costs */
270.1027 + for (j = 1; j <= n; j++)
270.1028 + {
270.1029 +#ifdef GLP_DEBUG
270.1030 + k = head[m+j]; /* x[k] = xN[j] */
270.1031 + xassert(1 <= k && k <= m+n);
270.1032 +#endif
270.1033 + cbar[j] = eval_cost(csa, pi, j);
270.1034 + }
270.1035 + return;
270.1036 +}
270.1037 +
270.1038 +/***********************************************************************
270.1039 +* reset_refsp - reset the reference space
270.1040 +*
270.1041 +* This routine resets (redefines) the reference space used in the
270.1042 +* projected steepest edge pricing algorithm. */
270.1043 +
270.1044 +static void reset_refsp(struct csa *csa)
270.1045 +{ int m = csa->m;
270.1046 + int n = csa->n;
270.1047 + int *head = csa->head;
270.1048 + char *refsp = csa->refsp;
270.1049 + double *gamma = csa->gamma;
270.1050 + int j, k;
270.1051 + xassert(csa->refct == 0);
270.1052 + csa->refct = 1000;
270.1053 + memset(&refsp[1], 0, (m+n) * sizeof(char));
270.1054 + for (j = 1; j <= n; j++)
270.1055 + { k = head[m+j]; /* x[k] = xN[j] */
270.1056 + refsp[k] = 1;
270.1057 + gamma[j] = 1.0;
270.1058 + }
270.1059 + return;
270.1060 +}
270.1061 +
270.1062 +/***********************************************************************
270.1063 +* eval_gamma - compute steepest edge coefficient
270.1064 +*
270.1065 +* This routine computes the steepest edge coefficient for non-basic
270.1066 +* variable xN[j] using its direct definition:
270.1067 +*
270.1068 +* gamma[j] = delta[j] + sum alfa[i,j]^2,
270.1069 +* i in R
270.1070 +*
270.1071 +* where delta[j] = 1, if xN[j] is in the current reference space,
270.1072 +* and 0 otherwise; R is a set of basic variables xB[i], which are in
270.1073 +* the current reference space; alfa[i,j] are elements of the current
270.1074 +* simplex table.
270.1075 +*
270.1076 +* NOTE: The routine is intended only for debugginig purposes. */
270.1077 +
270.1078 +static double eval_gamma(struct csa *csa, int j)
270.1079 +{ int m = csa->m;
270.1080 +#ifdef GLP_DEBUG
270.1081 + int n = csa->n;
270.1082 +#endif
270.1083 + int *head = csa->head;
270.1084 + char *refsp = csa->refsp;
270.1085 + double *alfa = csa->work3;
270.1086 + double *h = csa->work3;
270.1087 + int i, k;
270.1088 + double gamma;
270.1089 +#ifdef GLP_DEBUG
270.1090 + xassert(1 <= j && j <= n);
270.1091 +#endif
270.1092 + k = head[m+j]; /* x[k] = xN[j] */
270.1093 +#ifdef GLP_DEBUG
270.1094 + xassert(1 <= k && k <= m+n);
270.1095 +#endif
270.1096 + /* construct the right-hand side vector h = - N[j] */
270.1097 + for (i = 1; i <= m; i++)
270.1098 + h[i] = 0.0;
270.1099 + if (k <= m)
270.1100 + { /* N[j] is k-th column of submatrix I */
270.1101 + h[k] = -1.0;
270.1102 + }
270.1103 + else
270.1104 + { /* N[j] is (k-m)-th column of submatrix (-A) */
270.1105 + int *A_ptr = csa->A_ptr;
270.1106 + int *A_ind = csa->A_ind;
270.1107 + double *A_val = csa->A_val;
270.1108 + int beg, end, ptr;
270.1109 + beg = A_ptr[k-m];
270.1110 + end = A_ptr[k-m+1];
270.1111 + for (ptr = beg; ptr < end; ptr++)
270.1112 + h[A_ind[ptr]] = A_val[ptr];
270.1113 + }
270.1114 + /* solve system B * alfa = h */
270.1115 + xassert(csa->valid);
270.1116 + bfd_ftran(csa->bfd, alfa);
270.1117 + /* compute gamma */
270.1118 + gamma = (refsp[k] ? 1.0 : 0.0);
270.1119 + for (i = 1; i <= m; i++)
270.1120 + { k = head[i];
270.1121 +#ifdef GLP_DEBUG
270.1122 + xassert(1 <= k && k <= m+n);
270.1123 +#endif
270.1124 + if (refsp[k]) gamma += alfa[i] * alfa[i];
270.1125 + }
270.1126 + return gamma;
270.1127 +}
270.1128 +
270.1129 +/***********************************************************************
270.1130 +* chuzc - choose non-basic variable (column of the simplex table)
270.1131 +*
270.1132 +* This routine chooses non-basic variable xN[q], which has largest
270.1133 +* weighted reduced cost:
270.1134 +*
270.1135 +* |d[q]| / sqrt(gamma[q]) = max |d[j]| / sqrt(gamma[j]),
270.1136 +* j in J
270.1137 +*
270.1138 +* where J is a subset of eligible non-basic variables xN[j], d[j] is
270.1139 +* reduced cost of xN[j], gamma[j] is the steepest edge coefficient.
270.1140 +*
270.1141 +* The working objective function is always minimized, so the sign of
270.1142 +* d[q] determines direction, in which xN[q] has to change:
270.1143 +*
270.1144 +* if d[q] < 0, xN[q] has to increase;
270.1145 +*
270.1146 +* if d[q] > 0, xN[q] has to decrease.
270.1147 +*
270.1148 +* If |d[j]| <= tol_dj, where tol_dj is a specified tolerance, xN[j]
270.1149 +* is not included in J and therefore ignored. (It is assumed that the
270.1150 +* working objective row is appropriately scaled, i.e. max|c[k]| = 1.)
270.1151 +*
270.1152 +* If J is empty and no variable has been chosen, q is set to 0. */
270.1153 +
270.1154 +static void chuzc(struct csa *csa, double tol_dj)
270.1155 +{ int n = csa->n;
270.1156 + char *stat = csa->stat;
270.1157 + double *cbar = csa->cbar;
270.1158 + double *gamma = csa->gamma;
270.1159 + int j, q;
270.1160 + double dj, best, temp;
270.1161 + /* nothing is chosen so far */
270.1162 + q = 0, best = 0.0;
270.1163 + /* look through the list of non-basic variables */
270.1164 + for (j = 1; j <= n; j++)
270.1165 + { dj = cbar[j];
270.1166 + switch (stat[j])
270.1167 + { case GLP_NL:
270.1168 + /* xN[j] can increase */
270.1169 + if (dj >= - tol_dj) continue;
270.1170 + break;
270.1171 + case GLP_NU:
270.1172 + /* xN[j] can decrease */
270.1173 + if (dj <= + tol_dj) continue;
270.1174 + break;
270.1175 + case GLP_NF:
270.1176 + /* xN[j] can change in any direction */
270.1177 + if (- tol_dj <= dj && dj <= + tol_dj) continue;
270.1178 + break;
270.1179 + case GLP_NS:
270.1180 + /* xN[j] cannot change at all */
270.1181 + continue;
270.1182 + default:
270.1183 + xassert(stat != stat);
270.1184 + }
270.1185 + /* xN[j] is eligible non-basic variable; choose one which has
270.1186 + largest weighted reduced cost */
270.1187 +#ifdef GLP_DEBUG
270.1188 + xassert(gamma[j] > 0.0);
270.1189 +#endif
270.1190 + temp = (dj * dj) / gamma[j];
270.1191 + if (best < temp)
270.1192 + q = j, best = temp;
270.1193 + }
270.1194 + /* store the index of non-basic variable xN[q] chosen */
270.1195 + csa->q = q;
270.1196 + return;
270.1197 +}
270.1198 +
270.1199 +/***********************************************************************
270.1200 +* eval_tcol - compute pivot column of the simplex table
270.1201 +*
270.1202 +* This routine computes the pivot column of the simplex table, which
270.1203 +* corresponds to non-basic variable xN[q] chosen.
270.1204 +*
270.1205 +* The pivot column is the following vector:
270.1206 +*
270.1207 +* tcol = T * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q],
270.1208 +*
270.1209 +* where B is the current basis matrix, N[q] is a column of the matrix
270.1210 +* (I|-A) corresponding to variable xN[q]. */
270.1211 +
270.1212 +static void eval_tcol(struct csa *csa)
270.1213 +{ int m = csa->m;
270.1214 +#ifdef GLP_DEBUG
270.1215 + int n = csa->n;
270.1216 +#endif
270.1217 + int *head = csa->head;
270.1218 + int q = csa->q;
270.1219 + int *tcol_ind = csa->tcol_ind;
270.1220 + double *tcol_vec = csa->tcol_vec;
270.1221 + double *h = csa->tcol_vec;
270.1222 + int i, k, nnz;
270.1223 +#ifdef GLP_DEBUG
270.1224 + xassert(1 <= q && q <= n);
270.1225 +#endif
270.1226 + k = head[m+q]; /* x[k] = xN[q] */
270.1227 +#ifdef GLP_DEBUG
270.1228 + xassert(1 <= k && k <= m+n);
270.1229 +#endif
270.1230 + /* construct the right-hand side vector h = - N[q] */
270.1231 + for (i = 1; i <= m; i++)
270.1232 + h[i] = 0.0;
270.1233 + if (k <= m)
270.1234 + { /* N[q] is k-th column of submatrix I */
270.1235 + h[k] = -1.0;
270.1236 + }
270.1237 + else
270.1238 + { /* N[q] is (k-m)-th column of submatrix (-A) */
270.1239 + int *A_ptr = csa->A_ptr;
270.1240 + int *A_ind = csa->A_ind;
270.1241 + double *A_val = csa->A_val;
270.1242 + int beg, end, ptr;
270.1243 + beg = A_ptr[k-m];
270.1244 + end = A_ptr[k-m+1];
270.1245 + for (ptr = beg; ptr < end; ptr++)
270.1246 + h[A_ind[ptr]] = A_val[ptr];
270.1247 + }
270.1248 + /* solve system B * tcol = h */
270.1249 + xassert(csa->valid);
270.1250 + bfd_ftran(csa->bfd, tcol_vec);
270.1251 + /* construct sparse pattern of the pivot column */
270.1252 + nnz = 0;
270.1253 + for (i = 1; i <= m; i++)
270.1254 + { if (tcol_vec[i] != 0.0)
270.1255 + tcol_ind[++nnz] = i;
270.1256 + }
270.1257 + csa->tcol_nnz = nnz;
270.1258 + return;
270.1259 +}
270.1260 +
270.1261 +/***********************************************************************
270.1262 +* refine_tcol - refine pivot column of the simplex table
270.1263 +*
270.1264 +* This routine refines the pivot column of the simplex table assuming
270.1265 +* that it was previously computed by the routine eval_tcol. */
270.1266 +
270.1267 +static void refine_tcol(struct csa *csa)
270.1268 +{ int m = csa->m;
270.1269 +#ifdef GLP_DEBUG
270.1270 + int n = csa->n;
270.1271 +#endif
270.1272 + int *head = csa->head;
270.1273 + int q = csa->q;
270.1274 + int *tcol_ind = csa->tcol_ind;
270.1275 + double *tcol_vec = csa->tcol_vec;
270.1276 + double *h = csa->work3;
270.1277 + int i, k, nnz;
270.1278 +#ifdef GLP_DEBUG
270.1279 + xassert(1 <= q && q <= n);
270.1280 +#endif
270.1281 + k = head[m+q]; /* x[k] = xN[q] */
270.1282 +#ifdef GLP_DEBUG
270.1283 + xassert(1 <= k && k <= m+n);
270.1284 +#endif
270.1285 + /* construct the right-hand side vector h = - N[q] */
270.1286 + for (i = 1; i <= m; i++)
270.1287 + h[i] = 0.0;
270.1288 + if (k <= m)
270.1289 + { /* N[q] is k-th column of submatrix I */
270.1290 + h[k] = -1.0;
270.1291 + }
270.1292 + else
270.1293 + { /* N[q] is (k-m)-th column of submatrix (-A) */
270.1294 + int *A_ptr = csa->A_ptr;
270.1295 + int *A_ind = csa->A_ind;
270.1296 + double *A_val = csa->A_val;
270.1297 + int beg, end, ptr;
270.1298 + beg = A_ptr[k-m];
270.1299 + end = A_ptr[k-m+1];
270.1300 + for (ptr = beg; ptr < end; ptr++)
270.1301 + h[A_ind[ptr]] = A_val[ptr];
270.1302 + }
270.1303 + /* refine solution of B * tcol = h */
270.1304 + refine_ftran(csa, h, tcol_vec);
270.1305 + /* construct sparse pattern of the pivot column */
270.1306 + nnz = 0;
270.1307 + for (i = 1; i <= m; i++)
270.1308 + { if (tcol_vec[i] != 0.0)
270.1309 + tcol_ind[++nnz] = i;
270.1310 + }
270.1311 + csa->tcol_nnz = nnz;
270.1312 + return;
270.1313 +}
270.1314 +
270.1315 +/***********************************************************************
270.1316 +* sort_tcol - sort pivot column of the simplex table
270.1317 +*
270.1318 +* This routine reorders the list of non-zero elements of the pivot
270.1319 +* column to put significant elements, whose magnitude is not less than
270.1320 +* a specified tolerance, in front of the list, and stores the number
270.1321 +* of significant elements in tcol_num. */
270.1322 +
270.1323 +static void sort_tcol(struct csa *csa, double tol_piv)
270.1324 +{
270.1325 +#ifdef GLP_DEBUG
270.1326 + int m = csa->m;
270.1327 +#endif
270.1328 + int nnz = csa->tcol_nnz;
270.1329 + int *tcol_ind = csa->tcol_ind;
270.1330 + double *tcol_vec = csa->tcol_vec;
270.1331 + int i, num, pos;
270.1332 + double big, eps, temp;
270.1333 + /* compute infinity (maximum) norm of the column */
270.1334 + big = 0.0;
270.1335 + for (pos = 1; pos <= nnz; pos++)
270.1336 + {
270.1337 +#ifdef GLP_DEBUG
270.1338 + i = tcol_ind[pos];
270.1339 + xassert(1 <= i && i <= m);
270.1340 +#endif
270.1341 + temp = fabs(tcol_vec[tcol_ind[pos]]);
270.1342 + if (big < temp) big = temp;
270.1343 + }
270.1344 + csa->tcol_max = big;
270.1345 + /* determine absolute pivot tolerance */
270.1346 + eps = tol_piv * (1.0 + 0.01 * big);
270.1347 + /* move significant column components to front of the list */
270.1348 + for (num = 0; num < nnz; )
270.1349 + { i = tcol_ind[nnz];
270.1350 + if (fabs(tcol_vec[i]) < eps)
270.1351 + nnz--;
270.1352 + else
270.1353 + { num++;
270.1354 + tcol_ind[nnz] = tcol_ind[num];
270.1355 + tcol_ind[num] = i;
270.1356 + }
270.1357 + }
270.1358 + csa->tcol_num = num;
270.1359 + return;
270.1360 +}
270.1361 +
270.1362 +/***********************************************************************
270.1363 +* chuzr - choose basic variable (row of the simplex table)
270.1364 +*
270.1365 +* This routine chooses basic variable xB[p], which reaches its bound
270.1366 +* first on changing non-basic variable xN[q] in valid direction.
270.1367 +*
270.1368 +* The parameter rtol is a relative tolerance used to relax bounds of
270.1369 +* basic variables. If rtol = 0, the routine implements the standard
270.1370 +* ratio test. Otherwise, if rtol > 0, the routine implements Harris'
270.1371 +* two-pass ratio test. In the latter case rtol should be about three
270.1372 +* times less than a tolerance used to check primal feasibility. */
270.1373 +
270.1374 +static void chuzr(struct csa *csa, double rtol)
270.1375 +{ int m = csa->m;
270.1376 +#ifdef GLP_DEBUG
270.1377 + int n = csa->n;
270.1378 +#endif
270.1379 + char *type = csa->type;
270.1380 + double *lb = csa->lb;
270.1381 + double *ub = csa->ub;
270.1382 + double *coef = csa->coef;
270.1383 + int *head = csa->head;
270.1384 + int phase = csa->phase;
270.1385 + double *bbar = csa->bbar;
270.1386 + double *cbar = csa->cbar;
270.1387 + int q = csa->q;
270.1388 + int *tcol_ind = csa->tcol_ind;
270.1389 + double *tcol_vec = csa->tcol_vec;
270.1390 + int tcol_num = csa->tcol_num;
270.1391 + int i, i_stat, k, p, p_stat, pos;
270.1392 + double alfa, big, delta, s, t, teta, tmax;
270.1393 +#ifdef GLP_DEBUG
270.1394 + xassert(1 <= q && q <= n);
270.1395 +#endif
270.1396 + /* s := - sign(d[q]), where d[q] is reduced cost of xN[q] */
270.1397 +#ifdef GLP_DEBUG
270.1398 + xassert(cbar[q] != 0.0);
270.1399 +#endif
270.1400 + s = (cbar[q] > 0.0 ? -1.0 : +1.0);
270.1401 + /*** FIRST PASS ***/
270.1402 + k = head[m+q]; /* x[k] = xN[q] */
270.1403 +#ifdef GLP_DEBUG
270.1404 + xassert(1 <= k && k <= m+n);
270.1405 +#endif
270.1406 + if (type[k] == GLP_DB)
270.1407 + { /* xN[q] has both lower and upper bounds */
270.1408 + p = -1, p_stat = 0, teta = ub[k] - lb[k], big = 1.0;
270.1409 + }
270.1410 + else
270.1411 + { /* xN[q] has no opposite bound */
270.1412 + p = 0, p_stat = 0, teta = DBL_MAX, big = 0.0;
270.1413 + }
270.1414 + /* walk through significant elements of the pivot column */
270.1415 + for (pos = 1; pos <= tcol_num; pos++)
270.1416 + { i = tcol_ind[pos];
270.1417 +#ifdef GLP_DEBUG
270.1418 + xassert(1 <= i && i <= m);
270.1419 +#endif
270.1420 + k = head[i]; /* x[k] = xB[i] */
270.1421 +#ifdef GLP_DEBUG
270.1422 + xassert(1 <= k && k <= m+n);
270.1423 +#endif
270.1424 + alfa = s * tcol_vec[i];
270.1425 +#ifdef GLP_DEBUG
270.1426 + xassert(alfa != 0.0);
270.1427 +#endif
270.1428 + /* xB[i] = ... + alfa * xN[q] + ..., and due to s we need to
270.1429 + consider the only case when xN[q] is increasing */
270.1430 + if (alfa > 0.0)
270.1431 + { /* xB[i] is increasing */
270.1432 + if (phase == 1 && coef[k] < 0.0)
270.1433 + { /* xB[i] violates its lower bound, which plays the role
270.1434 + of an upper bound on phase I */
270.1435 + delta = rtol * (1.0 + kappa * fabs(lb[k]));
270.1436 + t = ((lb[k] + delta) - bbar[i]) / alfa;
270.1437 + i_stat = GLP_NL;
270.1438 + }
270.1439 + else if (phase == 1 && coef[k] > 0.0)
270.1440 + { /* xB[i] violates its upper bound, which plays the role
270.1441 + of an lower bound on phase I */
270.1442 + continue;
270.1443 + }
270.1444 + else if (type[k] == GLP_UP || type[k] == GLP_DB ||
270.1445 + type[k] == GLP_FX)
270.1446 + { /* xB[i] is within its bounds and has an upper bound */
270.1447 + delta = rtol * (1.0 + kappa * fabs(ub[k]));
270.1448 + t = ((ub[k] + delta) - bbar[i]) / alfa;
270.1449 + i_stat = GLP_NU;
270.1450 + }
270.1451 + else
270.1452 + { /* xB[i] is within its bounds and has no upper bound */
270.1453 + continue;
270.1454 + }
270.1455 + }
270.1456 + else
270.1457 + { /* xB[i] is decreasing */
270.1458 + if (phase == 1 && coef[k] > 0.0)
270.1459 + { /* xB[i] violates its upper bound, which plays the role
270.1460 + of an lower bound on phase I */
270.1461 + delta = rtol * (1.0 + kappa * fabs(ub[k]));
270.1462 + t = ((ub[k] - delta) - bbar[i]) / alfa;
270.1463 + i_stat = GLP_NU;
270.1464 + }
270.1465 + else if (phase == 1 && coef[k] < 0.0)
270.1466 + { /* xB[i] violates its lower bound, which plays the role
270.1467 + of an upper bound on phase I */
270.1468 + continue;
270.1469 + }
270.1470 + else if (type[k] == GLP_LO || type[k] == GLP_DB ||
270.1471 + type[k] == GLP_FX)
270.1472 + { /* xB[i] is within its bounds and has an lower bound */
270.1473 + delta = rtol * (1.0 + kappa * fabs(lb[k]));
270.1474 + t = ((lb[k] - delta) - bbar[i]) / alfa;
270.1475 + i_stat = GLP_NL;
270.1476 + }
270.1477 + else
270.1478 + { /* xB[i] is within its bounds and has no lower bound */
270.1479 + continue;
270.1480 + }
270.1481 + }
270.1482 + /* t is a change of xN[q], on which xB[i] reaches its bound
270.1483 + (possibly relaxed); since the basic solution is assumed to
270.1484 + be primal feasible (or pseudo feasible on phase I), t has
270.1485 + to be non-negative by definition; however, it may happen
270.1486 + that xB[i] slightly (i.e. within a tolerance) violates its
270.1487 + bound, that leads to negative t; in the latter case, if
270.1488 + xB[i] is chosen, negative t means that xN[q] changes in
270.1489 + wrong direction; if pivot alfa[i,q] is close to zero, even
270.1490 + small bound violation of xB[i] may lead to a large change
270.1491 + of xN[q] in wrong direction; let, for example, xB[i] >= 0
270.1492 + and in the current basis its value be -5e-9; let also xN[q]
270.1493 + be on its zero bound and should increase; from the ratio
270.1494 + test rule it follows that the pivot alfa[i,q] < 0; however,
270.1495 + if alfa[i,q] is, say, -1e-9, the change of xN[q] in wrong
270.1496 + direction is 5e-9 / (-1e-9) = -5, and using it for updating
270.1497 + values of other basic variables will give absolutely wrong
270.1498 + results; therefore, if t is negative, we should replace it
270.1499 + by exact zero assuming that xB[i] is exactly on its bound,
270.1500 + and the violation appears due to round-off errors */
270.1501 + if (t < 0.0) t = 0.0;
270.1502 + /* apply minimal ratio test */
270.1503 + if (teta > t || teta == t && big < fabs(alfa))
270.1504 + p = i, p_stat = i_stat, teta = t, big = fabs(alfa);
270.1505 + }
270.1506 + /* the second pass is skipped in the following cases: */
270.1507 + /* if the standard ratio test is used */
270.1508 + if (rtol == 0.0) goto done;
270.1509 + /* if xN[q] reaches its opposite bound or if no basic variable
270.1510 + has been chosen on the first pass */
270.1511 + if (p <= 0) goto done;
270.1512 + /* if xB[p] is a blocking variable, i.e. if it prevents xN[q]
270.1513 + from any change */
270.1514 + if (teta == 0.0) goto done;
270.1515 + /*** SECOND PASS ***/
270.1516 + /* here tmax is a maximal change of xN[q], on which the solution
270.1517 + remains primal feasible (or pseudo feasible on phase I) within
270.1518 + a tolerance */
270.1519 +#if 0
270.1520 + tmax = (1.0 + 10.0 * DBL_EPSILON) * teta;
270.1521 +#else
270.1522 + tmax = teta;
270.1523 +#endif
270.1524 + /* nothing is chosen so far */
270.1525 + p = 0, p_stat = 0, teta = DBL_MAX, big = 0.0;
270.1526 + /* walk through significant elements of the pivot column */
270.1527 + for (pos = 1; pos <= tcol_num; pos++)
270.1528 + { i = tcol_ind[pos];
270.1529 +#ifdef GLP_DEBUG
270.1530 + xassert(1 <= i && i <= m);
270.1531 +#endif
270.1532 + k = head[i]; /* x[k] = xB[i] */
270.1533 +#ifdef GLP_DEBUG
270.1534 + xassert(1 <= k && k <= m+n);
270.1535 +#endif
270.1536 + alfa = s * tcol_vec[i];
270.1537 +#ifdef GLP_DEBUG
270.1538 + xassert(alfa != 0.0);
270.1539 +#endif
270.1540 + /* xB[i] = ... + alfa * xN[q] + ..., and due to s we need to
270.1541 + consider the only case when xN[q] is increasing */
270.1542 + if (alfa > 0.0)
270.1543 + { /* xB[i] is increasing */
270.1544 + if (phase == 1 && coef[k] < 0.0)
270.1545 + { /* xB[i] violates its lower bound, which plays the role
270.1546 + of an upper bound on phase I */
270.1547 + t = (lb[k] - bbar[i]) / alfa;
270.1548 + i_stat = GLP_NL;
270.1549 + }
270.1550 + else if (phase == 1 && coef[k] > 0.0)
270.1551 + { /* xB[i] violates its upper bound, which plays the role
270.1552 + of an lower bound on phase I */
270.1553 + continue;
270.1554 + }
270.1555 + else if (type[k] == GLP_UP || type[k] == GLP_DB ||
270.1556 + type[k] == GLP_FX)
270.1557 + { /* xB[i] is within its bounds and has an upper bound */
270.1558 + t = (ub[k] - bbar[i]) / alfa;
270.1559 + i_stat = GLP_NU;
270.1560 + }
270.1561 + else
270.1562 + { /* xB[i] is within its bounds and has no upper bound */
270.1563 + continue;
270.1564 + }
270.1565 + }
270.1566 + else
270.1567 + { /* xB[i] is decreasing */
270.1568 + if (phase == 1 && coef[k] > 0.0)
270.1569 + { /* xB[i] violates its upper bound, which plays the role
270.1570 + of an lower bound on phase I */
270.1571 + t = (ub[k] - bbar[i]) / alfa;
270.1572 + i_stat = GLP_NU;
270.1573 + }
270.1574 + else if (phase == 1 && coef[k] < 0.0)
270.1575 + { /* xB[i] violates its lower bound, which plays the role
270.1576 + of an upper bound on phase I */
270.1577 + continue;
270.1578 + }
270.1579 + else if (type[k] == GLP_LO || type[k] == GLP_DB ||
270.1580 + type[k] == GLP_FX)
270.1581 + { /* xB[i] is within its bounds and has an lower bound */
270.1582 + t = (lb[k] - bbar[i]) / alfa;
270.1583 + i_stat = GLP_NL;
270.1584 + }
270.1585 + else
270.1586 + { /* xB[i] is within its bounds and has no lower bound */
270.1587 + continue;
270.1588 + }
270.1589 + }
270.1590 + /* (see comments for the first pass) */
270.1591 + if (t < 0.0) t = 0.0;
270.1592 + /* t is a change of xN[q], on which xB[i] reaches its bound;
270.1593 + if t <= tmax, all basic variables can violate their bounds
270.1594 + only within relaxation tolerance delta; we can use this
270.1595 + freedom and choose basic variable having largest influence
270.1596 + coefficient to avoid possible numeric instability */
270.1597 + if (t <= tmax && big < fabs(alfa))
270.1598 + p = i, p_stat = i_stat, teta = t, big = fabs(alfa);
270.1599 + }
270.1600 + /* something must be chosen on the second pass */
270.1601 + xassert(p != 0);
270.1602 +done: /* store the index and status of basic variable xB[p] chosen */
270.1603 + csa->p = p;
270.1604 + if (p > 0 && type[head[p]] == GLP_FX)
270.1605 + csa->p_stat = GLP_NS;
270.1606 + else
270.1607 + csa->p_stat = p_stat;
270.1608 + /* store corresponding change of non-basic variable xN[q] */
270.1609 +#ifdef GLP_DEBUG
270.1610 + xassert(teta >= 0.0);
270.1611 +#endif
270.1612 + csa->teta = s * teta;
270.1613 + return;
270.1614 +}
270.1615 +
270.1616 +/***********************************************************************
270.1617 +* eval_rho - compute pivot row of the inverse
270.1618 +*
270.1619 +* This routine computes the pivot (p-th) row of the inverse inv(B),
270.1620 +* which corresponds to basic variable xB[p] chosen:
270.1621 +*
270.1622 +* rho = inv(B') * e[p],
270.1623 +*
270.1624 +* where B' is a matrix transposed to the current basis matrix, e[p]
270.1625 +* is unity vector. */
270.1626 +
270.1627 +static void eval_rho(struct csa *csa, double rho[])
270.1628 +{ int m = csa->m;
270.1629 + int p = csa->p;
270.1630 + double *e = rho;
270.1631 + int i;
270.1632 +#ifdef GLP_DEBUG
270.1633 + xassert(1 <= p && p <= m);
270.1634 +#endif
270.1635 + /* construct the right-hand side vector e[p] */
270.1636 + for (i = 1; i <= m; i++)
270.1637 + e[i] = 0.0;
270.1638 + e[p] = 1.0;
270.1639 + /* solve system B'* rho = e[p] */
270.1640 + xassert(csa->valid);
270.1641 + bfd_btran(csa->bfd, rho);
270.1642 + return;
270.1643 +}
270.1644 +
270.1645 +/***********************************************************************
270.1646 +* refine_rho - refine pivot row of the inverse
270.1647 +*
270.1648 +* This routine refines the pivot row of the inverse inv(B) assuming
270.1649 +* that it was previously computed by the routine eval_rho. */
270.1650 +
270.1651 +static void refine_rho(struct csa *csa, double rho[])
270.1652 +{ int m = csa->m;
270.1653 + int p = csa->p;
270.1654 + double *e = csa->work3;
270.1655 + int i;
270.1656 +#ifdef GLP_DEBUG
270.1657 + xassert(1 <= p && p <= m);
270.1658 +#endif
270.1659 + /* construct the right-hand side vector e[p] */
270.1660 + for (i = 1; i <= m; i++)
270.1661 + e[i] = 0.0;
270.1662 + e[p] = 1.0;
270.1663 + /* refine solution of B'* rho = e[p] */
270.1664 + refine_btran(csa, e, rho);
270.1665 + return;
270.1666 +}
270.1667 +
270.1668 +/***********************************************************************
270.1669 +* eval_trow - compute pivot row of the simplex table
270.1670 +*
270.1671 +* This routine computes the pivot row of the simplex table, which
270.1672 +* corresponds to basic variable xB[p] chosen.
270.1673 +*
270.1674 +* The pivot row is the following vector:
270.1675 +*
270.1676 +* trow = T'* e[p] = - N'* inv(B') * e[p] = - N' * rho,
270.1677 +*
270.1678 +* where rho is the pivot row of the inverse inv(B) previously computed
270.1679 +* by the routine eval_rho.
270.1680 +*
270.1681 +* Note that elements of the pivot row corresponding to fixed non-basic
270.1682 +* variables are not computed. */
270.1683 +
270.1684 +static void eval_trow(struct csa *csa, double rho[])
270.1685 +{ int m = csa->m;
270.1686 + int n = csa->n;
270.1687 +#ifdef GLP_DEBUG
270.1688 + char *stat = csa->stat;
270.1689 +#endif
270.1690 + int *N_ptr = csa->N_ptr;
270.1691 + int *N_len = csa->N_len;
270.1692 + int *N_ind = csa->N_ind;
270.1693 + double *N_val = csa->N_val;
270.1694 + int *trow_ind = csa->trow_ind;
270.1695 + double *trow_vec = csa->trow_vec;
270.1696 + int i, j, beg, end, ptr, nnz;
270.1697 + double temp;
270.1698 + /* clear the pivot row */
270.1699 + for (j = 1; j <= n; j++)
270.1700 + trow_vec[j] = 0.0;
270.1701 + /* compute the pivot row as a linear combination of rows of the
270.1702 + matrix N: trow = - rho[1] * N'[1] - ... - rho[m] * N'[m] */
270.1703 + for (i = 1; i <= m; i++)
270.1704 + { temp = rho[i];
270.1705 + if (temp == 0.0) continue;
270.1706 + /* trow := trow - rho[i] * N'[i] */
270.1707 + beg = N_ptr[i];
270.1708 + end = beg + N_len[i];
270.1709 + for (ptr = beg; ptr < end; ptr++)
270.1710 + {
270.1711 +#ifdef GLP_DEBUG
270.1712 + j = N_ind[ptr];
270.1713 + xassert(1 <= j && j <= n);
270.1714 + xassert(stat[j] != GLP_NS);
270.1715 +#endif
270.1716 + trow_vec[N_ind[ptr]] -= temp * N_val[ptr];
270.1717 + }
270.1718 + }
270.1719 + /* construct sparse pattern of the pivot row */
270.1720 + nnz = 0;
270.1721 + for (j = 1; j <= n; j++)
270.1722 + { if (trow_vec[j] != 0.0)
270.1723 + trow_ind[++nnz] = j;
270.1724 + }
270.1725 + csa->trow_nnz = nnz;
270.1726 + return;
270.1727 +}
270.1728 +
270.1729 +/***********************************************************************
270.1730 +* update_bbar - update values of basic variables
270.1731 +*
270.1732 +* This routine updates values of all basic variables for the adjacent
270.1733 +* basis. */
270.1734 +
270.1735 +static void update_bbar(struct csa *csa)
270.1736 +{
270.1737 +#ifdef GLP_DEBUG
270.1738 + int m = csa->m;
270.1739 + int n = csa->n;
270.1740 +#endif
270.1741 + double *bbar = csa->bbar;
270.1742 + int q = csa->q;
270.1743 + int tcol_nnz = csa->tcol_nnz;
270.1744 + int *tcol_ind = csa->tcol_ind;
270.1745 + double *tcol_vec = csa->tcol_vec;
270.1746 + int p = csa->p;
270.1747 + double teta = csa->teta;
270.1748 + int i, pos;
270.1749 +#ifdef GLP_DEBUG
270.1750 + xassert(1 <= q && q <= n);
270.1751 + xassert(p < 0 || 1 <= p && p <= m);
270.1752 +#endif
270.1753 + /* if xN[q] leaves the basis, compute its value in the adjacent
270.1754 + basis, where it will replace xB[p] */
270.1755 + if (p > 0)
270.1756 + bbar[p] = get_xN(csa, q) + teta;
270.1757 + /* update values of other basic variables (except xB[p], because
270.1758 + it will be replaced by xN[q]) */
270.1759 + if (teta == 0.0) goto done;
270.1760 + for (pos = 1; pos <= tcol_nnz; pos++)
270.1761 + { i = tcol_ind[pos];
270.1762 + /* skip xB[p] */
270.1763 + if (i == p) continue;
270.1764 + /* (change of xB[i]) = alfa[i,q] * (change of xN[q]) */
270.1765 + bbar[i] += tcol_vec[i] * teta;
270.1766 + }
270.1767 +done: return;
270.1768 +}
270.1769 +
270.1770 +/***********************************************************************
270.1771 +* reeval_cost - recompute reduced cost of non-basic variable xN[q]
270.1772 +*
270.1773 +* This routine recomputes reduced cost of non-basic variable xN[q] for
270.1774 +* the current basis more accurately using its direct definition:
270.1775 +*
270.1776 +* d[q] = cN[q] - N'[q] * pi =
270.1777 +*
270.1778 +* = cN[q] - N'[q] * (inv(B') * cB) =
270.1779 +*
270.1780 +* = cN[q] - (cB' * inv(B) * N[q]) =
270.1781 +*
270.1782 +* = cN[q] + cB' * (pivot column).
270.1783 +*
270.1784 +* It is assumed that the pivot column of the simplex table is already
270.1785 +* computed. */
270.1786 +
270.1787 +static double reeval_cost(struct csa *csa)
270.1788 +{ int m = csa->m;
270.1789 +#ifdef GLP_DEBUG
270.1790 + int n = csa->n;
270.1791 +#endif
270.1792 + double *coef = csa->coef;
270.1793 + int *head = csa->head;
270.1794 + int q = csa->q;
270.1795 + int tcol_nnz = csa->tcol_nnz;
270.1796 + int *tcol_ind = csa->tcol_ind;
270.1797 + double *tcol_vec = csa->tcol_vec;
270.1798 + int i, pos;
270.1799 + double dq;
270.1800 +#ifdef GLP_DEBUG
270.1801 + xassert(1 <= q && q <= n);
270.1802 +#endif
270.1803 + dq = coef[head[m+q]];
270.1804 + for (pos = 1; pos <= tcol_nnz; pos++)
270.1805 + { i = tcol_ind[pos];
270.1806 +#ifdef GLP_DEBUG
270.1807 + xassert(1 <= i && i <= m);
270.1808 +#endif
270.1809 + dq += coef[head[i]] * tcol_vec[i];
270.1810 + }
270.1811 + return dq;
270.1812 +}
270.1813 +
270.1814 +/***********************************************************************
270.1815 +* update_cbar - update reduced costs of non-basic variables
270.1816 +*
270.1817 +* This routine updates reduced costs of all (except fixed) non-basic
270.1818 +* variables for the adjacent basis. */
270.1819 +
270.1820 +static void update_cbar(struct csa *csa)
270.1821 +{
270.1822 +#ifdef GLP_DEBUG
270.1823 + int n = csa->n;
270.1824 +#endif
270.1825 + double *cbar = csa->cbar;
270.1826 + int q = csa->q;
270.1827 + int trow_nnz = csa->trow_nnz;
270.1828 + int *trow_ind = csa->trow_ind;
270.1829 + double *trow_vec = csa->trow_vec;
270.1830 + int j, pos;
270.1831 + double new_dq;
270.1832 +#ifdef GLP_DEBUG
270.1833 + xassert(1 <= q && q <= n);
270.1834 +#endif
270.1835 + /* compute reduced cost of xB[p] in the adjacent basis, where it
270.1836 + will replace xN[q] */
270.1837 +#ifdef GLP_DEBUG
270.1838 + xassert(trow_vec[q] != 0.0);
270.1839 +#endif
270.1840 + new_dq = (cbar[q] /= trow_vec[q]);
270.1841 + /* update reduced costs of other non-basic variables (except
270.1842 + xN[q], because it will be replaced by xB[p]) */
270.1843 + for (pos = 1; pos <= trow_nnz; pos++)
270.1844 + { j = trow_ind[pos];
270.1845 + /* skip xN[q] */
270.1846 + if (j == q) continue;
270.1847 + cbar[j] -= trow_vec[j] * new_dq;
270.1848 + }
270.1849 + return;
270.1850 +}
270.1851 +
270.1852 +/***********************************************************************
270.1853 +* update_gamma - update steepest edge coefficients
270.1854 +*
270.1855 +* This routine updates steepest-edge coefficients for the adjacent
270.1856 +* basis. */
270.1857 +
270.1858 +static void update_gamma(struct csa *csa)
270.1859 +{ int m = csa->m;
270.1860 +#ifdef GLP_DEBUG
270.1861 + int n = csa->n;
270.1862 +#endif
270.1863 + char *type = csa->type;
270.1864 + int *A_ptr = csa->A_ptr;
270.1865 + int *A_ind = csa->A_ind;
270.1866 + double *A_val = csa->A_val;
270.1867 + int *head = csa->head;
270.1868 + char *refsp = csa->refsp;
270.1869 + double *gamma = csa->gamma;
270.1870 + int q = csa->q;
270.1871 + int tcol_nnz = csa->tcol_nnz;
270.1872 + int *tcol_ind = csa->tcol_ind;
270.1873 + double *tcol_vec = csa->tcol_vec;
270.1874 + int p = csa->p;
270.1875 + int trow_nnz = csa->trow_nnz;
270.1876 + int *trow_ind = csa->trow_ind;
270.1877 + double *trow_vec = csa->trow_vec;
270.1878 + double *u = csa->work3;
270.1879 + int i, j, k, pos, beg, end, ptr;
270.1880 + double gamma_q, delta_q, pivot, s, t, t1, t2;
270.1881 +#ifdef GLP_DEBUG
270.1882 + xassert(1 <= p && p <= m);
270.1883 + xassert(1 <= q && q <= n);
270.1884 +#endif
270.1885 + /* the basis changes, so decrease the count */
270.1886 + xassert(csa->refct > 0);
270.1887 + csa->refct--;
270.1888 + /* recompute gamma[q] for the current basis more accurately and
270.1889 + compute auxiliary vector u */
270.1890 + gamma_q = delta_q = (refsp[head[m+q]] ? 1.0 : 0.0);
270.1891 + for (i = 1; i <= m; i++) u[i] = 0.0;
270.1892 + for (pos = 1; pos <= tcol_nnz; pos++)
270.1893 + { i = tcol_ind[pos];
270.1894 + if (refsp[head[i]])
270.1895 + { u[i] = t = tcol_vec[i];
270.1896 + gamma_q += t * t;
270.1897 + }
270.1898 + else
270.1899 + u[i] = 0.0;
270.1900 + }
270.1901 + xassert(csa->valid);
270.1902 + bfd_btran(csa->bfd, u);
270.1903 + /* update gamma[k] for other non-basic variables (except fixed
270.1904 + variables and xN[q], because it will be replaced by xB[p]) */
270.1905 + pivot = trow_vec[q];
270.1906 +#ifdef GLP_DEBUG
270.1907 + xassert(pivot != 0.0);
270.1908 +#endif
270.1909 + for (pos = 1; pos <= trow_nnz; pos++)
270.1910 + { j = trow_ind[pos];
270.1911 + /* skip xN[q] */
270.1912 + if (j == q) continue;
270.1913 + /* compute t */
270.1914 + t = trow_vec[j] / pivot;
270.1915 + /* compute inner product s = N'[j] * u */
270.1916 + k = head[m+j]; /* x[k] = xN[j] */
270.1917 + if (k <= m)
270.1918 + s = u[k];
270.1919 + else
270.1920 + { s = 0.0;
270.1921 + beg = A_ptr[k-m];
270.1922 + end = A_ptr[k-m+1];
270.1923 + for (ptr = beg; ptr < end; ptr++)
270.1924 + s -= A_val[ptr] * u[A_ind[ptr]];
270.1925 + }
270.1926 + /* compute gamma[k] for the adjacent basis */
270.1927 + t1 = gamma[j] + t * t * gamma_q + 2.0 * t * s;
270.1928 + t2 = (refsp[k] ? 1.0 : 0.0) + delta_q * t * t;
270.1929 + gamma[j] = (t1 >= t2 ? t1 : t2);
270.1930 + if (gamma[j] < DBL_EPSILON) gamma[j] = DBL_EPSILON;
270.1931 + }
270.1932 + /* compute gamma[q] for the adjacent basis */
270.1933 + if (type[head[p]] == GLP_FX)
270.1934 + gamma[q] = 1.0;
270.1935 + else
270.1936 + { gamma[q] = gamma_q / (pivot * pivot);
270.1937 + if (gamma[q] < DBL_EPSILON) gamma[q] = DBL_EPSILON;
270.1938 + }
270.1939 + return;
270.1940 +}
270.1941 +
270.1942 +/***********************************************************************
270.1943 +* err_in_bbar - compute maximal relative error in primal solution
270.1944 +*
270.1945 +* This routine returns maximal relative error:
270.1946 +*
270.1947 +* max |beta[i] - bbar[i]| / (1 + |beta[i]|),
270.1948 +*
270.1949 +* where beta and bbar are, respectively, directly computed and the
270.1950 +* current (updated) values of basic variables.
270.1951 +*
270.1952 +* NOTE: The routine is intended only for debugginig purposes. */
270.1953 +
270.1954 +static double err_in_bbar(struct csa *csa)
270.1955 +{ int m = csa->m;
270.1956 + double *bbar = csa->bbar;
270.1957 + int i;
270.1958 + double e, emax, *beta;
270.1959 + beta = xcalloc(1+m, sizeof(double));
270.1960 + eval_beta(csa, beta);
270.1961 + emax = 0.0;
270.1962 + for (i = 1; i <= m; i++)
270.1963 + { e = fabs(beta[i] - bbar[i]) / (1.0 + fabs(beta[i]));
270.1964 + if (emax < e) emax = e;
270.1965 + }
270.1966 + xfree(beta);
270.1967 + return emax;
270.1968 +}
270.1969 +
270.1970 +/***********************************************************************
270.1971 +* err_in_cbar - compute maximal relative error in dual solution
270.1972 +*
270.1973 +* This routine returns maximal relative error:
270.1974 +*
270.1975 +* max |cost[j] - cbar[j]| / (1 + |cost[j]|),
270.1976 +*
270.1977 +* where cost and cbar are, respectively, directly computed and the
270.1978 +* current (updated) reduced costs of non-basic non-fixed variables.
270.1979 +*
270.1980 +* NOTE: The routine is intended only for debugginig purposes. */
270.1981 +
270.1982 +static double err_in_cbar(struct csa *csa)
270.1983 +{ int m = csa->m;
270.1984 + int n = csa->n;
270.1985 + char *stat = csa->stat;
270.1986 + double *cbar = csa->cbar;
270.1987 + int j;
270.1988 + double e, emax, cost, *pi;
270.1989 + pi = xcalloc(1+m, sizeof(double));
270.1990 + eval_pi(csa, pi);
270.1991 + emax = 0.0;
270.1992 + for (j = 1; j <= n; j++)
270.1993 + { if (stat[j] == GLP_NS) continue;
270.1994 + cost = eval_cost(csa, pi, j);
270.1995 + e = fabs(cost - cbar[j]) / (1.0 + fabs(cost));
270.1996 + if (emax < e) emax = e;
270.1997 + }
270.1998 + xfree(pi);
270.1999 + return emax;
270.2000 +}
270.2001 +
270.2002 +/***********************************************************************
270.2003 +* err_in_gamma - compute maximal relative error in steepest edge cff.
270.2004 +*
270.2005 +* This routine returns maximal relative error:
270.2006 +*
270.2007 +* max |gamma'[j] - gamma[j]| / (1 + |gamma'[j]),
270.2008 +*
270.2009 +* where gamma'[j] and gamma[j] are, respectively, directly computed
270.2010 +* and the current (updated) steepest edge coefficients for non-basic
270.2011 +* non-fixed variable x[j].
270.2012 +*
270.2013 +* NOTE: The routine is intended only for debugginig purposes. */
270.2014 +
270.2015 +static double err_in_gamma(struct csa *csa)
270.2016 +{ int n = csa->n;
270.2017 + char *stat = csa->stat;
270.2018 + double *gamma = csa->gamma;
270.2019 + int j;
270.2020 + double e, emax, temp;
270.2021 + emax = 0.0;
270.2022 + for (j = 1; j <= n; j++)
270.2023 + { if (stat[j] == GLP_NS)
270.2024 + { xassert(gamma[j] == 1.0);
270.2025 + continue;
270.2026 + }
270.2027 + temp = eval_gamma(csa, j);
270.2028 + e = fabs(temp - gamma[j]) / (1.0 + fabs(temp));
270.2029 + if (emax < e) emax = e;
270.2030 + }
270.2031 + return emax;
270.2032 +}
270.2033 +
270.2034 +/***********************************************************************
270.2035 +* change_basis - change basis header
270.2036 +*
270.2037 +* This routine changes the basis header to make it corresponding to
270.2038 +* the adjacent basis. */
270.2039 +
270.2040 +static void change_basis(struct csa *csa)
270.2041 +{ int m = csa->m;
270.2042 +#ifdef GLP_DEBUG
270.2043 + int n = csa->n;
270.2044 + char *type = csa->type;
270.2045 +#endif
270.2046 + int *head = csa->head;
270.2047 + char *stat = csa->stat;
270.2048 + int q = csa->q;
270.2049 + int p = csa->p;
270.2050 + int p_stat = csa->p_stat;
270.2051 + int k;
270.2052 +#ifdef GLP_DEBUG
270.2053 + xassert(1 <= q && q <= n);
270.2054 +#endif
270.2055 + if (p < 0)
270.2056 + { /* xN[q] goes to its opposite bound */
270.2057 +#ifdef GLP_DEBUG
270.2058 + k = head[m+q]; /* x[k] = xN[q] */
270.2059 + xassert(1 <= k && k <= m+n);
270.2060 + xassert(type[k] == GLP_DB);
270.2061 +#endif
270.2062 + switch (stat[q])
270.2063 + { case GLP_NL:
270.2064 + /* xN[q] increases */
270.2065 + stat[q] = GLP_NU;
270.2066 + break;
270.2067 + case GLP_NU:
270.2068 + /* xN[q] decreases */
270.2069 + stat[q] = GLP_NL;
270.2070 + break;
270.2071 + default:
270.2072 + xassert(stat != stat);
270.2073 + }
270.2074 + }
270.2075 + else
270.2076 + { /* xB[p] leaves the basis, xN[q] enters the basis */
270.2077 +#ifdef GLP_DEBUG
270.2078 + xassert(1 <= p && p <= m);
270.2079 + k = head[p]; /* x[k] = xB[p] */
270.2080 + switch (p_stat)
270.2081 + { case GLP_NL:
270.2082 + /* xB[p] goes to its lower bound */
270.2083 + xassert(type[k] == GLP_LO || type[k] == GLP_DB);
270.2084 + break;
270.2085 + case GLP_NU:
270.2086 + /* xB[p] goes to its upper bound */
270.2087 + xassert(type[k] == GLP_UP || type[k] == GLP_DB);
270.2088 + break;
270.2089 + case GLP_NS:
270.2090 + /* xB[p] goes to its fixed value */
270.2091 + xassert(type[k] == GLP_NS);
270.2092 + break;
270.2093 + default:
270.2094 + xassert(p_stat != p_stat);
270.2095 + }
270.2096 +#endif
270.2097 + /* xB[p] <-> xN[q] */
270.2098 + k = head[p], head[p] = head[m+q], head[m+q] = k;
270.2099 + stat[q] = (char)p_stat;
270.2100 + }
270.2101 + return;
270.2102 +}
270.2103 +
270.2104 +/***********************************************************************
270.2105 +* set_aux_obj - construct auxiliary objective function
270.2106 +*
270.2107 +* The auxiliary objective function is a separable piecewise linear
270.2108 +* convex function, which is the sum of primal infeasibilities:
270.2109 +*
270.2110 +* z = t[1] + ... + t[m+n] -> minimize,
270.2111 +*
270.2112 +* where:
270.2113 +*
270.2114 +* / lb[k] - x[k], if x[k] < lb[k]
270.2115 +* |
270.2116 +* t[k] = < 0, if lb[k] <= x[k] <= ub[k]
270.2117 +* |
270.2118 +* \ x[k] - ub[k], if x[k] > ub[k]
270.2119 +*
270.2120 +* This routine computes objective coefficients for the current basis
270.2121 +* and returns the number of non-zero terms t[k]. */
270.2122 +
270.2123 +static int set_aux_obj(struct csa *csa, double tol_bnd)
270.2124 +{ int m = csa->m;
270.2125 + int n = csa->n;
270.2126 + char *type = csa->type;
270.2127 + double *lb = csa->lb;
270.2128 + double *ub = csa->ub;
270.2129 + double *coef = csa->coef;
270.2130 + int *head = csa->head;
270.2131 + double *bbar = csa->bbar;
270.2132 + int i, k, cnt = 0;
270.2133 + double eps;
270.2134 + /* use a bit more restrictive tolerance */
270.2135 + tol_bnd *= 0.90;
270.2136 + /* clear all objective coefficients */
270.2137 + for (k = 1; k <= m+n; k++)
270.2138 + coef[k] = 0.0;
270.2139 + /* walk through the list of basic variables */
270.2140 + for (i = 1; i <= m; i++)
270.2141 + { k = head[i]; /* x[k] = xB[i] */
270.2142 + if (type[k] == GLP_LO || type[k] == GLP_DB ||
270.2143 + type[k] == GLP_FX)
270.2144 + { /* x[k] has lower bound */
270.2145 + eps = tol_bnd * (1.0 + kappa * fabs(lb[k]));
270.2146 + if (bbar[i] < lb[k] - eps)
270.2147 + { /* and violates it */
270.2148 + coef[k] = -1.0;
270.2149 + cnt++;
270.2150 + }
270.2151 + }
270.2152 + if (type[k] == GLP_UP || type[k] == GLP_DB ||
270.2153 + type[k] == GLP_FX)
270.2154 + { /* x[k] has upper bound */
270.2155 + eps = tol_bnd * (1.0 + kappa * fabs(ub[k]));
270.2156 + if (bbar[i] > ub[k] + eps)
270.2157 + { /* and violates it */
270.2158 + coef[k] = +1.0;
270.2159 + cnt++;
270.2160 + }
270.2161 + }
270.2162 + }
270.2163 + return cnt;
270.2164 +}
270.2165 +
270.2166 +/***********************************************************************
270.2167 +* set_orig_obj - restore original objective function
270.2168 +*
270.2169 +* This routine assigns scaled original objective coefficients to the
270.2170 +* working objective function. */
270.2171 +
270.2172 +static void set_orig_obj(struct csa *csa)
270.2173 +{ int m = csa->m;
270.2174 + int n = csa->n;
270.2175 + double *coef = csa->coef;
270.2176 + double *obj = csa->obj;
270.2177 + double zeta = csa->zeta;
270.2178 + int i, j;
270.2179 + for (i = 1; i <= m; i++)
270.2180 + coef[i] = 0.0;
270.2181 + for (j = 1; j <= n; j++)
270.2182 + coef[m+j] = zeta * obj[j];
270.2183 + return;
270.2184 +}
270.2185 +
270.2186 +/***********************************************************************
270.2187 +* check_stab - check numerical stability of basic solution
270.2188 +*
270.2189 +* If the current basic solution is primal feasible (or pseudo feasible
270.2190 +* on phase I) within a tolerance, this routine returns zero, otherwise
270.2191 +* it returns non-zero. */
270.2192 +
270.2193 +static int check_stab(struct csa *csa, double tol_bnd)
270.2194 +{ int m = csa->m;
270.2195 +#ifdef GLP_DEBUG
270.2196 + int n = csa->n;
270.2197 +#endif
270.2198 + char *type = csa->type;
270.2199 + double *lb = csa->lb;
270.2200 + double *ub = csa->ub;
270.2201 + double *coef = csa->coef;
270.2202 + int *head = csa->head;
270.2203 + int phase = csa->phase;
270.2204 + double *bbar = csa->bbar;
270.2205 + int i, k;
270.2206 + double eps;
270.2207 + /* walk through the list of basic variables */
270.2208 + for (i = 1; i <= m; i++)
270.2209 + { k = head[i]; /* x[k] = xB[i] */
270.2210 +#ifdef GLP_DEBUG
270.2211 + xassert(1 <= k && k <= m+n);
270.2212 +#endif
270.2213 + if (phase == 1 && coef[k] < 0.0)
270.2214 + { /* x[k] must not be greater than its lower bound */
270.2215 +#ifdef GLP_DEBUG
270.2216 + xassert(type[k] == GLP_LO || type[k] == GLP_DB ||
270.2217 + type[k] == GLP_FX);
270.2218 +#endif
270.2219 + eps = tol_bnd * (1.0 + kappa * fabs(lb[k]));
270.2220 + if (bbar[i] > lb[k] + eps) return 1;
270.2221 + }
270.2222 + else if (phase == 1 && coef[k] > 0.0)
270.2223 + { /* x[k] must not be less than its upper bound */
270.2224 +#ifdef GLP_DEBUG
270.2225 + xassert(type[k] == GLP_UP || type[k] == GLP_DB ||
270.2226 + type[k] == GLP_FX);
270.2227 +#endif
270.2228 + eps = tol_bnd * (1.0 + kappa * fabs(ub[k]));
270.2229 + if (bbar[i] < ub[k] - eps) return 1;
270.2230 + }
270.2231 + else
270.2232 + { /* either phase = 1 and coef[k] = 0, or phase = 2 */
270.2233 + if (type[k] == GLP_LO || type[k] == GLP_DB ||
270.2234 + type[k] == GLP_FX)
270.2235 + { /* x[k] must not be less than its lower bound */
270.2236 + eps = tol_bnd * (1.0 + kappa * fabs(lb[k]));
270.2237 + if (bbar[i] < lb[k] - eps) return 1;
270.2238 + }
270.2239 + if (type[k] == GLP_UP || type[k] == GLP_DB ||
270.2240 + type[k] == GLP_FX)
270.2241 + { /* x[k] must not be greater then its upper bound */
270.2242 + eps = tol_bnd * (1.0 + kappa * fabs(ub[k]));
270.2243 + if (bbar[i] > ub[k] + eps) return 1;
270.2244 + }
270.2245 + }
270.2246 + }
270.2247 + /* basic solution is primal feasible within a tolerance */
270.2248 + return 0;
270.2249 +}
270.2250 +
270.2251 +/***********************************************************************
270.2252 +* check_feas - check primal feasibility of basic solution
270.2253 +*
270.2254 +* If the current basic solution is primal feasible within a tolerance,
270.2255 +* this routine returns zero, otherwise it returns non-zero. */
270.2256 +
270.2257 +static int check_feas(struct csa *csa, double tol_bnd)
270.2258 +{ int m = csa->m;
270.2259 +#ifdef GLP_DEBUG
270.2260 + int n = csa->n;
270.2261 + char *type = csa->type;
270.2262 +#endif
270.2263 + double *lb = csa->lb;
270.2264 + double *ub = csa->ub;
270.2265 + double *coef = csa->coef;
270.2266 + int *head = csa->head;
270.2267 + double *bbar = csa->bbar;
270.2268 + int i, k;
270.2269 + double eps;
270.2270 + xassert(csa->phase == 1);
270.2271 + /* walk through the list of basic variables */
270.2272 + for (i = 1; i <= m; i++)
270.2273 + { k = head[i]; /* x[k] = xB[i] */
270.2274 +#ifdef GLP_DEBUG
270.2275 + xassert(1 <= k && k <= m+n);
270.2276 +#endif
270.2277 + if (coef[k] < 0.0)
270.2278 + { /* check if x[k] still violates its lower bound */
270.2279 +#ifdef GLP_DEBUG
270.2280 + xassert(type[k] == GLP_LO || type[k] == GLP_DB ||
270.2281 + type[k] == GLP_FX);
270.2282 +#endif
270.2283 + eps = tol_bnd * (1.0 + kappa * fabs(lb[k]));
270.2284 + if (bbar[i] < lb[k] - eps) return 1;
270.2285 + }
270.2286 + else if (coef[k] > 0.0)
270.2287 + { /* check if x[k] still violates its upper bound */
270.2288 +#ifdef GLP_DEBUG
270.2289 + xassert(type[k] == GLP_UP || type[k] == GLP_DB ||
270.2290 + type[k] == GLP_FX);
270.2291 +#endif
270.2292 + eps = tol_bnd * (1.0 + kappa * fabs(ub[k]));
270.2293 + if (bbar[i] > ub[k] + eps) return 1;
270.2294 + }
270.2295 + }
270.2296 + /* basic solution is primal feasible within a tolerance */
270.2297 + return 0;
270.2298 +}
270.2299 +
270.2300 +/***********************************************************************
270.2301 +* eval_obj - compute original objective function
270.2302 +*
270.2303 +* This routine computes the current value of the original objective
270.2304 +* function. */
270.2305 +
270.2306 +static double eval_obj(struct csa *csa)
270.2307 +{ int m = csa->m;
270.2308 + int n = csa->n;
270.2309 + double *obj = csa->obj;
270.2310 + int *head = csa->head;
270.2311 + double *bbar = csa->bbar;
270.2312 + int i, j, k;
270.2313 + double sum;
270.2314 + sum = obj[0];
270.2315 + /* walk through the list of basic variables */
270.2316 + for (i = 1; i <= m; i++)
270.2317 + { k = head[i]; /* x[k] = xB[i] */
270.2318 +#ifdef GLP_DEBUG
270.2319 + xassert(1 <= k && k <= m+n);
270.2320 +#endif
270.2321 + if (k > m)
270.2322 + sum += obj[k-m] * bbar[i];
270.2323 + }
270.2324 + /* walk through the list of non-basic variables */
270.2325 + for (j = 1; j <= n; j++)
270.2326 + { k = head[m+j]; /* x[k] = xN[j] */
270.2327 +#ifdef GLP_DEBUG
270.2328 + xassert(1 <= k && k <= m+n);
270.2329 +#endif
270.2330 + if (k > m)
270.2331 + sum += obj[k-m] * get_xN(csa, j);
270.2332 + }
270.2333 + return sum;
270.2334 +}
270.2335 +
270.2336 +/***********************************************************************
270.2337 +* display - display the search progress
270.2338 +*
270.2339 +* This routine displays some information about the search progress
270.2340 +* that includes:
270.2341 +*
270.2342 +* the search phase;
270.2343 +*
270.2344 +* the number of simplex iterations performed by the solver;
270.2345 +*
270.2346 +* the original objective value;
270.2347 +*
270.2348 +* the sum of (scaled) primal infeasibilities;
270.2349 +*
270.2350 +* the number of basic fixed variables. */
270.2351 +
270.2352 +static void display(struct csa *csa, const glp_smcp *parm, int spec)
270.2353 +{ int m = csa->m;
270.2354 +#ifdef GLP_DEBUG
270.2355 + int n = csa->n;
270.2356 +#endif
270.2357 + char *type = csa->type;
270.2358 + double *lb = csa->lb;
270.2359 + double *ub = csa->ub;
270.2360 + int phase = csa->phase;
270.2361 + int *head = csa->head;
270.2362 + double *bbar = csa->bbar;
270.2363 + int i, k, cnt;
270.2364 + double sum;
270.2365 + if (parm->msg_lev < GLP_MSG_ON) goto skip;
270.2366 + if (parm->out_dly > 0 &&
270.2367 + 1000.0 * xdifftime(xtime(), csa->tm_beg) < parm->out_dly)
270.2368 + goto skip;
270.2369 + if (csa->it_cnt == csa->it_dpy) goto skip;
270.2370 + if (!spec && csa->it_cnt % parm->out_frq != 0) goto skip;
270.2371 + /* compute the sum of primal infeasibilities and determine the
270.2372 + number of basic fixed variables */
270.2373 + sum = 0.0, cnt = 0;
270.2374 + for (i = 1; i <= m; i++)
270.2375 + { k = head[i]; /* x[k] = xB[i] */
270.2376 +#ifdef GLP_DEBUG
270.2377 + xassert(1 <= k && k <= m+n);
270.2378 +#endif
270.2379 + if (type[k] == GLP_LO || type[k] == GLP_DB ||
270.2380 + type[k] == GLP_FX)
270.2381 + { /* x[k] has lower bound */
270.2382 + if (bbar[i] < lb[k])
270.2383 + sum += (lb[k] - bbar[i]);
270.2384 + }
270.2385 + if (type[k] == GLP_UP || type[k] == GLP_DB ||
270.2386 + type[k] == GLP_FX)
270.2387 + { /* x[k] has upper bound */
270.2388 + if (bbar[i] > ub[k])
270.2389 + sum += (bbar[i] - ub[k]);
270.2390 + }
270.2391 + if (type[k] == GLP_FX) cnt++;
270.2392 + }
270.2393 + xprintf("%c%6d: obj = %17.9e infeas = %10.3e (%d)\n",
270.2394 + phase == 1 ? ' ' : '*', csa->it_cnt, eval_obj(csa), sum, cnt);
270.2395 + csa->it_dpy = csa->it_cnt;
270.2396 +skip: return;
270.2397 +}
270.2398 +
270.2399 +/***********************************************************************
270.2400 +* store_sol - store basic solution back to the problem object
270.2401 +*
270.2402 +* This routine stores basic solution components back to the problem
270.2403 +* object. */
270.2404 +
270.2405 +static void store_sol(struct csa *csa, glp_prob *lp, int p_stat,
270.2406 + int d_stat, int ray)
270.2407 +{ int m = csa->m;
270.2408 + int n = csa->n;
270.2409 + double zeta = csa->zeta;
270.2410 + int *head = csa->head;
270.2411 + char *stat = csa->stat;
270.2412 + double *bbar = csa->bbar;
270.2413 + double *cbar = csa->cbar;
270.2414 + int i, j, k;
270.2415 +#ifdef GLP_DEBUG
270.2416 + xassert(lp->m == m);
270.2417 + xassert(lp->n == n);
270.2418 +#endif
270.2419 + /* basis factorization */
270.2420 +#ifdef GLP_DEBUG
270.2421 + xassert(!lp->valid && lp->bfd == NULL);
270.2422 + xassert(csa->valid && csa->bfd != NULL);
270.2423 +#endif
270.2424 + lp->valid = 1, csa->valid = 0;
270.2425 + lp->bfd = csa->bfd, csa->bfd = NULL;
270.2426 + memcpy(&lp->head[1], &head[1], m * sizeof(int));
270.2427 + /* basic solution status */
270.2428 + lp->pbs_stat = p_stat;
270.2429 + lp->dbs_stat = d_stat;
270.2430 + /* objective function value */
270.2431 + lp->obj_val = eval_obj(csa);
270.2432 + /* simplex iteration count */
270.2433 + lp->it_cnt = csa->it_cnt;
270.2434 + /* unbounded ray */
270.2435 + lp->some = ray;
270.2436 + /* basic variables */
270.2437 + for (i = 1; i <= m; i++)
270.2438 + { k = head[i]; /* x[k] = xB[i] */
270.2439 +#ifdef GLP_DEBUG
270.2440 + xassert(1 <= k && k <= m+n);
270.2441 +#endif
270.2442 + if (k <= m)
270.2443 + { GLPROW *row = lp->row[k];
270.2444 + row->stat = GLP_BS;
270.2445 + row->bind = i;
270.2446 + row->prim = bbar[i] / row->rii;
270.2447 + row->dual = 0.0;
270.2448 + }
270.2449 + else
270.2450 + { GLPCOL *col = lp->col[k-m];
270.2451 + col->stat = GLP_BS;
270.2452 + col->bind = i;
270.2453 + col->prim = bbar[i] * col->sjj;
270.2454 + col->dual = 0.0;
270.2455 + }
270.2456 + }
270.2457 + /* non-basic variables */
270.2458 + for (j = 1; j <= n; j++)
270.2459 + { k = head[m+j]; /* x[k] = xN[j] */
270.2460 +#ifdef GLP_DEBUG
270.2461 + xassert(1 <= k && k <= m+n);
270.2462 +#endif
270.2463 + if (k <= m)
270.2464 + { GLPROW *row = lp->row[k];
270.2465 + row->stat = stat[j];
270.2466 + row->bind = 0;
270.2467 +#if 0
270.2468 + row->prim = get_xN(csa, j) / row->rii;
270.2469 +#else
270.2470 + switch (stat[j])
270.2471 + { case GLP_NL:
270.2472 + row->prim = row->lb; break;
270.2473 + case GLP_NU:
270.2474 + row->prim = row->ub; break;
270.2475 + case GLP_NF:
270.2476 + row->prim = 0.0; break;
270.2477 + case GLP_NS:
270.2478 + row->prim = row->lb; break;
270.2479 + default:
270.2480 + xassert(stat != stat);
270.2481 + }
270.2482 +#endif
270.2483 + row->dual = (cbar[j] * row->rii) / zeta;
270.2484 + }
270.2485 + else
270.2486 + { GLPCOL *col = lp->col[k-m];
270.2487 + col->stat = stat[j];
270.2488 + col->bind = 0;
270.2489 +#if 0
270.2490 + col->prim = get_xN(csa, j) * col->sjj;
270.2491 +#else
270.2492 + switch (stat[j])
270.2493 + { case GLP_NL:
270.2494 + col->prim = col->lb; break;
270.2495 + case GLP_NU:
270.2496 + col->prim = col->ub; break;
270.2497 + case GLP_NF:
270.2498 + col->prim = 0.0; break;
270.2499 + case GLP_NS:
270.2500 + col->prim = col->lb; break;
270.2501 + default:
270.2502 + xassert(stat != stat);
270.2503 + }
270.2504 +#endif
270.2505 + col->dual = (cbar[j] / col->sjj) / zeta;
270.2506 + }
270.2507 + }
270.2508 + return;
270.2509 +}
270.2510 +
270.2511 +/***********************************************************************
270.2512 +* free_csa - deallocate common storage area
270.2513 +*
270.2514 +* This routine frees all the memory allocated to arrays in the common
270.2515 +* storage area (CSA). */
270.2516 +
270.2517 +static void free_csa(struct csa *csa)
270.2518 +{ xfree(csa->type);
270.2519 + xfree(csa->lb);
270.2520 + xfree(csa->ub);
270.2521 + xfree(csa->coef);
270.2522 + xfree(csa->obj);
270.2523 + xfree(csa->A_ptr);
270.2524 + xfree(csa->A_ind);
270.2525 + xfree(csa->A_val);
270.2526 + xfree(csa->head);
270.2527 + xfree(csa->stat);
270.2528 + xfree(csa->N_ptr);
270.2529 + xfree(csa->N_len);
270.2530 + xfree(csa->N_ind);
270.2531 + xfree(csa->N_val);
270.2532 + xfree(csa->bbar);
270.2533 + xfree(csa->cbar);
270.2534 + xfree(csa->refsp);
270.2535 + xfree(csa->gamma);
270.2536 + xfree(csa->tcol_ind);
270.2537 + xfree(csa->tcol_vec);
270.2538 + xfree(csa->trow_ind);
270.2539 + xfree(csa->trow_vec);
270.2540 + xfree(csa->work1);
270.2541 + xfree(csa->work2);
270.2542 + xfree(csa->work3);
270.2543 + xfree(csa->work4);
270.2544 + xfree(csa);
270.2545 + return;
270.2546 +}
270.2547 +
270.2548 +/***********************************************************************
270.2549 +* spx_primal - core LP solver based on the primal simplex method
270.2550 +*
270.2551 +* SYNOPSIS
270.2552 +*
270.2553 +* #include "glpspx.h"
270.2554 +* int spx_primal(glp_prob *lp, const glp_smcp *parm);
270.2555 +*
270.2556 +* DESCRIPTION
270.2557 +*
270.2558 +* The routine spx_primal is a core LP solver based on the two-phase
270.2559 +* primal simplex method.
270.2560 +*
270.2561 +* RETURNS
270.2562 +*
270.2563 +* 0 LP instance has been successfully solved.
270.2564 +*
270.2565 +* GLP_EITLIM
270.2566 +* Iteration limit has been exhausted.
270.2567 +*
270.2568 +* GLP_ETMLIM
270.2569 +* Time limit has been exhausted.
270.2570 +*
270.2571 +* GLP_EFAIL
270.2572 +* The solver failed to solve LP instance. */
270.2573 +
270.2574 +int spx_primal(glp_prob *lp, const glp_smcp *parm)
270.2575 +{ struct csa *csa;
270.2576 + int binv_st = 2;
270.2577 + /* status of basis matrix factorization:
270.2578 + 0 - invalid; 1 - just computed; 2 - updated */
270.2579 + int bbar_st = 0;
270.2580 + /* status of primal values of basic variables:
270.2581 + 0 - invalid; 1 - just computed; 2 - updated */
270.2582 + int cbar_st = 0;
270.2583 + /* status of reduced costs of non-basic variables:
270.2584 + 0 - invalid; 1 - just computed; 2 - updated */
270.2585 + int rigorous = 0;
270.2586 + /* rigorous mode flag; this flag is used to enable iterative
270.2587 + refinement on computing pivot rows and columns of the simplex
270.2588 + table */
270.2589 + int check = 0;
270.2590 + int p_stat, d_stat, ret;
270.2591 + /* allocate and initialize the common storage area */
270.2592 + csa = alloc_csa(lp);
270.2593 + init_csa(csa, lp);
270.2594 + if (parm->msg_lev >= GLP_MSG_DBG)
270.2595 + xprintf("Objective scale factor = %g\n", csa->zeta);
270.2596 +loop: /* main loop starts here */
270.2597 + /* compute factorization of the basis matrix */
270.2598 + if (binv_st == 0)
270.2599 + { ret = invert_B(csa);
270.2600 + if (ret != 0)
270.2601 + { if (parm->msg_lev >= GLP_MSG_ERR)
270.2602 + { xprintf("Error: unable to factorize the basis matrix (%d"
270.2603 + ")\n", ret);
270.2604 + xprintf("Sorry, basis recovery procedure not implemented"
270.2605 + " yet\n");
270.2606 + }
270.2607 + xassert(!lp->valid && lp->bfd == NULL);
270.2608 + lp->bfd = csa->bfd, csa->bfd = NULL;
270.2609 + lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
270.2610 + lp->obj_val = 0.0;
270.2611 + lp->it_cnt = csa->it_cnt;
270.2612 + lp->some = 0;
270.2613 + ret = GLP_EFAIL;
270.2614 + goto done;
270.2615 + }
270.2616 + csa->valid = 1;
270.2617 + binv_st = 1; /* just computed */
270.2618 + /* invalidate basic solution components */
270.2619 + bbar_st = cbar_st = 0;
270.2620 + }
270.2621 + /* compute primal values of basic variables */
270.2622 + if (bbar_st == 0)
270.2623 + { eval_bbar(csa);
270.2624 + bbar_st = 1; /* just computed */
270.2625 + /* determine the search phase, if not determined yet */
270.2626 + if (csa->phase == 0)
270.2627 + { if (set_aux_obj(csa, parm->tol_bnd) > 0)
270.2628 + { /* current basic solution is primal infeasible */
270.2629 + /* start to minimize the sum of infeasibilities */
270.2630 + csa->phase = 1;
270.2631 + }
270.2632 + else
270.2633 + { /* current basic solution is primal feasible */
270.2634 + /* start to minimize the original objective function */
270.2635 + set_orig_obj(csa);
270.2636 + csa->phase = 2;
270.2637 + }
270.2638 + xassert(check_stab(csa, parm->tol_bnd) == 0);
270.2639 + /* working objective coefficients have been changed, so
270.2640 + invalidate reduced costs */
270.2641 + cbar_st = 0;
270.2642 + display(csa, parm, 1);
270.2643 + }
270.2644 + /* make sure that the current basic solution remains primal
270.2645 + feasible (or pseudo feasible on phase I) */
270.2646 + if (check_stab(csa, parm->tol_bnd))
270.2647 + { /* there are excessive bound violations due to round-off
270.2648 + errors */
270.2649 + if (parm->msg_lev >= GLP_MSG_ERR)
270.2650 + xprintf("Warning: numerical instability (primal simplex,"
270.2651 + " phase %s)\n", csa->phase == 1 ? "I" : "II");
270.2652 + /* restart the search */
270.2653 + csa->phase = 0;
270.2654 + binv_st = 0;
270.2655 + rigorous = 5;
270.2656 + goto loop;
270.2657 + }
270.2658 + }
270.2659 + xassert(csa->phase == 1 || csa->phase == 2);
270.2660 + /* on phase I we do not need to wait until the current basic
270.2661 + solution becomes dual feasible; it is sufficient to make sure
270.2662 + that no basic variable violates its bounds */
270.2663 + if (csa->phase == 1 && !check_feas(csa, parm->tol_bnd))
270.2664 + { /* the current basis is primal feasible; switch to phase II */
270.2665 + csa->phase = 2;
270.2666 + set_orig_obj(csa);
270.2667 + cbar_st = 0;
270.2668 + display(csa, parm, 1);
270.2669 + }
270.2670 + /* compute reduced costs of non-basic variables */
270.2671 + if (cbar_st == 0)
270.2672 + { eval_cbar(csa);
270.2673 + cbar_st = 1; /* just computed */
270.2674 + }
270.2675 + /* redefine the reference space, if required */
270.2676 + switch (parm->pricing)
270.2677 + { case GLP_PT_STD:
270.2678 + break;
270.2679 + case GLP_PT_PSE:
270.2680 + if (csa->refct == 0) reset_refsp(csa);
270.2681 + break;
270.2682 + default:
270.2683 + xassert(parm != parm);
270.2684 + }
270.2685 + /* at this point the basis factorization and all basic solution
270.2686 + components are valid */
270.2687 + xassert(binv_st && bbar_st && cbar_st);
270.2688 + /* check accuracy of current basic solution components (only for
270.2689 + debugging) */
270.2690 + if (check)
270.2691 + { double e_bbar = err_in_bbar(csa);
270.2692 + double e_cbar = err_in_cbar(csa);
270.2693 + double e_gamma =
270.2694 + (parm->pricing == GLP_PT_PSE ? err_in_gamma(csa) : 0.0);
270.2695 + xprintf("e_bbar = %10.3e; e_cbar = %10.3e; e_gamma = %10.3e\n",
270.2696 + e_bbar, e_cbar, e_gamma);
270.2697 + xassert(e_bbar <= 1e-5 && e_cbar <= 1e-5 && e_gamma <= 1e-3);
270.2698 + }
270.2699 + /* check if the iteration limit has been exhausted */
270.2700 + if (parm->it_lim < INT_MAX &&
270.2701 + csa->it_cnt - csa->it_beg >= parm->it_lim)
270.2702 + { if (bbar_st != 1 || csa->phase == 2 && cbar_st != 1)
270.2703 + { if (bbar_st != 1) bbar_st = 0;
270.2704 + if (csa->phase == 2 && cbar_st != 1) cbar_st = 0;
270.2705 + goto loop;
270.2706 + }
270.2707 + display(csa, parm, 1);
270.2708 + if (parm->msg_lev >= GLP_MSG_ALL)
270.2709 + xprintf("ITERATION LIMIT EXCEEDED; SEARCH TERMINATED\n");
270.2710 + switch (csa->phase)
270.2711 + { case 1:
270.2712 + p_stat = GLP_INFEAS;
270.2713 + set_orig_obj(csa);
270.2714 + eval_cbar(csa);
270.2715 + break;
270.2716 + case 2:
270.2717 + p_stat = GLP_FEAS;
270.2718 + break;
270.2719 + default:
270.2720 + xassert(csa != csa);
270.2721 + }
270.2722 + chuzc(csa, parm->tol_dj);
270.2723 + d_stat = (csa->q == 0 ? GLP_FEAS : GLP_INFEAS);
270.2724 + store_sol(csa, lp, p_stat, d_stat, 0);
270.2725 + ret = GLP_EITLIM;
270.2726 + goto done;
270.2727 + }
270.2728 + /* check if the time limit has been exhausted */
270.2729 + if (parm->tm_lim < INT_MAX &&
270.2730 + 1000.0 * xdifftime(xtime(), csa->tm_beg) >= parm->tm_lim)
270.2731 + { if (bbar_st != 1 || csa->phase == 2 && cbar_st != 1)
270.2732 + { if (bbar_st != 1) bbar_st = 0;
270.2733 + if (csa->phase == 2 && cbar_st != 1) cbar_st = 0;
270.2734 + goto loop;
270.2735 + }
270.2736 + display(csa, parm, 1);
270.2737 + if (parm->msg_lev >= GLP_MSG_ALL)
270.2738 + xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
270.2739 + switch (csa->phase)
270.2740 + { case 1:
270.2741 + p_stat = GLP_INFEAS;
270.2742 + set_orig_obj(csa);
270.2743 + eval_cbar(csa);
270.2744 + break;
270.2745 + case 2:
270.2746 + p_stat = GLP_FEAS;
270.2747 + break;
270.2748 + default:
270.2749 + xassert(csa != csa);
270.2750 + }
270.2751 + chuzc(csa, parm->tol_dj);
270.2752 + d_stat = (csa->q == 0 ? GLP_FEAS : GLP_INFEAS);
270.2753 + store_sol(csa, lp, p_stat, d_stat, 0);
270.2754 + ret = GLP_ETMLIM;
270.2755 + goto done;
270.2756 + }
270.2757 + /* display the search progress */
270.2758 + display(csa, parm, 0);
270.2759 + /* choose non-basic variable xN[q] */
270.2760 + chuzc(csa, parm->tol_dj);
270.2761 + if (csa->q == 0)
270.2762 + { if (bbar_st != 1 || cbar_st != 1)
270.2763 + { if (bbar_st != 1) bbar_st = 0;
270.2764 + if (cbar_st != 1) cbar_st = 0;
270.2765 + goto loop;
270.2766 + }
270.2767 + display(csa, parm, 1);
270.2768 + switch (csa->phase)
270.2769 + { case 1:
270.2770 + if (parm->msg_lev >= GLP_MSG_ALL)
270.2771 + xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n");
270.2772 + p_stat = GLP_NOFEAS;
270.2773 + set_orig_obj(csa);
270.2774 + eval_cbar(csa);
270.2775 + chuzc(csa, parm->tol_dj);
270.2776 + d_stat = (csa->q == 0 ? GLP_FEAS : GLP_INFEAS);
270.2777 + break;
270.2778 + case 2:
270.2779 + if (parm->msg_lev >= GLP_MSG_ALL)
270.2780 + xprintf("OPTIMAL SOLUTION FOUND\n");
270.2781 + p_stat = d_stat = GLP_FEAS;
270.2782 + break;
270.2783 + default:
270.2784 + xassert(csa != csa);
270.2785 + }
270.2786 + store_sol(csa, lp, p_stat, d_stat, 0);
270.2787 + ret = 0;
270.2788 + goto done;
270.2789 + }
270.2790 + /* compute pivot column of the simplex table */
270.2791 + eval_tcol(csa);
270.2792 + if (rigorous) refine_tcol(csa);
270.2793 + sort_tcol(csa, parm->tol_piv);
270.2794 + /* check accuracy of the reduced cost of xN[q] */
270.2795 + { double d1 = csa->cbar[csa->q]; /* less accurate */
270.2796 + double d2 = reeval_cost(csa); /* more accurate */
270.2797 + xassert(d1 != 0.0);
270.2798 + if (fabs(d1 - d2) > 1e-5 * (1.0 + fabs(d2)) ||
270.2799 + !(d1 < 0.0 && d2 < 0.0 || d1 > 0.0 && d2 > 0.0))
270.2800 + { if (parm->msg_lev >= GLP_MSG_DBG)
270.2801 + xprintf("d1 = %.12g; d2 = %.12g\n", d1, d2);
270.2802 + if (cbar_st != 1 || !rigorous)
270.2803 + { if (cbar_st != 1) cbar_st = 0;
270.2804 + rigorous = 5;
270.2805 + goto loop;
270.2806 + }
270.2807 + }
270.2808 + /* replace cbar[q] by more accurate value keeping its sign */
270.2809 + if (d1 > 0.0)
270.2810 + csa->cbar[csa->q] = (d2 > 0.0 ? d2 : +DBL_EPSILON);
270.2811 + else
270.2812 + csa->cbar[csa->q] = (d2 < 0.0 ? d2 : -DBL_EPSILON);
270.2813 + }
270.2814 + /* choose basic variable xB[p] */
270.2815 + switch (parm->r_test)
270.2816 + { case GLP_RT_STD:
270.2817 + chuzr(csa, 0.0);
270.2818 + break;
270.2819 + case GLP_RT_HAR:
270.2820 + chuzr(csa, 0.30 * parm->tol_bnd);
270.2821 + break;
270.2822 + default:
270.2823 + xassert(parm != parm);
270.2824 + }
270.2825 + if (csa->p == 0)
270.2826 + { if (bbar_st != 1 || cbar_st != 1 || !rigorous)
270.2827 + { if (bbar_st != 1) bbar_st = 0;
270.2828 + if (cbar_st != 1) cbar_st = 0;
270.2829 + rigorous = 1;
270.2830 + goto loop;
270.2831 + }
270.2832 + display(csa, parm, 1);
270.2833 + switch (csa->phase)
270.2834 + { case 1:
270.2835 + if (parm->msg_lev >= GLP_MSG_ERR)
270.2836 + xprintf("Error: unable to choose basic variable on ph"
270.2837 + "ase I\n");
270.2838 + xassert(!lp->valid && lp->bfd == NULL);
270.2839 + lp->bfd = csa->bfd, csa->bfd = NULL;
270.2840 + lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
270.2841 + lp->obj_val = 0.0;
270.2842 + lp->it_cnt = csa->it_cnt;
270.2843 + lp->some = 0;
270.2844 + ret = GLP_EFAIL;
270.2845 + break;
270.2846 + case 2:
270.2847 + if (parm->msg_lev >= GLP_MSG_ALL)
270.2848 + xprintf("PROBLEM HAS UNBOUNDED SOLUTION\n");
270.2849 + store_sol(csa, lp, GLP_FEAS, GLP_NOFEAS,
270.2850 + csa->head[csa->m+csa->q]);
270.2851 + ret = 0;
270.2852 + break;
270.2853 + default:
270.2854 + xassert(csa != csa);
270.2855 + }
270.2856 + goto done;
270.2857 + }
270.2858 + /* check if the pivot element is acceptable */
270.2859 + if (csa->p > 0)
270.2860 + { double piv = csa->tcol_vec[csa->p];
270.2861 + double eps = 1e-5 * (1.0 + 0.01 * csa->tcol_max);
270.2862 + if (fabs(piv) < eps)
270.2863 + { if (parm->msg_lev >= GLP_MSG_DBG)
270.2864 + xprintf("piv = %.12g; eps = %g\n", piv, eps);
270.2865 + if (!rigorous)
270.2866 + { rigorous = 5;
270.2867 + goto loop;
270.2868 + }
270.2869 + }
270.2870 + }
270.2871 + /* now xN[q] and xB[p] have been chosen anyhow */
270.2872 + /* compute pivot row of the simplex table */
270.2873 + if (csa->p > 0)
270.2874 + { double *rho = csa->work4;
270.2875 + eval_rho(csa, rho);
270.2876 + if (rigorous) refine_rho(csa, rho);
270.2877 + eval_trow(csa, rho);
270.2878 + }
270.2879 + /* accuracy check based on the pivot element */
270.2880 + if (csa->p > 0)
270.2881 + { double piv1 = csa->tcol_vec[csa->p]; /* more accurate */
270.2882 + double piv2 = csa->trow_vec[csa->q]; /* less accurate */
270.2883 + xassert(piv1 != 0.0);
270.2884 + if (fabs(piv1 - piv2) > 1e-8 * (1.0 + fabs(piv1)) ||
270.2885 + !(piv1 > 0.0 && piv2 > 0.0 || piv1 < 0.0 && piv2 < 0.0))
270.2886 + { if (parm->msg_lev >= GLP_MSG_DBG)
270.2887 + xprintf("piv1 = %.12g; piv2 = %.12g\n", piv1, piv2);
270.2888 + if (binv_st != 1 || !rigorous)
270.2889 + { if (binv_st != 1) binv_st = 0;
270.2890 + rigorous = 5;
270.2891 + goto loop;
270.2892 + }
270.2893 + /* use more accurate version in the pivot row */
270.2894 + if (csa->trow_vec[csa->q] == 0.0)
270.2895 + { csa->trow_nnz++;
270.2896 + xassert(csa->trow_nnz <= csa->n);
270.2897 + csa->trow_ind[csa->trow_nnz] = csa->q;
270.2898 + }
270.2899 + csa->trow_vec[csa->q] = piv1;
270.2900 + }
270.2901 + }
270.2902 + /* update primal values of basic variables */
270.2903 + update_bbar(csa);
270.2904 + bbar_st = 2; /* updated */
270.2905 + /* update reduced costs of non-basic variables */
270.2906 + if (csa->p > 0)
270.2907 + { update_cbar(csa);
270.2908 + cbar_st = 2; /* updated */
270.2909 + /* on phase I objective coefficient of xB[p] in the adjacent
270.2910 + basis becomes zero */
270.2911 + if (csa->phase == 1)
270.2912 + { int k = csa->head[csa->p]; /* x[k] = xB[p] -> xN[q] */
270.2913 + csa->cbar[csa->q] -= csa->coef[k];
270.2914 + csa->coef[k] = 0.0;
270.2915 + }
270.2916 + }
270.2917 + /* update steepest edge coefficients */
270.2918 + if (csa->p > 0)
270.2919 + { switch (parm->pricing)
270.2920 + { case GLP_PT_STD:
270.2921 + break;
270.2922 + case GLP_PT_PSE:
270.2923 + if (csa->refct > 0) update_gamma(csa);
270.2924 + break;
270.2925 + default:
270.2926 + xassert(parm != parm);
270.2927 + }
270.2928 + }
270.2929 + /* update factorization of the basis matrix */
270.2930 + if (csa->p > 0)
270.2931 + { ret = update_B(csa, csa->p, csa->head[csa->m+csa->q]);
270.2932 + if (ret == 0)
270.2933 + binv_st = 2; /* updated */
270.2934 + else
270.2935 + { csa->valid = 0;
270.2936 + binv_st = 0; /* invalid */
270.2937 + }
270.2938 + }
270.2939 + /* update matrix N */
270.2940 + if (csa->p > 0)
270.2941 + { del_N_col(csa, csa->q, csa->head[csa->m+csa->q]);
270.2942 + if (csa->type[csa->head[csa->p]] != GLP_FX)
270.2943 + add_N_col(csa, csa->q, csa->head[csa->p]);
270.2944 + }
270.2945 + /* change the basis header */
270.2946 + change_basis(csa);
270.2947 + /* iteration complete */
270.2948 + csa->it_cnt++;
270.2949 + if (rigorous > 0) rigorous--;
270.2950 + goto loop;
270.2951 +done: /* deallocate the common storage area */
270.2952 + free_csa(csa);
270.2953 + /* return to the calling program */
270.2954 + return ret;
270.2955 +}
270.2956 +
270.2957 +/* eof */
271.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
271.2 +++ b/src/glpspx02.c Mon Dec 06 13:09:21 2010 +0100
271.3 @@ -0,0 +1,3077 @@
271.4 +/* glpspx02.c (dual simplex method) */
271.5 +
271.6 +/***********************************************************************
271.7 +* This code is part of GLPK (GNU Linear Programming Kit).
271.8 +*
271.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
271.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
271.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
271.12 +* E-mail: <mao@gnu.org>.
271.13 +*
271.14 +* GLPK is free software: you can redistribute it and/or modify it
271.15 +* under the terms of the GNU General Public License as published by
271.16 +* the Free Software Foundation, either version 3 of the License, or
271.17 +* (at your option) any later version.
271.18 +*
271.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
271.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
271.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
271.22 +* License for more details.
271.23 +*
271.24 +* You should have received a copy of the GNU General Public License
271.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
271.26 +***********************************************************************/
271.27 +
271.28 +#include "glpspx.h"
271.29 +
271.30 +#define GLP_DEBUG 1
271.31 +
271.32 +#if 0
271.33 +#define GLP_LONG_STEP 1
271.34 +#endif
271.35 +
271.36 +struct csa
271.37 +{ /* common storage area */
271.38 + /*--------------------------------------------------------------*/
271.39 + /* LP data */
271.40 + int m;
271.41 + /* number of rows (auxiliary variables), m > 0 */
271.42 + int n;
271.43 + /* number of columns (structural variables), n > 0 */
271.44 + char *type; /* char type[1+m+n]; */
271.45 + /* type[0] is not used;
271.46 + type[k], 1 <= k <= m+n, is the type of variable x[k]:
271.47 + GLP_FR - free variable
271.48 + GLP_LO - variable with lower bound
271.49 + GLP_UP - variable with upper bound
271.50 + GLP_DB - double-bounded variable
271.51 + GLP_FX - fixed variable */
271.52 + double *lb; /* double lb[1+m+n]; */
271.53 + /* lb[0] is not used;
271.54 + lb[k], 1 <= k <= m+n, is an lower bound of variable x[k];
271.55 + if x[k] has no lower bound, lb[k] is zero */
271.56 + double *ub; /* double ub[1+m+n]; */
271.57 + /* ub[0] is not used;
271.58 + ub[k], 1 <= k <= m+n, is an upper bound of variable x[k];
271.59 + if x[k] has no upper bound, ub[k] is zero;
271.60 + if x[k] is of fixed type, ub[k] is the same as lb[k] */
271.61 + double *coef; /* double coef[1+m+n]; */
271.62 + /* coef[0] is not used;
271.63 + coef[k], 1 <= k <= m+n, is an objective coefficient at
271.64 + variable x[k] */
271.65 + /*--------------------------------------------------------------*/
271.66 + /* original bounds of variables */
271.67 + char *orig_type; /* char orig_type[1+m+n]; */
271.68 + double *orig_lb; /* double orig_lb[1+m+n]; */
271.69 + double *orig_ub; /* double orig_ub[1+m+n]; */
271.70 + /*--------------------------------------------------------------*/
271.71 + /* original objective function */
271.72 + double *obj; /* double obj[1+n]; */
271.73 + /* obj[0] is a constant term of the original objective function;
271.74 + obj[j], 1 <= j <= n, is an original objective coefficient at
271.75 + structural variable x[m+j] */
271.76 + double zeta;
271.77 + /* factor used to scale original objective coefficients; its
271.78 + sign defines original optimization direction: zeta > 0 means
271.79 + minimization, zeta < 0 means maximization */
271.80 + /*--------------------------------------------------------------*/
271.81 + /* constraint matrix A; it has m rows and n columns and is stored
271.82 + by columns */
271.83 + int *A_ptr; /* int A_ptr[1+n+1]; */
271.84 + /* A_ptr[0] is not used;
271.85 + A_ptr[j], 1 <= j <= n, is starting position of j-th column in
271.86 + arrays A_ind and A_val; note that A_ptr[1] is always 1;
271.87 + A_ptr[n+1] indicates the position after the last element in
271.88 + arrays A_ind and A_val */
271.89 + int *A_ind; /* int A_ind[A_ptr[n+1]]; */
271.90 + /* row indices */
271.91 + double *A_val; /* double A_val[A_ptr[n+1]]; */
271.92 + /* non-zero element values */
271.93 +#if 1 /* 06/IV-2009 */
271.94 + /* constraint matrix A stored by rows */
271.95 + int *AT_ptr; /* int AT_ptr[1+m+1];
271.96 + /* AT_ptr[0] is not used;
271.97 + AT_ptr[i], 1 <= i <= m, is starting position of i-th row in
271.98 + arrays AT_ind and AT_val; note that AT_ptr[1] is always 1;
271.99 + AT_ptr[m+1] indicates the position after the last element in
271.100 + arrays AT_ind and AT_val */
271.101 + int *AT_ind; /* int AT_ind[AT_ptr[m+1]]; */
271.102 + /* column indices */
271.103 + double *AT_val; /* double AT_val[AT_ptr[m+1]]; */
271.104 + /* non-zero element values */
271.105 +#endif
271.106 + /*--------------------------------------------------------------*/
271.107 + /* basis header */
271.108 + int *head; /* int head[1+m+n]; */
271.109 + /* head[0] is not used;
271.110 + head[i], 1 <= i <= m, is the ordinal number of basic variable
271.111 + xB[i]; head[i] = k means that xB[i] = x[k] and i-th column of
271.112 + matrix B is k-th column of matrix (I|-A);
271.113 + head[m+j], 1 <= j <= n, is the ordinal number of non-basic
271.114 + variable xN[j]; head[m+j] = k means that xN[j] = x[k] and j-th
271.115 + column of matrix N is k-th column of matrix (I|-A) */
271.116 +#if 1 /* 06/IV-2009 */
271.117 + int *bind; /* int bind[1+m+n]; */
271.118 + /* bind[0] is not used;
271.119 + bind[k], 1 <= k <= m+n, is the position of k-th column of the
271.120 + matrix (I|-A) in the matrix (B|N); that is, bind[k] = k' means
271.121 + that head[k'] = k */
271.122 +#endif
271.123 + char *stat; /* char stat[1+n]; */
271.124 + /* stat[0] is not used;
271.125 + stat[j], 1 <= j <= n, is the status of non-basic variable
271.126 + xN[j], which defines its active bound:
271.127 + GLP_NL - lower bound is active
271.128 + GLP_NU - upper bound is active
271.129 + GLP_NF - free variable
271.130 + GLP_NS - fixed variable */
271.131 + /*--------------------------------------------------------------*/
271.132 + /* matrix B is the basis matrix; it is composed from columns of
271.133 + the augmented constraint matrix (I|-A) corresponding to basic
271.134 + variables and stored in a factorized (invertable) form */
271.135 + int valid;
271.136 + /* factorization is valid only if this flag is set */
271.137 + BFD *bfd; /* BFD bfd[1:m,1:m]; */
271.138 + /* factorized (invertable) form of the basis matrix */
271.139 +#if 0 /* 06/IV-2009 */
271.140 + /*--------------------------------------------------------------*/
271.141 + /* matrix N is a matrix composed from columns of the augmented
271.142 + constraint matrix (I|-A) corresponding to non-basic variables
271.143 + except fixed ones; it is stored by rows and changes every time
271.144 + the basis changes */
271.145 + int *N_ptr; /* int N_ptr[1+m+1]; */
271.146 + /* N_ptr[0] is not used;
271.147 + N_ptr[i], 1 <= i <= m, is starting position of i-th row in
271.148 + arrays N_ind and N_val; note that N_ptr[1] is always 1;
271.149 + N_ptr[m+1] indicates the position after the last element in
271.150 + arrays N_ind and N_val */
271.151 + int *N_len; /* int N_len[1+m]; */
271.152 + /* N_len[0] is not used;
271.153 + N_len[i], 1 <= i <= m, is length of i-th row (0 to n) */
271.154 + int *N_ind; /* int N_ind[N_ptr[m+1]]; */
271.155 + /* column indices */
271.156 + double *N_val; /* double N_val[N_ptr[m+1]]; */
271.157 + /* non-zero element values */
271.158 +#endif
271.159 + /*--------------------------------------------------------------*/
271.160 + /* working parameters */
271.161 + int phase;
271.162 + /* search phase:
271.163 + 0 - not determined yet
271.164 + 1 - search for dual feasible solution
271.165 + 2 - search for optimal solution */
271.166 + glp_long tm_beg;
271.167 + /* time value at the beginning of the search */
271.168 + int it_beg;
271.169 + /* simplex iteration count at the beginning of the search */
271.170 + int it_cnt;
271.171 + /* simplex iteration count; it increases by one every time the
271.172 + basis changes */
271.173 + int it_dpy;
271.174 + /* simplex iteration count at the most recent display output */
271.175 + /*--------------------------------------------------------------*/
271.176 + /* basic solution components */
271.177 + double *bbar; /* double bbar[1+m]; */
271.178 + /* bbar[0] is not used on phase I; on phase II it is the current
271.179 + value of the original objective function;
271.180 + bbar[i], 1 <= i <= m, is primal value of basic variable xB[i]
271.181 + (if xB[i] is free, its primal value is not updated) */
271.182 + double *cbar; /* double cbar[1+n]; */
271.183 + /* cbar[0] is not used;
271.184 + cbar[j], 1 <= j <= n, is reduced cost of non-basic variable
271.185 + xN[j] (if xN[j] is fixed, its reduced cost is not updated) */
271.186 + /*--------------------------------------------------------------*/
271.187 + /* the following pricing technique options may be used:
271.188 + GLP_PT_STD - standard ("textbook") pricing;
271.189 + GLP_PT_PSE - projected steepest edge;
271.190 + GLP_PT_DVX - Devex pricing (not implemented yet);
271.191 + in case of GLP_PT_STD the reference space is not used, and all
271.192 + steepest edge coefficients are set to 1 */
271.193 + int refct;
271.194 + /* this count is set to an initial value when the reference space
271.195 + is defined and decreases by one every time the basis changes;
271.196 + once this count reaches zero, the reference space is redefined
271.197 + again */
271.198 + char *refsp; /* char refsp[1+m+n]; */
271.199 + /* refsp[0] is not used;
271.200 + refsp[k], 1 <= k <= m+n, is the flag which means that variable
271.201 + x[k] belongs to the current reference space */
271.202 + double *gamma; /* double gamma[1+m]; */
271.203 + /* gamma[0] is not used;
271.204 + gamma[i], 1 <= i <= n, is the steepest edge coefficient for
271.205 + basic variable xB[i]; if xB[i] is free, gamma[i] is not used
271.206 + and just set to 1 */
271.207 + /*--------------------------------------------------------------*/
271.208 + /* basic variable xB[p] chosen to leave the basis */
271.209 + int p;
271.210 + /* index of the basic variable xB[p] chosen, 1 <= p <= m;
271.211 + if the set of eligible basic variables is empty (i.e. if the
271.212 + current basic solution is primal feasible within a tolerance)
271.213 + and thus no variable has been chosen, p is set to 0 */
271.214 + double delta;
271.215 + /* change of xB[p] in the adjacent basis;
271.216 + delta > 0 means that xB[p] violates its lower bound and will
271.217 + increase to achieve it in the adjacent basis;
271.218 + delta < 0 means that xB[p] violates its upper bound and will
271.219 + decrease to achieve it in the adjacent basis */
271.220 + /*--------------------------------------------------------------*/
271.221 + /* pivot row of the simplex table corresponding to basic variable
271.222 + xB[p] chosen is the following vector:
271.223 + T' * e[p] = - N' * inv(B') * e[p] = - N' * rho,
271.224 + where B' is a matrix transposed to the current basis matrix,
271.225 + N' is a matrix, whose rows are columns of the matrix (I|-A)
271.226 + corresponding to non-basic non-fixed variables */
271.227 + int trow_nnz;
271.228 + /* number of non-zero components, 0 <= nnz <= n */
271.229 + int *trow_ind; /* int trow_ind[1+n]; */
271.230 + /* trow_ind[0] is not used;
271.231 + trow_ind[t], 1 <= t <= nnz, is an index of non-zero component,
271.232 + i.e. trow_ind[t] = j means that trow_vec[j] != 0 */
271.233 + double *trow_vec; /* int trow_vec[1+n]; */
271.234 + /* trow_vec[0] is not used;
271.235 + trow_vec[j], 1 <= j <= n, is a numeric value of j-th component
271.236 + of the row */
271.237 + double trow_max;
271.238 + /* infinity (maximum) norm of the row (max |trow_vec[j]|) */
271.239 + int trow_num;
271.240 + /* number of significant non-zero components, which means that:
271.241 + |trow_vec[j]| >= eps for j in trow_ind[1,...,num],
271.242 + |tcol_vec[j]| < eps for j in trow_ind[num+1,...,nnz],
271.243 + where eps is a pivot tolerance */
271.244 + /*--------------------------------------------------------------*/
271.245 +#ifdef GLP_LONG_STEP /* 07/IV-2009 */
271.246 + int nbps;
271.247 + /* number of breakpoints, 0 <= nbps <= n */
271.248 + struct bkpt
271.249 + { int j;
271.250 + /* index of non-basic variable xN[j], 1 <= j <= n */
271.251 + double t;
271.252 + /* value of dual ray parameter at breakpoint, t >= 0 */
271.253 + double dz;
271.254 + /* dz = zeta(t = t[k]) - zeta(t = 0) */
271.255 + } *bkpt; /* struct bkpt bkpt[1+n]; */
271.256 + /* bkpt[0] is not used;
271.257 + bkpt[k], 1 <= k <= nbps, is k-th breakpoint of the dual
271.258 + objective */
271.259 +#endif
271.260 + /*--------------------------------------------------------------*/
271.261 + /* non-basic variable xN[q] chosen to enter the basis */
271.262 + int q;
271.263 + /* index of the non-basic variable xN[q] chosen, 1 <= q <= n;
271.264 + if no variable has been chosen, q is set to 0 */
271.265 + double new_dq;
271.266 + /* reduced cost of xN[q] in the adjacent basis (it is the change
271.267 + of lambdaB[p]) */
271.268 + /*--------------------------------------------------------------*/
271.269 + /* pivot column of the simplex table corresponding to non-basic
271.270 + variable xN[q] chosen is the following vector:
271.271 + T * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q],
271.272 + where B is the current basis matrix, N[q] is a column of the
271.273 + matrix (I|-A) corresponding to xN[q] */
271.274 + int tcol_nnz;
271.275 + /* number of non-zero components, 0 <= nnz <= m */
271.276 + int *tcol_ind; /* int tcol_ind[1+m]; */
271.277 + /* tcol_ind[0] is not used;
271.278 + tcol_ind[t], 1 <= t <= nnz, is an index of non-zero component,
271.279 + i.e. tcol_ind[t] = i means that tcol_vec[i] != 0 */
271.280 + double *tcol_vec; /* double tcol_vec[1+m]; */
271.281 + /* tcol_vec[0] is not used;
271.282 + tcol_vec[i], 1 <= i <= m, is a numeric value of i-th component
271.283 + of the column */
271.284 + /*--------------------------------------------------------------*/
271.285 + /* working arrays */
271.286 + double *work1; /* double work1[1+m]; */
271.287 + double *work2; /* double work2[1+m]; */
271.288 + double *work3; /* double work3[1+m]; */
271.289 + double *work4; /* double work4[1+m]; */
271.290 +};
271.291 +
271.292 +static const double kappa = 0.10;
271.293 +
271.294 +/***********************************************************************
271.295 +* alloc_csa - allocate common storage area
271.296 +*
271.297 +* This routine allocates all arrays in the common storage area (CSA)
271.298 +* and returns a pointer to the CSA. */
271.299 +
271.300 +static struct csa *alloc_csa(glp_prob *lp)
271.301 +{ struct csa *csa;
271.302 + int m = lp->m;
271.303 + int n = lp->n;
271.304 + int nnz = lp->nnz;
271.305 + csa = xmalloc(sizeof(struct csa));
271.306 + xassert(m > 0 && n > 0);
271.307 + csa->m = m;
271.308 + csa->n = n;
271.309 + csa->type = xcalloc(1+m+n, sizeof(char));
271.310 + csa->lb = xcalloc(1+m+n, sizeof(double));
271.311 + csa->ub = xcalloc(1+m+n, sizeof(double));
271.312 + csa->coef = xcalloc(1+m+n, sizeof(double));
271.313 + csa->orig_type = xcalloc(1+m+n, sizeof(char));
271.314 + csa->orig_lb = xcalloc(1+m+n, sizeof(double));
271.315 + csa->orig_ub = xcalloc(1+m+n, sizeof(double));
271.316 + csa->obj = xcalloc(1+n, sizeof(double));
271.317 + csa->A_ptr = xcalloc(1+n+1, sizeof(int));
271.318 + csa->A_ind = xcalloc(1+nnz, sizeof(int));
271.319 + csa->A_val = xcalloc(1+nnz, sizeof(double));
271.320 +#if 1 /* 06/IV-2009 */
271.321 + csa->AT_ptr = xcalloc(1+m+1, sizeof(int));
271.322 + csa->AT_ind = xcalloc(1+nnz, sizeof(int));
271.323 + csa->AT_val = xcalloc(1+nnz, sizeof(double));
271.324 +#endif
271.325 + csa->head = xcalloc(1+m+n, sizeof(int));
271.326 +#if 1 /* 06/IV-2009 */
271.327 + csa->bind = xcalloc(1+m+n, sizeof(int));
271.328 +#endif
271.329 + csa->stat = xcalloc(1+n, sizeof(char));
271.330 +#if 0 /* 06/IV-2009 */
271.331 + csa->N_ptr = xcalloc(1+m+1, sizeof(int));
271.332 + csa->N_len = xcalloc(1+m, sizeof(int));
271.333 + csa->N_ind = NULL; /* will be allocated later */
271.334 + csa->N_val = NULL; /* will be allocated later */
271.335 +#endif
271.336 + csa->bbar = xcalloc(1+m, sizeof(double));
271.337 + csa->cbar = xcalloc(1+n, sizeof(double));
271.338 + csa->refsp = xcalloc(1+m+n, sizeof(char));
271.339 + csa->gamma = xcalloc(1+m, sizeof(double));
271.340 + csa->trow_ind = xcalloc(1+n, sizeof(int));
271.341 + csa->trow_vec = xcalloc(1+n, sizeof(double));
271.342 +#ifdef GLP_LONG_STEP /* 07/IV-2009 */
271.343 + csa->bkpt = xcalloc(1+n, sizeof(struct bkpt));
271.344 +#endif
271.345 + csa->tcol_ind = xcalloc(1+m, sizeof(int));
271.346 + csa->tcol_vec = xcalloc(1+m, sizeof(double));
271.347 + csa->work1 = xcalloc(1+m, sizeof(double));
271.348 + csa->work2 = xcalloc(1+m, sizeof(double));
271.349 + csa->work3 = xcalloc(1+m, sizeof(double));
271.350 + csa->work4 = xcalloc(1+m, sizeof(double));
271.351 + return csa;
271.352 +}
271.353 +
271.354 +/***********************************************************************
271.355 +* init_csa - initialize common storage area
271.356 +*
271.357 +* This routine initializes all data structures in the common storage
271.358 +* area (CSA). */
271.359 +
271.360 +static void init_csa(struct csa *csa, glp_prob *lp)
271.361 +{ int m = csa->m;
271.362 + int n = csa->n;
271.363 + char *type = csa->type;
271.364 + double *lb = csa->lb;
271.365 + double *ub = csa->ub;
271.366 + double *coef = csa->coef;
271.367 + char *orig_type = csa->orig_type;
271.368 + double *orig_lb = csa->orig_lb;
271.369 + double *orig_ub = csa->orig_ub;
271.370 + double *obj = csa->obj;
271.371 + int *A_ptr = csa->A_ptr;
271.372 + int *A_ind = csa->A_ind;
271.373 + double *A_val = csa->A_val;
271.374 +#if 1 /* 06/IV-2009 */
271.375 + int *AT_ptr = csa->AT_ptr;
271.376 + int *AT_ind = csa->AT_ind;
271.377 + double *AT_val = csa->AT_val;
271.378 +#endif
271.379 + int *head = csa->head;
271.380 +#if 1 /* 06/IV-2009 */
271.381 + int *bind = csa->bind;
271.382 +#endif
271.383 + char *stat = csa->stat;
271.384 + char *refsp = csa->refsp;
271.385 + double *gamma = csa->gamma;
271.386 + int i, j, k, loc;
271.387 + double cmax;
271.388 + /* auxiliary variables */
271.389 + for (i = 1; i <= m; i++)
271.390 + { GLPROW *row = lp->row[i];
271.391 + type[i] = (char)row->type;
271.392 + lb[i] = row->lb * row->rii;
271.393 + ub[i] = row->ub * row->rii;
271.394 + coef[i] = 0.0;
271.395 + }
271.396 + /* structural variables */
271.397 + for (j = 1; j <= n; j++)
271.398 + { GLPCOL *col = lp->col[j];
271.399 + type[m+j] = (char)col->type;
271.400 + lb[m+j] = col->lb / col->sjj;
271.401 + ub[m+j] = col->ub / col->sjj;
271.402 + coef[m+j] = col->coef * col->sjj;
271.403 + }
271.404 + /* original bounds of variables */
271.405 + memcpy(&orig_type[1], &type[1], (m+n) * sizeof(char));
271.406 + memcpy(&orig_lb[1], &lb[1], (m+n) * sizeof(double));
271.407 + memcpy(&orig_ub[1], &ub[1], (m+n) * sizeof(double));
271.408 + /* original objective function */
271.409 + obj[0] = lp->c0;
271.410 + memcpy(&obj[1], &coef[m+1], n * sizeof(double));
271.411 + /* factor used to scale original objective coefficients */
271.412 + cmax = 0.0;
271.413 + for (j = 1; j <= n; j++)
271.414 + if (cmax < fabs(obj[j])) cmax = fabs(obj[j]);
271.415 + if (cmax == 0.0) cmax = 1.0;
271.416 + switch (lp->dir)
271.417 + { case GLP_MIN:
271.418 + csa->zeta = + 1.0 / cmax;
271.419 + break;
271.420 + case GLP_MAX:
271.421 + csa->zeta = - 1.0 / cmax;
271.422 + break;
271.423 + default:
271.424 + xassert(lp != lp);
271.425 + }
271.426 +#if 1
271.427 + if (fabs(csa->zeta) < 1.0) csa->zeta *= 1000.0;
271.428 +#endif
271.429 + /* scale working objective coefficients */
271.430 + for (j = 1; j <= n; j++) coef[m+j] *= csa->zeta;
271.431 + /* matrix A (by columns) */
271.432 + loc = 1;
271.433 + for (j = 1; j <= n; j++)
271.434 + { GLPAIJ *aij;
271.435 + A_ptr[j] = loc;
271.436 + for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
271.437 + { A_ind[loc] = aij->row->i;
271.438 + A_val[loc] = aij->row->rii * aij->val * aij->col->sjj;
271.439 + loc++;
271.440 + }
271.441 + }
271.442 + A_ptr[n+1] = loc;
271.443 + xassert(loc-1 == lp->nnz);
271.444 +#if 1 /* 06/IV-2009 */
271.445 + /* matrix A (by rows) */
271.446 + loc = 1;
271.447 + for (i = 1; i <= m; i++)
271.448 + { GLPAIJ *aij;
271.449 + AT_ptr[i] = loc;
271.450 + for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
271.451 + { AT_ind[loc] = aij->col->j;
271.452 + AT_val[loc] = aij->row->rii * aij->val * aij->col->sjj;
271.453 + loc++;
271.454 + }
271.455 + }
271.456 + AT_ptr[m+1] = loc;
271.457 + xassert(loc-1 == lp->nnz);
271.458 +#endif
271.459 + /* basis header */
271.460 + xassert(lp->valid);
271.461 + memcpy(&head[1], &lp->head[1], m * sizeof(int));
271.462 + k = 0;
271.463 + for (i = 1; i <= m; i++)
271.464 + { GLPROW *row = lp->row[i];
271.465 + if (row->stat != GLP_BS)
271.466 + { k++;
271.467 + xassert(k <= n);
271.468 + head[m+k] = i;
271.469 + stat[k] = (char)row->stat;
271.470 + }
271.471 + }
271.472 + for (j = 1; j <= n; j++)
271.473 + { GLPCOL *col = lp->col[j];
271.474 + if (col->stat != GLP_BS)
271.475 + { k++;
271.476 + xassert(k <= n);
271.477 + head[m+k] = m + j;
271.478 + stat[k] = (char)col->stat;
271.479 + }
271.480 + }
271.481 + xassert(k == n);
271.482 +#if 1 /* 06/IV-2009 */
271.483 + for (k = 1; k <= m+n; k++)
271.484 + bind[head[k]] = k;
271.485 +#endif
271.486 + /* factorization of matrix B */
271.487 + csa->valid = 1, lp->valid = 0;
271.488 + csa->bfd = lp->bfd, lp->bfd = NULL;
271.489 +#if 0 /* 06/IV-2009 */
271.490 + /* matrix N (by rows) */
271.491 + alloc_N(csa);
271.492 + build_N(csa);
271.493 +#endif
271.494 + /* working parameters */
271.495 + csa->phase = 0;
271.496 + csa->tm_beg = xtime();
271.497 + csa->it_beg = csa->it_cnt = lp->it_cnt;
271.498 + csa->it_dpy = -1;
271.499 + /* reference space and steepest edge coefficients */
271.500 + csa->refct = 0;
271.501 + memset(&refsp[1], 0, (m+n) * sizeof(char));
271.502 + for (i = 1; i <= m; i++) gamma[i] = 1.0;
271.503 + return;
271.504 +}
271.505 +
271.506 +#if 1 /* copied from primal */
271.507 +/***********************************************************************
271.508 +* invert_B - compute factorization of the basis matrix
271.509 +*
271.510 +* This routine computes factorization of the current basis matrix B.
271.511 +*
271.512 +* If the operation is successful, the routine returns zero, otherwise
271.513 +* non-zero. */
271.514 +
271.515 +static int inv_col(void *info, int i, int ind[], double val[])
271.516 +{ /* this auxiliary routine returns row indices and numeric values
271.517 + of non-zero elements of i-th column of the basis matrix */
271.518 + struct csa *csa = info;
271.519 + int m = csa->m;
271.520 +#ifdef GLP_DEBUG
271.521 + int n = csa->n;
271.522 +#endif
271.523 + int *A_ptr = csa->A_ptr;
271.524 + int *A_ind = csa->A_ind;
271.525 + double *A_val = csa->A_val;
271.526 + int *head = csa->head;
271.527 + int k, len, ptr, t;
271.528 +#ifdef GLP_DEBUG
271.529 + xassert(1 <= i && i <= m);
271.530 +#endif
271.531 + k = head[i]; /* B[i] is k-th column of (I|-A) */
271.532 +#ifdef GLP_DEBUG
271.533 + xassert(1 <= k && k <= m+n);
271.534 +#endif
271.535 + if (k <= m)
271.536 + { /* B[i] is k-th column of submatrix I */
271.537 + len = 1;
271.538 + ind[1] = k;
271.539 + val[1] = 1.0;
271.540 + }
271.541 + else
271.542 + { /* B[i] is (k-m)-th column of submatrix (-A) */
271.543 + ptr = A_ptr[k-m];
271.544 + len = A_ptr[k-m+1] - ptr;
271.545 + memcpy(&ind[1], &A_ind[ptr], len * sizeof(int));
271.546 + memcpy(&val[1], &A_val[ptr], len * sizeof(double));
271.547 + for (t = 1; t <= len; t++) val[t] = - val[t];
271.548 + }
271.549 + return len;
271.550 +}
271.551 +
271.552 +static int invert_B(struct csa *csa)
271.553 +{ int ret;
271.554 + ret = bfd_factorize(csa->bfd, csa->m, NULL, inv_col, csa);
271.555 + csa->valid = (ret == 0);
271.556 + return ret;
271.557 +}
271.558 +#endif
271.559 +
271.560 +#if 1 /* copied from primal */
271.561 +/***********************************************************************
271.562 +* update_B - update factorization of the basis matrix
271.563 +*
271.564 +* This routine replaces i-th column of the basis matrix B by k-th
271.565 +* column of the augmented constraint matrix (I|-A) and then updates
271.566 +* the factorization of B.
271.567 +*
271.568 +* If the factorization has been successfully updated, the routine
271.569 +* returns zero, otherwise non-zero. */
271.570 +
271.571 +static int update_B(struct csa *csa, int i, int k)
271.572 +{ int m = csa->m;
271.573 +#ifdef GLP_DEBUG
271.574 + int n = csa->n;
271.575 +#endif
271.576 + int ret;
271.577 +#ifdef GLP_DEBUG
271.578 + xassert(1 <= i && i <= m);
271.579 + xassert(1 <= k && k <= m+n);
271.580 +#endif
271.581 + if (k <= m)
271.582 + { /* new i-th column of B is k-th column of I */
271.583 + int ind[1+1];
271.584 + double val[1+1];
271.585 + ind[1] = k;
271.586 + val[1] = 1.0;
271.587 + xassert(csa->valid);
271.588 + ret = bfd_update_it(csa->bfd, i, 0, 1, ind, val);
271.589 + }
271.590 + else
271.591 + { /* new i-th column of B is (k-m)-th column of (-A) */
271.592 + int *A_ptr = csa->A_ptr;
271.593 + int *A_ind = csa->A_ind;
271.594 + double *A_val = csa->A_val;
271.595 + double *val = csa->work1;
271.596 + int beg, end, ptr, len;
271.597 + beg = A_ptr[k-m];
271.598 + end = A_ptr[k-m+1];
271.599 + len = 0;
271.600 + for (ptr = beg; ptr < end; ptr++)
271.601 + val[++len] = - A_val[ptr];
271.602 + xassert(csa->valid);
271.603 + ret = bfd_update_it(csa->bfd, i, 0, len, &A_ind[beg-1], val);
271.604 + }
271.605 + csa->valid = (ret == 0);
271.606 + return ret;
271.607 +}
271.608 +#endif
271.609 +
271.610 +#if 1 /* copied from primal */
271.611 +/***********************************************************************
271.612 +* error_ftran - compute residual vector r = h - B * x
271.613 +*
271.614 +* This routine computes the residual vector r = h - B * x, where B is
271.615 +* the current basis matrix, h is the vector of right-hand sides, x is
271.616 +* the solution vector. */
271.617 +
271.618 +static void error_ftran(struct csa *csa, double h[], double x[],
271.619 + double r[])
271.620 +{ int m = csa->m;
271.621 +#ifdef GLP_DEBUG
271.622 + int n = csa->n;
271.623 +#endif
271.624 + int *A_ptr = csa->A_ptr;
271.625 + int *A_ind = csa->A_ind;
271.626 + double *A_val = csa->A_val;
271.627 + int *head = csa->head;
271.628 + int i, k, beg, end, ptr;
271.629 + double temp;
271.630 + /* compute the residual vector:
271.631 + r = h - B * x = h - B[1] * x[1] - ... - B[m] * x[m],
271.632 + where B[1], ..., B[m] are columns of matrix B */
271.633 + memcpy(&r[1], &h[1], m * sizeof(double));
271.634 + for (i = 1; i <= m; i++)
271.635 + { temp = x[i];
271.636 + if (temp == 0.0) continue;
271.637 + k = head[i]; /* B[i] is k-th column of (I|-A) */
271.638 +#ifdef GLP_DEBUG
271.639 + xassert(1 <= k && k <= m+n);
271.640 +#endif
271.641 + if (k <= m)
271.642 + { /* B[i] is k-th column of submatrix I */
271.643 + r[k] -= temp;
271.644 + }
271.645 + else
271.646 + { /* B[i] is (k-m)-th column of submatrix (-A) */
271.647 + beg = A_ptr[k-m];
271.648 + end = A_ptr[k-m+1];
271.649 + for (ptr = beg; ptr < end; ptr++)
271.650 + r[A_ind[ptr]] += A_val[ptr] * temp;
271.651 + }
271.652 + }
271.653 + return;
271.654 +}
271.655 +#endif
271.656 +
271.657 +#if 1 /* copied from primal */
271.658 +/***********************************************************************
271.659 +* refine_ftran - refine solution of B * x = h
271.660 +*
271.661 +* This routine performs one iteration to refine the solution of
271.662 +* the system B * x = h, where B is the current basis matrix, h is the
271.663 +* vector of right-hand sides, x is the solution vector. */
271.664 +
271.665 +static void refine_ftran(struct csa *csa, double h[], double x[])
271.666 +{ int m = csa->m;
271.667 + double *r = csa->work1;
271.668 + double *d = csa->work1;
271.669 + int i;
271.670 + /* compute the residual vector r = h - B * x */
271.671 + error_ftran(csa, h, x, r);
271.672 + /* compute the correction vector d = inv(B) * r */
271.673 + xassert(csa->valid);
271.674 + bfd_ftran(csa->bfd, d);
271.675 + /* refine the solution vector (new x) = (old x) + d */
271.676 + for (i = 1; i <= m; i++) x[i] += d[i];
271.677 + return;
271.678 +}
271.679 +#endif
271.680 +
271.681 +#if 1 /* copied from primal */
271.682 +/***********************************************************************
271.683 +* error_btran - compute residual vector r = h - B'* x
271.684 +*
271.685 +* This routine computes the residual vector r = h - B'* x, where B'
271.686 +* is a matrix transposed to the current basis matrix, h is the vector
271.687 +* of right-hand sides, x is the solution vector. */
271.688 +
271.689 +static void error_btran(struct csa *csa, double h[], double x[],
271.690 + double r[])
271.691 +{ int m = csa->m;
271.692 +#ifdef GLP_DEBUG
271.693 + int n = csa->n;
271.694 +#endif
271.695 + int *A_ptr = csa->A_ptr;
271.696 + int *A_ind = csa->A_ind;
271.697 + double *A_val = csa->A_val;
271.698 + int *head = csa->head;
271.699 + int i, k, beg, end, ptr;
271.700 + double temp;
271.701 + /* compute the residual vector r = b - B'* x */
271.702 + for (i = 1; i <= m; i++)
271.703 + { /* r[i] := b[i] - (i-th column of B)'* x */
271.704 + k = head[i]; /* B[i] is k-th column of (I|-A) */
271.705 +#ifdef GLP_DEBUG
271.706 + xassert(1 <= k && k <= m+n);
271.707 +#endif
271.708 + temp = h[i];
271.709 + if (k <= m)
271.710 + { /* B[i] is k-th column of submatrix I */
271.711 + temp -= x[k];
271.712 + }
271.713 + else
271.714 + { /* B[i] is (k-m)-th column of submatrix (-A) */
271.715 + beg = A_ptr[k-m];
271.716 + end = A_ptr[k-m+1];
271.717 + for (ptr = beg; ptr < end; ptr++)
271.718 + temp += A_val[ptr] * x[A_ind[ptr]];
271.719 + }
271.720 + r[i] = temp;
271.721 + }
271.722 + return;
271.723 +}
271.724 +#endif
271.725 +
271.726 +#if 1 /* copied from primal */
271.727 +/***********************************************************************
271.728 +* refine_btran - refine solution of B'* x = h
271.729 +*
271.730 +* This routine performs one iteration to refine the solution of the
271.731 +* system B'* x = h, where B' is a matrix transposed to the current
271.732 +* basis matrix, h is the vector of right-hand sides, x is the solution
271.733 +* vector. */
271.734 +
271.735 +static void refine_btran(struct csa *csa, double h[], double x[])
271.736 +{ int m = csa->m;
271.737 + double *r = csa->work1;
271.738 + double *d = csa->work1;
271.739 + int i;
271.740 + /* compute the residual vector r = h - B'* x */
271.741 + error_btran(csa, h, x, r);
271.742 + /* compute the correction vector d = inv(B') * r */
271.743 + xassert(csa->valid);
271.744 + bfd_btran(csa->bfd, d);
271.745 + /* refine the solution vector (new x) = (old x) + d */
271.746 + for (i = 1; i <= m; i++) x[i] += d[i];
271.747 + return;
271.748 +}
271.749 +#endif
271.750 +
271.751 +#if 1 /* copied from primal */
271.752 +/***********************************************************************
271.753 +* get_xN - determine current value of non-basic variable xN[j]
271.754 +*
271.755 +* This routine returns the current value of non-basic variable xN[j],
271.756 +* which is a value of its active bound. */
271.757 +
271.758 +static double get_xN(struct csa *csa, int j)
271.759 +{ int m = csa->m;
271.760 +#ifdef GLP_DEBUG
271.761 + int n = csa->n;
271.762 +#endif
271.763 + double *lb = csa->lb;
271.764 + double *ub = csa->ub;
271.765 + int *head = csa->head;
271.766 + char *stat = csa->stat;
271.767 + int k;
271.768 + double xN;
271.769 +#ifdef GLP_DEBUG
271.770 + xassert(1 <= j && j <= n);
271.771 +#endif
271.772 + k = head[m+j]; /* x[k] = xN[j] */
271.773 +#ifdef GLP_DEBUG
271.774 + xassert(1 <= k && k <= m+n);
271.775 +#endif
271.776 + switch (stat[j])
271.777 + { case GLP_NL:
271.778 + /* x[k] is on its lower bound */
271.779 + xN = lb[k]; break;
271.780 + case GLP_NU:
271.781 + /* x[k] is on its upper bound */
271.782 + xN = ub[k]; break;
271.783 + case GLP_NF:
271.784 + /* x[k] is free non-basic variable */
271.785 + xN = 0.0; break;
271.786 + case GLP_NS:
271.787 + /* x[k] is fixed non-basic variable */
271.788 + xN = lb[k]; break;
271.789 + default:
271.790 + xassert(stat != stat);
271.791 + }
271.792 + return xN;
271.793 +}
271.794 +#endif
271.795 +
271.796 +#if 1 /* copied from primal */
271.797 +/***********************************************************************
271.798 +* eval_beta - compute primal values of basic variables
271.799 +*
271.800 +* This routine computes current primal values of all basic variables:
271.801 +*
271.802 +* beta = - inv(B) * N * xN,
271.803 +*
271.804 +* where B is the current basis matrix, N is a matrix built of columns
271.805 +* of matrix (I|-A) corresponding to non-basic variables, and xN is the
271.806 +* vector of current values of non-basic variables. */
271.807 +
271.808 +static void eval_beta(struct csa *csa, double beta[])
271.809 +{ int m = csa->m;
271.810 + int n = csa->n;
271.811 + int *A_ptr = csa->A_ptr;
271.812 + int *A_ind = csa->A_ind;
271.813 + double *A_val = csa->A_val;
271.814 + int *head = csa->head;
271.815 + double *h = csa->work2;
271.816 + int i, j, k, beg, end, ptr;
271.817 + double xN;
271.818 + /* compute the right-hand side vector:
271.819 + h := - N * xN = - N[1] * xN[1] - ... - N[n] * xN[n],
271.820 + where N[1], ..., N[n] are columns of matrix N */
271.821 + for (i = 1; i <= m; i++)
271.822 + h[i] = 0.0;
271.823 + for (j = 1; j <= n; j++)
271.824 + { k = head[m+j]; /* x[k] = xN[j] */
271.825 +#ifdef GLP_DEBUG
271.826 + xassert(1 <= k && k <= m+n);
271.827 +#endif
271.828 + /* determine current value of xN[j] */
271.829 + xN = get_xN(csa, j);
271.830 + if (xN == 0.0) continue;
271.831 + if (k <= m)
271.832 + { /* N[j] is k-th column of submatrix I */
271.833 + h[k] -= xN;
271.834 + }
271.835 + else
271.836 + { /* N[j] is (k-m)-th column of submatrix (-A) */
271.837 + beg = A_ptr[k-m];
271.838 + end = A_ptr[k-m+1];
271.839 + for (ptr = beg; ptr < end; ptr++)
271.840 + h[A_ind[ptr]] += xN * A_val[ptr];
271.841 + }
271.842 + }
271.843 + /* solve system B * beta = h */
271.844 + memcpy(&beta[1], &h[1], m * sizeof(double));
271.845 + xassert(csa->valid);
271.846 + bfd_ftran(csa->bfd, beta);
271.847 + /* and refine the solution */
271.848 + refine_ftran(csa, h, beta);
271.849 + return;
271.850 +}
271.851 +#endif
271.852 +
271.853 +#if 1 /* copied from primal */
271.854 +/***********************************************************************
271.855 +* eval_pi - compute vector of simplex multipliers
271.856 +*
271.857 +* This routine computes the vector of current simplex multipliers:
271.858 +*
271.859 +* pi = inv(B') * cB,
271.860 +*
271.861 +* where B' is a matrix transposed to the current basis matrix, cB is
271.862 +* a subvector of objective coefficients at basic variables. */
271.863 +
271.864 +static void eval_pi(struct csa *csa, double pi[])
271.865 +{ int m = csa->m;
271.866 + double *c = csa->coef;
271.867 + int *head = csa->head;
271.868 + double *cB = csa->work2;
271.869 + int i;
271.870 + /* construct the right-hand side vector cB */
271.871 + for (i = 1; i <= m; i++)
271.872 + cB[i] = c[head[i]];
271.873 + /* solve system B'* pi = cB */
271.874 + memcpy(&pi[1], &cB[1], m * sizeof(double));
271.875 + xassert(csa->valid);
271.876 + bfd_btran(csa->bfd, pi);
271.877 + /* and refine the solution */
271.878 + refine_btran(csa, cB, pi);
271.879 + return;
271.880 +}
271.881 +#endif
271.882 +
271.883 +#if 1 /* copied from primal */
271.884 +/***********************************************************************
271.885 +* eval_cost - compute reduced cost of non-basic variable xN[j]
271.886 +*
271.887 +* This routine computes the current reduced cost of non-basic variable
271.888 +* xN[j]:
271.889 +*
271.890 +* d[j] = cN[j] - N'[j] * pi,
271.891 +*
271.892 +* where cN[j] is the objective coefficient at variable xN[j], N[j] is
271.893 +* a column of the augmented constraint matrix (I|-A) corresponding to
271.894 +* xN[j], pi is the vector of simplex multipliers. */
271.895 +
271.896 +static double eval_cost(struct csa *csa, double pi[], int j)
271.897 +{ int m = csa->m;
271.898 +#ifdef GLP_DEBUG
271.899 + int n = csa->n;
271.900 +#endif
271.901 + double *coef = csa->coef;
271.902 + int *head = csa->head;
271.903 + int k;
271.904 + double dj;
271.905 +#ifdef GLP_DEBUG
271.906 + xassert(1 <= j && j <= n);
271.907 +#endif
271.908 + k = head[m+j]; /* x[k] = xN[j] */
271.909 +#ifdef GLP_DEBUG
271.910 + xassert(1 <= k && k <= m+n);
271.911 +#endif
271.912 + dj = coef[k];
271.913 + if (k <= m)
271.914 + { /* N[j] is k-th column of submatrix I */
271.915 + dj -= pi[k];
271.916 + }
271.917 + else
271.918 + { /* N[j] is (k-m)-th column of submatrix (-A) */
271.919 + int *A_ptr = csa->A_ptr;
271.920 + int *A_ind = csa->A_ind;
271.921 + double *A_val = csa->A_val;
271.922 + int beg, end, ptr;
271.923 + beg = A_ptr[k-m];
271.924 + end = A_ptr[k-m+1];
271.925 + for (ptr = beg; ptr < end; ptr++)
271.926 + dj += A_val[ptr] * pi[A_ind[ptr]];
271.927 + }
271.928 + return dj;
271.929 +}
271.930 +#endif
271.931 +
271.932 +#if 1 /* copied from primal */
271.933 +/***********************************************************************
271.934 +* eval_bbar - compute and store primal values of basic variables
271.935 +*
271.936 +* This routine computes primal values of all basic variables and then
271.937 +* stores them in the solution array. */
271.938 +
271.939 +static void eval_bbar(struct csa *csa)
271.940 +{ eval_beta(csa, csa->bbar);
271.941 + return;
271.942 +}
271.943 +#endif
271.944 +
271.945 +#if 1 /* copied from primal */
271.946 +/***********************************************************************
271.947 +* eval_cbar - compute and store reduced costs of non-basic variables
271.948 +*
271.949 +* This routine computes reduced costs of all non-basic variables and
271.950 +* then stores them in the solution array. */
271.951 +
271.952 +static void eval_cbar(struct csa *csa)
271.953 +{
271.954 +#ifdef GLP_DEBUG
271.955 + int m = csa->m;
271.956 +#endif
271.957 + int n = csa->n;
271.958 +#ifdef GLP_DEBUG
271.959 + int *head = csa->head;
271.960 +#endif
271.961 + double *cbar = csa->cbar;
271.962 + double *pi = csa->work3;
271.963 + int j;
271.964 +#ifdef GLP_DEBUG
271.965 + int k;
271.966 +#endif
271.967 + /* compute simplex multipliers */
271.968 + eval_pi(csa, pi);
271.969 + /* compute and store reduced costs */
271.970 + for (j = 1; j <= n; j++)
271.971 + {
271.972 +#ifdef GLP_DEBUG
271.973 + k = head[m+j]; /* x[k] = xN[j] */
271.974 + xassert(1 <= k && k <= m+n);
271.975 +#endif
271.976 + cbar[j] = eval_cost(csa, pi, j);
271.977 + }
271.978 + return;
271.979 +}
271.980 +#endif
271.981 +
271.982 +/***********************************************************************
271.983 +* reset_refsp - reset the reference space
271.984 +*
271.985 +* This routine resets (redefines) the reference space used in the
271.986 +* projected steepest edge pricing algorithm. */
271.987 +
271.988 +static void reset_refsp(struct csa *csa)
271.989 +{ int m = csa->m;
271.990 + int n = csa->n;
271.991 + int *head = csa->head;
271.992 + char *refsp = csa->refsp;
271.993 + double *gamma = csa->gamma;
271.994 + int i, k;
271.995 + xassert(csa->refct == 0);
271.996 + csa->refct = 1000;
271.997 + memset(&refsp[1], 0, (m+n) * sizeof(char));
271.998 + for (i = 1; i <= m; i++)
271.999 + { k = head[i]; /* x[k] = xB[i] */
271.1000 + refsp[k] = 1;
271.1001 + gamma[i] = 1.0;
271.1002 + }
271.1003 + return;
271.1004 +}
271.1005 +
271.1006 +/***********************************************************************
271.1007 +* eval_gamma - compute steepest edge coefficients
271.1008 +*
271.1009 +* This routine computes the vector of steepest edge coefficients for
271.1010 +* all basic variables (except free ones) using its direct definition:
271.1011 +*
271.1012 +* gamma[i] = eta[i] + sum alfa[i,j]^2, i = 1,...,m,
271.1013 +* j in C
271.1014 +*
271.1015 +* where eta[i] = 1 means that xB[i] is in the current reference space,
271.1016 +* and 0 otherwise; C is a set of non-basic non-fixed variables xN[j],
271.1017 +* which are in the current reference space; alfa[i,j] are elements of
271.1018 +* the current simplex table.
271.1019 +*
271.1020 +* NOTE: The routine is intended only for debugginig purposes. */
271.1021 +
271.1022 +static void eval_gamma(struct csa *csa, double gamma[])
271.1023 +{ int m = csa->m;
271.1024 + int n = csa->n;
271.1025 + char *type = csa->type;
271.1026 + int *head = csa->head;
271.1027 + char *refsp = csa->refsp;
271.1028 + double *alfa = csa->work3;
271.1029 + double *h = csa->work3;
271.1030 + int i, j, k;
271.1031 + /* gamma[i] := eta[i] (or 1, if xB[i] is free) */
271.1032 + for (i = 1; i <= m; i++)
271.1033 + { k = head[i]; /* x[k] = xB[i] */
271.1034 +#ifdef GLP_DEBUG
271.1035 + xassert(1 <= k && k <= m+n);
271.1036 +#endif
271.1037 + if (type[k] == GLP_FR)
271.1038 + gamma[i] = 1.0;
271.1039 + else
271.1040 + gamma[i] = (refsp[k] ? 1.0 : 0.0);
271.1041 + }
271.1042 + /* compute columns of the current simplex table */
271.1043 + for (j = 1; j <= n; j++)
271.1044 + { k = head[m+j]; /* x[k] = xN[j] */
271.1045 +#ifdef GLP_DEBUG
271.1046 + xassert(1 <= k && k <= m+n);
271.1047 +#endif
271.1048 + /* skip column, if xN[j] is not in C */
271.1049 + if (!refsp[k]) continue;
271.1050 +#ifdef GLP_DEBUG
271.1051 + /* set C must not contain fixed variables */
271.1052 + xassert(type[k] != GLP_FX);
271.1053 +#endif
271.1054 + /* construct the right-hand side vector h = - N[j] */
271.1055 + for (i = 1; i <= m; i++)
271.1056 + h[i] = 0.0;
271.1057 + if (k <= m)
271.1058 + { /* N[j] is k-th column of submatrix I */
271.1059 + h[k] = -1.0;
271.1060 + }
271.1061 + else
271.1062 + { /* N[j] is (k-m)-th column of submatrix (-A) */
271.1063 + int *A_ptr = csa->A_ptr;
271.1064 + int *A_ind = csa->A_ind;
271.1065 + double *A_val = csa->A_val;
271.1066 + int beg, end, ptr;
271.1067 + beg = A_ptr[k-m];
271.1068 + end = A_ptr[k-m+1];
271.1069 + for (ptr = beg; ptr < end; ptr++)
271.1070 + h[A_ind[ptr]] = A_val[ptr];
271.1071 + }
271.1072 + /* solve system B * alfa = h */
271.1073 + xassert(csa->valid);
271.1074 + bfd_ftran(csa->bfd, alfa);
271.1075 + /* gamma[i] := gamma[i] + alfa[i,j]^2 */
271.1076 + for (i = 1; i <= m; i++)
271.1077 + { k = head[i]; /* x[k] = xB[i] */
271.1078 + if (type[k] != GLP_FR)
271.1079 + gamma[i] += alfa[i] * alfa[i];
271.1080 + }
271.1081 + }
271.1082 + return;
271.1083 +}
271.1084 +
271.1085 +/***********************************************************************
271.1086 +* chuzr - choose basic variable (row of the simplex table)
271.1087 +*
271.1088 +* This routine chooses basic variable xB[p] having largest weighted
271.1089 +* bound violation:
271.1090 +*
271.1091 +* |r[p]| / sqrt(gamma[p]) = max |r[i]| / sqrt(gamma[i]),
271.1092 +* i in I
271.1093 +*
271.1094 +* / lB[i] - beta[i], if beta[i] < lB[i]
271.1095 +* |
271.1096 +* r[i] = < 0, if lB[i] <= beta[i] <= uB[i]
271.1097 +* |
271.1098 +* \ uB[i] - beta[i], if beta[i] > uB[i]
271.1099 +*
271.1100 +* where beta[i] is primal value of xB[i] in the current basis, lB[i]
271.1101 +* and uB[i] are lower and upper bounds of xB[i], I is a subset of
271.1102 +* eligible basic variables, which significantly violates their bounds,
271.1103 +* gamma[i] is the steepest edge coefficient.
271.1104 +*
271.1105 +* If |r[i]| is less than a specified tolerance, xB[i] is not included
271.1106 +* in I and therefore ignored.
271.1107 +*
271.1108 +* If I is empty and no variable has been chosen, p is set to 0. */
271.1109 +
271.1110 +static void chuzr(struct csa *csa, double tol_bnd)
271.1111 +{ int m = csa->m;
271.1112 +#ifdef GLP_DEBUG
271.1113 + int n = csa->n;
271.1114 +#endif
271.1115 + char *type = csa->type;
271.1116 + double *lb = csa->lb;
271.1117 + double *ub = csa->ub;
271.1118 + int *head = csa->head;
271.1119 + double *bbar = csa->bbar;
271.1120 + double *gamma = csa->gamma;
271.1121 + int i, k, p;
271.1122 + double delta, best, eps, ri, temp;
271.1123 + /* nothing is chosen so far */
271.1124 + p = 0, delta = 0.0, best = 0.0;
271.1125 + /* look through the list of basic variables */
271.1126 + for (i = 1; i <= m; i++)
271.1127 + { k = head[i]; /* x[k] = xB[i] */
271.1128 +#ifdef GLP_DEBUG
271.1129 + xassert(1 <= k && k <= m+n);
271.1130 +#endif
271.1131 + /* determine bound violation ri[i] */
271.1132 + ri = 0.0;
271.1133 + if (type[k] == GLP_LO || type[k] == GLP_DB ||
271.1134 + type[k] == GLP_FX)
271.1135 + { /* xB[i] has lower bound */
271.1136 + eps = tol_bnd * (1.0 + kappa * fabs(lb[k]));
271.1137 + if (bbar[i] < lb[k] - eps)
271.1138 + { /* and significantly violates it */
271.1139 + ri = lb[k] - bbar[i];
271.1140 + }
271.1141 + }
271.1142 + if (type[k] == GLP_UP || type[k] == GLP_DB ||
271.1143 + type[k] == GLP_FX)
271.1144 + { /* xB[i] has upper bound */
271.1145 + eps = tol_bnd * (1.0 + kappa * fabs(ub[k]));
271.1146 + if (bbar[i] > ub[k] + eps)
271.1147 + { /* and significantly violates it */
271.1148 + ri = ub[k] - bbar[i];
271.1149 + }
271.1150 + }
271.1151 + /* if xB[i] is not eligible, skip it */
271.1152 + if (ri == 0.0) continue;
271.1153 + /* xB[i] is eligible basic variable; choose one with largest
271.1154 + weighted bound violation */
271.1155 +#ifdef GLP_DEBUG
271.1156 + xassert(gamma[i] >= 0.0);
271.1157 +#endif
271.1158 + temp = gamma[i];
271.1159 + if (temp < DBL_EPSILON) temp = DBL_EPSILON;
271.1160 + temp = (ri * ri) / temp;
271.1161 + if (best < temp)
271.1162 + p = i, delta = ri, best = temp;
271.1163 + }
271.1164 + /* store the index of basic variable xB[p] chosen and its change
271.1165 + in the adjacent basis */
271.1166 + csa->p = p;
271.1167 + csa->delta = delta;
271.1168 + return;
271.1169 +}
271.1170 +
271.1171 +#if 1 /* copied from primal */
271.1172 +/***********************************************************************
271.1173 +* eval_rho - compute pivot row of the inverse
271.1174 +*
271.1175 +* This routine computes the pivot (p-th) row of the inverse inv(B),
271.1176 +* which corresponds to basic variable xB[p] chosen:
271.1177 +*
271.1178 +* rho = inv(B') * e[p],
271.1179 +*
271.1180 +* where B' is a matrix transposed to the current basis matrix, e[p]
271.1181 +* is unity vector. */
271.1182 +
271.1183 +static void eval_rho(struct csa *csa, double rho[])
271.1184 +{ int m = csa->m;
271.1185 + int p = csa->p;
271.1186 + double *e = rho;
271.1187 + int i;
271.1188 +#ifdef GLP_DEBUG
271.1189 + xassert(1 <= p && p <= m);
271.1190 +#endif
271.1191 + /* construct the right-hand side vector e[p] */
271.1192 + for (i = 1; i <= m; i++)
271.1193 + e[i] = 0.0;
271.1194 + e[p] = 1.0;
271.1195 + /* solve system B'* rho = e[p] */
271.1196 + xassert(csa->valid);
271.1197 + bfd_btran(csa->bfd, rho);
271.1198 + return;
271.1199 +}
271.1200 +#endif
271.1201 +
271.1202 +#if 1 /* copied from primal */
271.1203 +/***********************************************************************
271.1204 +* refine_rho - refine pivot row of the inverse
271.1205 +*
271.1206 +* This routine refines the pivot row of the inverse inv(B) assuming
271.1207 +* that it was previously computed by the routine eval_rho. */
271.1208 +
271.1209 +static void refine_rho(struct csa *csa, double rho[])
271.1210 +{ int m = csa->m;
271.1211 + int p = csa->p;
271.1212 + double *e = csa->work3;
271.1213 + int i;
271.1214 +#ifdef GLP_DEBUG
271.1215 + xassert(1 <= p && p <= m);
271.1216 +#endif
271.1217 + /* construct the right-hand side vector e[p] */
271.1218 + for (i = 1; i <= m; i++)
271.1219 + e[i] = 0.0;
271.1220 + e[p] = 1.0;
271.1221 + /* refine solution of B'* rho = e[p] */
271.1222 + refine_btran(csa, e, rho);
271.1223 + return;
271.1224 +}
271.1225 +#endif
271.1226 +
271.1227 +#if 1 /* 06/IV-2009 */
271.1228 +/***********************************************************************
271.1229 +* eval_trow - compute pivot row of the simplex table
271.1230 +*
271.1231 +* This routine computes the pivot row of the simplex table, which
271.1232 +* corresponds to basic variable xB[p] chosen.
271.1233 +*
271.1234 +* The pivot row is the following vector:
271.1235 +*
271.1236 +* trow = T'* e[p] = - N'* inv(B') * e[p] = - N' * rho,
271.1237 +*
271.1238 +* where rho is the pivot row of the inverse inv(B) previously computed
271.1239 +* by the routine eval_rho.
271.1240 +*
271.1241 +* Note that elements of the pivot row corresponding to fixed non-basic
271.1242 +* variables are not computed.
271.1243 +*
271.1244 +* NOTES
271.1245 +*
271.1246 +* Computing pivot row of the simplex table is one of the most time
271.1247 +* consuming operations, and for some instances it may take more than
271.1248 +* 50% of the total solution time.
271.1249 +*
271.1250 +* In the current implementation there are two routines to compute the
271.1251 +* pivot row. The routine eval_trow1 computes elements of the pivot row
271.1252 +* as inner products of columns of the matrix N and the vector rho; it
271.1253 +* is used when the vector rho is relatively dense. The routine
271.1254 +* eval_trow2 computes the pivot row as a linear combination of rows of
271.1255 +* the matrix N; it is used when the vector rho is relatively sparse. */
271.1256 +
271.1257 +static void eval_trow1(struct csa *csa, double rho[])
271.1258 +{ int m = csa->m;
271.1259 + int n = csa->n;
271.1260 + int *A_ptr = csa->A_ptr;
271.1261 + int *A_ind = csa->A_ind;
271.1262 + double *A_val = csa->A_val;
271.1263 + int *head = csa->head;
271.1264 + char *stat = csa->stat;
271.1265 + int *trow_ind = csa->trow_ind;
271.1266 + double *trow_vec = csa->trow_vec;
271.1267 + int j, k, beg, end, ptr, nnz;
271.1268 + double temp;
271.1269 + /* compute the pivot row as inner products of columns of the
271.1270 + matrix N and vector rho: trow[j] = - rho * N[j] */
271.1271 + nnz = 0;
271.1272 + for (j = 1; j <= n; j++)
271.1273 + { if (stat[j] == GLP_NS)
271.1274 + { /* xN[j] is fixed */
271.1275 + trow_vec[j] = 0.0;
271.1276 + continue;
271.1277 + }
271.1278 + k = head[m+j]; /* x[k] = xN[j] */
271.1279 + if (k <= m)
271.1280 + { /* N[j] is k-th column of submatrix I */
271.1281 + temp = - rho[k];
271.1282 + }
271.1283 + else
271.1284 + { /* N[j] is (k-m)-th column of submatrix (-A) */
271.1285 + beg = A_ptr[k-m], end = A_ptr[k-m+1];
271.1286 + temp = 0.0;
271.1287 + for (ptr = beg; ptr < end; ptr++)
271.1288 + temp += rho[A_ind[ptr]] * A_val[ptr];
271.1289 + }
271.1290 + if (temp != 0.0)
271.1291 + trow_ind[++nnz] = j;
271.1292 + trow_vec[j] = temp;
271.1293 + }
271.1294 + csa->trow_nnz = nnz;
271.1295 + return;
271.1296 +}
271.1297 +
271.1298 +static void eval_trow2(struct csa *csa, double rho[])
271.1299 +{ int m = csa->m;
271.1300 + int n = csa->n;
271.1301 + int *AT_ptr = csa->AT_ptr;
271.1302 + int *AT_ind = csa->AT_ind;
271.1303 + double *AT_val = csa->AT_val;
271.1304 + int *bind = csa->bind;
271.1305 + char *stat = csa->stat;
271.1306 + int *trow_ind = csa->trow_ind;
271.1307 + double *trow_vec = csa->trow_vec;
271.1308 + int i, j, beg, end, ptr, nnz;
271.1309 + double temp;
271.1310 + /* clear the pivot row */
271.1311 + for (j = 1; j <= n; j++)
271.1312 + trow_vec[j] = 0.0;
271.1313 + /* compute the pivot row as a linear combination of rows of the
271.1314 + matrix N: trow = - rho[1] * N'[1] - ... - rho[m] * N'[m] */
271.1315 + for (i = 1; i <= m; i++)
271.1316 + { temp = rho[i];
271.1317 + if (temp == 0.0) continue;
271.1318 + /* trow := trow - rho[i] * N'[i] */
271.1319 + j = bind[i] - m; /* x[i] = xN[j] */
271.1320 + if (j >= 1 && stat[j] != GLP_NS)
271.1321 + trow_vec[j] -= temp;
271.1322 + beg = AT_ptr[i], end = AT_ptr[i+1];
271.1323 + for (ptr = beg; ptr < end; ptr++)
271.1324 + { j = bind[m + AT_ind[ptr]] - m; /* x[k] = xN[j] */
271.1325 + if (j >= 1 && stat[j] != GLP_NS)
271.1326 + trow_vec[j] += temp * AT_val[ptr];
271.1327 + }
271.1328 + }
271.1329 + /* construct sparse pattern of the pivot row */
271.1330 + nnz = 0;
271.1331 + for (j = 1; j <= n; j++)
271.1332 + { if (trow_vec[j] != 0.0)
271.1333 + trow_ind[++nnz] = j;
271.1334 + }
271.1335 + csa->trow_nnz = nnz;
271.1336 + return;
271.1337 +}
271.1338 +
271.1339 +static void eval_trow(struct csa *csa, double rho[])
271.1340 +{ int m = csa->m;
271.1341 + int i, nnz;
271.1342 + double dens;
271.1343 + /* determine the density of the vector rho */
271.1344 + nnz = 0;
271.1345 + for (i = 1; i <= m; i++)
271.1346 + if (rho[i] != 0.0) nnz++;
271.1347 + dens = (double)nnz / (double)m;
271.1348 + if (dens >= 0.20)
271.1349 + { /* rho is relatively dense */
271.1350 + eval_trow1(csa, rho);
271.1351 + }
271.1352 + else
271.1353 + { /* rho is relatively sparse */
271.1354 + eval_trow2(csa, rho);
271.1355 + }
271.1356 + return;
271.1357 +}
271.1358 +#endif
271.1359 +
271.1360 +/***********************************************************************
271.1361 +* sort_trow - sort pivot row of the simplex table
271.1362 +*
271.1363 +* This routine reorders the list of non-zero elements of the pivot
271.1364 +* row to put significant elements, whose magnitude is not less than
271.1365 +* a specified tolerance, in front of the list, and stores the number
271.1366 +* of significant elements in trow_num. */
271.1367 +
271.1368 +static void sort_trow(struct csa *csa, double tol_piv)
271.1369 +{
271.1370 +#ifdef GLP_DEBUG
271.1371 + int n = csa->n;
271.1372 + char *stat = csa->stat;
271.1373 +#endif
271.1374 + int nnz = csa->trow_nnz;
271.1375 + int *trow_ind = csa->trow_ind;
271.1376 + double *trow_vec = csa->trow_vec;
271.1377 + int j, num, pos;
271.1378 + double big, eps, temp;
271.1379 + /* compute infinity (maximum) norm of the row */
271.1380 + big = 0.0;
271.1381 + for (pos = 1; pos <= nnz; pos++)
271.1382 + {
271.1383 +#ifdef GLP_DEBUG
271.1384 + j = trow_ind[pos];
271.1385 + xassert(1 <= j && j <= n);
271.1386 + xassert(stat[j] != GLP_NS);
271.1387 +#endif
271.1388 + temp = fabs(trow_vec[trow_ind[pos]]);
271.1389 + if (big < temp) big = temp;
271.1390 + }
271.1391 + csa->trow_max = big;
271.1392 + /* determine absolute pivot tolerance */
271.1393 + eps = tol_piv * (1.0 + 0.01 * big);
271.1394 + /* move significant row components to the front of the list */
271.1395 + for (num = 0; num < nnz; )
271.1396 + { j = trow_ind[nnz];
271.1397 + if (fabs(trow_vec[j]) < eps)
271.1398 + nnz--;
271.1399 + else
271.1400 + { num++;
271.1401 + trow_ind[nnz] = trow_ind[num];
271.1402 + trow_ind[num] = j;
271.1403 + }
271.1404 + }
271.1405 + csa->trow_num = num;
271.1406 + return;
271.1407 +}
271.1408 +
271.1409 +#ifdef GLP_LONG_STEP /* 07/IV-2009 */
271.1410 +static int ls_func(const void *p1_, const void *p2_)
271.1411 +{ const struct bkpt *p1 = p1_, *p2 = p2_;
271.1412 + if (p1->t < p2->t) return -1;
271.1413 + if (p1->t > p2->t) return +1;
271.1414 + return 0;
271.1415 +}
271.1416 +
271.1417 +static int ls_func1(const void *p1_, const void *p2_)
271.1418 +{ const struct bkpt *p1 = p1_, *p2 = p2_;
271.1419 + if (p1->dz < p2->dz) return -1;
271.1420 + if (p1->dz > p2->dz) return +1;
271.1421 + return 0;
271.1422 +}
271.1423 +
271.1424 +static void long_step(struct csa *csa)
271.1425 +{ int m = csa->m;
271.1426 +#ifdef GLP_DEBUG
271.1427 + int n = csa->n;
271.1428 +#endif
271.1429 + char *type = csa->type;
271.1430 + double *lb = csa->lb;
271.1431 + double *ub = csa->ub;
271.1432 + int *head = csa->head;
271.1433 + char *stat = csa->stat;
271.1434 + double *cbar = csa->cbar;
271.1435 + double delta = csa->delta;
271.1436 + int *trow_ind = csa->trow_ind;
271.1437 + double *trow_vec = csa->trow_vec;
271.1438 + int trow_num = csa->trow_num;
271.1439 + struct bkpt *bkpt = csa->bkpt;
271.1440 + int j, k, kk, nbps, pos;
271.1441 + double alfa, s, slope, dzmax;
271.1442 + /* delta > 0 means that xB[p] violates its lower bound, so to
271.1443 + increase the dual objective lambdaB[p] must increase;
271.1444 + delta < 0 means that xB[p] violates its upper bound, so to
271.1445 + increase the dual objective lambdaB[p] must decrease */
271.1446 + /* s := sign(delta) */
271.1447 + s = (delta > 0.0 ? +1.0 : -1.0);
271.1448 + /* determine breakpoints of the dual objective */
271.1449 + nbps = 0;
271.1450 + for (pos = 1; pos <= trow_num; pos++)
271.1451 + { j = trow_ind[pos];
271.1452 +#ifdef GLP_DEBUG
271.1453 + xassert(1 <= j && j <= n);
271.1454 + xassert(stat[j] != GLP_NS);
271.1455 +#endif
271.1456 + /* if there is free non-basic variable, switch to the standard
271.1457 + ratio test */
271.1458 + if (stat[j] == GLP_NF)
271.1459 + { nbps = 0;
271.1460 + goto done;
271.1461 + }
271.1462 + /* lambdaN[j] = ... - alfa * t - ..., where t = s * lambdaB[i]
271.1463 + is the dual ray parameter, t >= 0 */
271.1464 + alfa = s * trow_vec[j];
271.1465 +#ifdef GLP_DEBUG
271.1466 + xassert(alfa != 0.0);
271.1467 + xassert(stat[j] == GLP_NL || stat[j] == GLP_NU);
271.1468 +#endif
271.1469 + if (alfa > 0.0 && stat[j] == GLP_NL ||
271.1470 + alfa < 0.0 && stat[j] == GLP_NU)
271.1471 + { /* either lambdaN[j] >= 0 (if stat = GLP_NL) and decreases
271.1472 + or lambdaN[j] <= 0 (if stat = GLP_NU) and increases; in
271.1473 + both cases we have a breakpoint */
271.1474 + nbps++;
271.1475 +#ifdef GLP_DEBUG
271.1476 + xassert(nbps <= n);
271.1477 +#endif
271.1478 + bkpt[nbps].j = j;
271.1479 + bkpt[nbps].t = cbar[j] / alfa;
271.1480 +/*
271.1481 +if (stat[j] == GLP_NL && cbar[j] < 0.0 ||
271.1482 + stat[j] == GLP_NU && cbar[j] > 0.0)
271.1483 +xprintf("%d %g\n", stat[j], cbar[j]);
271.1484 +*/
271.1485 + /* if t is negative, replace it by exact zero (see comments
271.1486 + in the routine chuzc) */
271.1487 + if (bkpt[nbps].t < 0.0) bkpt[nbps].t = 0.0;
271.1488 + }
271.1489 + }
271.1490 + /* if there are less than two breakpoints, switch to the standard
271.1491 + ratio test */
271.1492 + if (nbps < 2)
271.1493 + { nbps = 0;
271.1494 + goto done;
271.1495 + }
271.1496 + /* sort breakpoints by ascending the dual ray parameter, t */
271.1497 + qsort(&bkpt[1], nbps, sizeof(struct bkpt), ls_func);
271.1498 + /* determine last breakpoint, at which the dual objective still
271.1499 + greater than at t = 0 */
271.1500 + dzmax = 0.0;
271.1501 + slope = fabs(delta); /* initial slope */
271.1502 + for (kk = 1; kk <= nbps; kk++)
271.1503 + { if (kk == 1)
271.1504 + bkpt[kk].dz =
271.1505 + 0.0 + slope * (bkpt[kk].t - 0.0);
271.1506 + else
271.1507 + bkpt[kk].dz =
271.1508 + bkpt[kk-1].dz + slope * (bkpt[kk].t - bkpt[kk-1].t);
271.1509 + if (dzmax < bkpt[kk].dz)
271.1510 + dzmax = bkpt[kk].dz;
271.1511 + else if (bkpt[kk].dz < 0.05 * (1.0 + dzmax))
271.1512 + { nbps = kk - 1;
271.1513 + break;
271.1514 + }
271.1515 + j = bkpt[kk].j;
271.1516 + k = head[m+j]; /* x[k] = xN[j] */
271.1517 + if (type[k] == GLP_DB)
271.1518 + slope -= fabs(trow_vec[j]) * (ub[k] - lb[k]);
271.1519 + else
271.1520 + { nbps = kk;
271.1521 + break;
271.1522 + }
271.1523 + }
271.1524 + /* if there are less than two breakpoints, switch to the standard
271.1525 + ratio test */
271.1526 + if (nbps < 2)
271.1527 + { nbps = 0;
271.1528 + goto done;
271.1529 + }
271.1530 + /* sort breakpoints by ascending the dual change, dz */
271.1531 + qsort(&bkpt[1], nbps, sizeof(struct bkpt), ls_func1);
271.1532 +/*
271.1533 +for (kk = 1; kk <= nbps; kk++)
271.1534 +xprintf("%d; t = %g; dz = %g\n", kk, bkpt[kk].t, bkpt[kk].dz);
271.1535 +*/
271.1536 +done: csa->nbps = nbps;
271.1537 + return;
271.1538 +}
271.1539 +#endif
271.1540 +
271.1541 +/***********************************************************************
271.1542 +* chuzc - choose non-basic variable (column of the simplex table)
271.1543 +*
271.1544 +* This routine chooses non-basic variable xN[q], which being entered
271.1545 +* in the basis keeps dual feasibility of the basic solution.
271.1546 +*
271.1547 +* The parameter rtol is a relative tolerance used to relax zero bounds
271.1548 +* of reduced costs of non-basic variables. If rtol = 0, the routine
271.1549 +* implements the standard ratio test. Otherwise, if rtol > 0, the
271.1550 +* routine implements Harris' two-pass ratio test. In the latter case
271.1551 +* rtol should be about three times less than a tolerance used to check
271.1552 +* dual feasibility. */
271.1553 +
271.1554 +static void chuzc(struct csa *csa, double rtol)
271.1555 +{
271.1556 +#ifdef GLP_DEBUG
271.1557 + int m = csa->m;
271.1558 + int n = csa->n;
271.1559 +#endif
271.1560 + char *stat = csa->stat;
271.1561 + double *cbar = csa->cbar;
271.1562 +#ifdef GLP_DEBUG
271.1563 + int p = csa->p;
271.1564 +#endif
271.1565 + double delta = csa->delta;
271.1566 + int *trow_ind = csa->trow_ind;
271.1567 + double *trow_vec = csa->trow_vec;
271.1568 + int trow_num = csa->trow_num;
271.1569 + int j, pos, q;
271.1570 + double alfa, big, s, t, teta, tmax;
271.1571 +#ifdef GLP_DEBUG
271.1572 + xassert(1 <= p && p <= m);
271.1573 +#endif
271.1574 + /* delta > 0 means that xB[p] violates its lower bound and goes
271.1575 + to it in the adjacent basis, so lambdaB[p] is increasing from
271.1576 + its lower zero bound;
271.1577 + delta < 0 means that xB[p] violates its upper bound and goes
271.1578 + to it in the adjacent basis, so lambdaB[p] is decreasing from
271.1579 + its upper zero bound */
271.1580 +#ifdef GLP_DEBUG
271.1581 + xassert(delta != 0.0);
271.1582 +#endif
271.1583 + /* s := sign(delta) */
271.1584 + s = (delta > 0.0 ? +1.0 : -1.0);
271.1585 + /*** FIRST PASS ***/
271.1586 + /* nothing is chosen so far */
271.1587 + q = 0, teta = DBL_MAX, big = 0.0;
271.1588 + /* walk through significant elements of the pivot row */
271.1589 + for (pos = 1; pos <= trow_num; pos++)
271.1590 + { j = trow_ind[pos];
271.1591 +#ifdef GLP_DEBUG
271.1592 + xassert(1 <= j && j <= n);
271.1593 +#endif
271.1594 + alfa = s * trow_vec[j];
271.1595 +#ifdef GLP_DEBUG
271.1596 + xassert(alfa != 0.0);
271.1597 +#endif
271.1598 + /* lambdaN[j] = ... - alfa * lambdaB[p] - ..., and due to s we
271.1599 + need to consider only increasing lambdaB[p] */
271.1600 + if (alfa > 0.0)
271.1601 + { /* lambdaN[j] is decreasing */
271.1602 + if (stat[j] == GLP_NL || stat[j] == GLP_NF)
271.1603 + { /* lambdaN[j] has zero lower bound */
271.1604 + t = (cbar[j] + rtol) / alfa;
271.1605 + }
271.1606 + else
271.1607 + { /* lambdaN[j] has no lower bound */
271.1608 + continue;
271.1609 + }
271.1610 + }
271.1611 + else
271.1612 + { /* lambdaN[j] is increasing */
271.1613 + if (stat[j] == GLP_NU || stat[j] == GLP_NF)
271.1614 + { /* lambdaN[j] has zero upper bound */
271.1615 + t = (cbar[j] - rtol) / alfa;
271.1616 + }
271.1617 + else
271.1618 + { /* lambdaN[j] has no upper bound */
271.1619 + continue;
271.1620 + }
271.1621 + }
271.1622 + /* t is a change of lambdaB[p], on which lambdaN[j] reaches
271.1623 + its zero bound (possibly relaxed); since the basic solution
271.1624 + is assumed to be dual feasible, t has to be non-negative by
271.1625 + definition; however, it may happen that lambdaN[j] slightly
271.1626 + (i.e. within a tolerance) violates its zero bound, that
271.1627 + leads to negative t; in the latter case, if xN[j] is chosen,
271.1628 + negative t means that lambdaB[p] changes in wrong direction
271.1629 + that may cause wrong results on updating reduced costs;
271.1630 + thus, if t is negative, we should replace it by exact zero
271.1631 + assuming that lambdaN[j] is exactly on its zero bound, and
271.1632 + violation appears due to round-off errors */
271.1633 + if (t < 0.0) t = 0.0;
271.1634 + /* apply minimal ratio test */
271.1635 + if (teta > t || teta == t && big < fabs(alfa))
271.1636 + q = j, teta = t, big = fabs(alfa);
271.1637 + }
271.1638 + /* the second pass is skipped in the following cases: */
271.1639 + /* if the standard ratio test is used */
271.1640 + if (rtol == 0.0) goto done;
271.1641 + /* if no non-basic variable has been chosen on the first pass */
271.1642 + if (q == 0) goto done;
271.1643 + /* if lambdaN[q] prevents lambdaB[p] from any change */
271.1644 + if (teta == 0.0) goto done;
271.1645 + /*** SECOND PASS ***/
271.1646 + /* here tmax is a maximal change of lambdaB[p], on which the
271.1647 + solution remains dual feasible within a tolerance */
271.1648 +#if 0
271.1649 + tmax = (1.0 + 10.0 * DBL_EPSILON) * teta;
271.1650 +#else
271.1651 + tmax = teta;
271.1652 +#endif
271.1653 + /* nothing is chosen so far */
271.1654 + q = 0, teta = DBL_MAX, big = 0.0;
271.1655 + /* walk through significant elements of the pivot row */
271.1656 + for (pos = 1; pos <= trow_num; pos++)
271.1657 + { j = trow_ind[pos];
271.1658 +#ifdef GLP_DEBUG
271.1659 + xassert(1 <= j && j <= n);
271.1660 +#endif
271.1661 + alfa = s * trow_vec[j];
271.1662 +#ifdef GLP_DEBUG
271.1663 + xassert(alfa != 0.0);
271.1664 +#endif
271.1665 + /* lambdaN[j] = ... - alfa * lambdaB[p] - ..., and due to s we
271.1666 + need to consider only increasing lambdaB[p] */
271.1667 + if (alfa > 0.0)
271.1668 + { /* lambdaN[j] is decreasing */
271.1669 + if (stat[j] == GLP_NL || stat[j] == GLP_NF)
271.1670 + { /* lambdaN[j] has zero lower bound */
271.1671 + t = cbar[j] / alfa;
271.1672 + }
271.1673 + else
271.1674 + { /* lambdaN[j] has no lower bound */
271.1675 + continue;
271.1676 + }
271.1677 + }
271.1678 + else
271.1679 + { /* lambdaN[j] is increasing */
271.1680 + if (stat[j] == GLP_NU || stat[j] == GLP_NF)
271.1681 + { /* lambdaN[j] has zero upper bound */
271.1682 + t = cbar[j] / alfa;
271.1683 + }
271.1684 + else
271.1685 + { /* lambdaN[j] has no upper bound */
271.1686 + continue;
271.1687 + }
271.1688 + }
271.1689 + /* (see comments for the first pass) */
271.1690 + if (t < 0.0) t = 0.0;
271.1691 + /* t is a change of lambdaB[p], on which lambdaN[j] reaches
271.1692 + its zero (lower or upper) bound; if t <= tmax, all reduced
271.1693 + costs can violate their zero bounds only within relaxation
271.1694 + tolerance rtol, so we can choose non-basic variable having
271.1695 + largest influence coefficient to avoid possible numerical
271.1696 + instability */
271.1697 + if (t <= tmax && big < fabs(alfa))
271.1698 + q = j, teta = t, big = fabs(alfa);
271.1699 + }
271.1700 + /* something must be chosen on the second pass */
271.1701 + xassert(q != 0);
271.1702 +done: /* store the index of non-basic variable xN[q] chosen */
271.1703 + csa->q = q;
271.1704 + /* store reduced cost of xN[q] in the adjacent basis */
271.1705 + csa->new_dq = s * teta;
271.1706 + return;
271.1707 +}
271.1708 +
271.1709 +#if 1 /* copied from primal */
271.1710 +/***********************************************************************
271.1711 +* eval_tcol - compute pivot column of the simplex table
271.1712 +*
271.1713 +* This routine computes the pivot column of the simplex table, which
271.1714 +* corresponds to non-basic variable xN[q] chosen.
271.1715 +*
271.1716 +* The pivot column is the following vector:
271.1717 +*
271.1718 +* tcol = T * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q],
271.1719 +*
271.1720 +* where B is the current basis matrix, N[q] is a column of the matrix
271.1721 +* (I|-A) corresponding to variable xN[q]. */
271.1722 +
271.1723 +static void eval_tcol(struct csa *csa)
271.1724 +{ int m = csa->m;
271.1725 +#ifdef GLP_DEBUG
271.1726 + int n = csa->n;
271.1727 +#endif
271.1728 + int *head = csa->head;
271.1729 + int q = csa->q;
271.1730 + int *tcol_ind = csa->tcol_ind;
271.1731 + double *tcol_vec = csa->tcol_vec;
271.1732 + double *h = csa->tcol_vec;
271.1733 + int i, k, nnz;
271.1734 +#ifdef GLP_DEBUG
271.1735 + xassert(1 <= q && q <= n);
271.1736 +#endif
271.1737 + k = head[m+q]; /* x[k] = xN[q] */
271.1738 +#ifdef GLP_DEBUG
271.1739 + xassert(1 <= k && k <= m+n);
271.1740 +#endif
271.1741 + /* construct the right-hand side vector h = - N[q] */
271.1742 + for (i = 1; i <= m; i++)
271.1743 + h[i] = 0.0;
271.1744 + if (k <= m)
271.1745 + { /* N[q] is k-th column of submatrix I */
271.1746 + h[k] = -1.0;
271.1747 + }
271.1748 + else
271.1749 + { /* N[q] is (k-m)-th column of submatrix (-A) */
271.1750 + int *A_ptr = csa->A_ptr;
271.1751 + int *A_ind = csa->A_ind;
271.1752 + double *A_val = csa->A_val;
271.1753 + int beg, end, ptr;
271.1754 + beg = A_ptr[k-m];
271.1755 + end = A_ptr[k-m+1];
271.1756 + for (ptr = beg; ptr < end; ptr++)
271.1757 + h[A_ind[ptr]] = A_val[ptr];
271.1758 + }
271.1759 + /* solve system B * tcol = h */
271.1760 + xassert(csa->valid);
271.1761 + bfd_ftran(csa->bfd, tcol_vec);
271.1762 + /* construct sparse pattern of the pivot column */
271.1763 + nnz = 0;
271.1764 + for (i = 1; i <= m; i++)
271.1765 + { if (tcol_vec[i] != 0.0)
271.1766 + tcol_ind[++nnz] = i;
271.1767 + }
271.1768 + csa->tcol_nnz = nnz;
271.1769 + return;
271.1770 +}
271.1771 +#endif
271.1772 +
271.1773 +#if 1 /* copied from primal */
271.1774 +/***********************************************************************
271.1775 +* refine_tcol - refine pivot column of the simplex table
271.1776 +*
271.1777 +* This routine refines the pivot column of the simplex table assuming
271.1778 +* that it was previously computed by the routine eval_tcol. */
271.1779 +
271.1780 +static void refine_tcol(struct csa *csa)
271.1781 +{ int m = csa->m;
271.1782 +#ifdef GLP_DEBUG
271.1783 + int n = csa->n;
271.1784 +#endif
271.1785 + int *head = csa->head;
271.1786 + int q = csa->q;
271.1787 + int *tcol_ind = csa->tcol_ind;
271.1788 + double *tcol_vec = csa->tcol_vec;
271.1789 + double *h = csa->work3;
271.1790 + int i, k, nnz;
271.1791 +#ifdef GLP_DEBUG
271.1792 + xassert(1 <= q && q <= n);
271.1793 +#endif
271.1794 + k = head[m+q]; /* x[k] = xN[q] */
271.1795 +#ifdef GLP_DEBUG
271.1796 + xassert(1 <= k && k <= m+n);
271.1797 +#endif
271.1798 + /* construct the right-hand side vector h = - N[q] */
271.1799 + for (i = 1; i <= m; i++)
271.1800 + h[i] = 0.0;
271.1801 + if (k <= m)
271.1802 + { /* N[q] is k-th column of submatrix I */
271.1803 + h[k] = -1.0;
271.1804 + }
271.1805 + else
271.1806 + { /* N[q] is (k-m)-th column of submatrix (-A) */
271.1807 + int *A_ptr = csa->A_ptr;
271.1808 + int *A_ind = csa->A_ind;
271.1809 + double *A_val = csa->A_val;
271.1810 + int beg, end, ptr;
271.1811 + beg = A_ptr[k-m];
271.1812 + end = A_ptr[k-m+1];
271.1813 + for (ptr = beg; ptr < end; ptr++)
271.1814 + h[A_ind[ptr]] = A_val[ptr];
271.1815 + }
271.1816 + /* refine solution of B * tcol = h */
271.1817 + refine_ftran(csa, h, tcol_vec);
271.1818 + /* construct sparse pattern of the pivot column */
271.1819 + nnz = 0;
271.1820 + for (i = 1; i <= m; i++)
271.1821 + { if (tcol_vec[i] != 0.0)
271.1822 + tcol_ind[++nnz] = i;
271.1823 + }
271.1824 + csa->tcol_nnz = nnz;
271.1825 + return;
271.1826 +}
271.1827 +#endif
271.1828 +
271.1829 +/***********************************************************************
271.1830 +* update_cbar - update reduced costs of non-basic variables
271.1831 +*
271.1832 +* This routine updates reduced costs of all (except fixed) non-basic
271.1833 +* variables for the adjacent basis. */
271.1834 +
271.1835 +static void update_cbar(struct csa *csa)
271.1836 +{
271.1837 +#ifdef GLP_DEBUG
271.1838 + int n = csa->n;
271.1839 +#endif
271.1840 + double *cbar = csa->cbar;
271.1841 + int trow_nnz = csa->trow_nnz;
271.1842 + int *trow_ind = csa->trow_ind;
271.1843 + double *trow_vec = csa->trow_vec;
271.1844 + int q = csa->q;
271.1845 + double new_dq = csa->new_dq;
271.1846 + int j, pos;
271.1847 +#ifdef GLP_DEBUG
271.1848 + xassert(1 <= q && q <= n);
271.1849 +#endif
271.1850 + /* set new reduced cost of xN[q] */
271.1851 + cbar[q] = new_dq;
271.1852 + /* update reduced costs of other non-basic variables */
271.1853 + if (new_dq == 0.0) goto done;
271.1854 + for (pos = 1; pos <= trow_nnz; pos++)
271.1855 + { j = trow_ind[pos];
271.1856 +#ifdef GLP_DEBUG
271.1857 + xassert(1 <= j && j <= n);
271.1858 +#endif
271.1859 + if (j != q)
271.1860 + cbar[j] -= trow_vec[j] * new_dq;
271.1861 + }
271.1862 +done: return;
271.1863 +}
271.1864 +
271.1865 +/***********************************************************************
271.1866 +* update_bbar - update values of basic variables
271.1867 +*
271.1868 +* This routine updates values of all basic variables for the adjacent
271.1869 +* basis. */
271.1870 +
271.1871 +static void update_bbar(struct csa *csa)
271.1872 +{
271.1873 +#ifdef GLP_DEBUG
271.1874 + int m = csa->m;
271.1875 + int n = csa->n;
271.1876 +#endif
271.1877 + double *bbar = csa->bbar;
271.1878 + int p = csa->p;
271.1879 + double delta = csa->delta;
271.1880 + int q = csa->q;
271.1881 + int tcol_nnz = csa->tcol_nnz;
271.1882 + int *tcol_ind = csa->tcol_ind;
271.1883 + double *tcol_vec = csa->tcol_vec;
271.1884 + int i, pos;
271.1885 + double teta;
271.1886 +#ifdef GLP_DEBUG
271.1887 + xassert(1 <= p && p <= m);
271.1888 + xassert(1 <= q && q <= n);
271.1889 +#endif
271.1890 + /* determine the change of xN[q] in the adjacent basis */
271.1891 +#ifdef GLP_DEBUG
271.1892 + xassert(tcol_vec[p] != 0.0);
271.1893 +#endif
271.1894 + teta = delta / tcol_vec[p];
271.1895 + /* set new primal value of xN[q] */
271.1896 + bbar[p] = get_xN(csa, q) + teta;
271.1897 + /* update primal values of other basic variables */
271.1898 + if (teta == 0.0) goto done;
271.1899 + for (pos = 1; pos <= tcol_nnz; pos++)
271.1900 + { i = tcol_ind[pos];
271.1901 +#ifdef GLP_DEBUG
271.1902 + xassert(1 <= i && i <= m);
271.1903 +#endif
271.1904 + if (i != p)
271.1905 + bbar[i] += tcol_vec[i] * teta;
271.1906 + }
271.1907 +done: return;
271.1908 +}
271.1909 +
271.1910 +/***********************************************************************
271.1911 +* update_gamma - update steepest edge coefficients
271.1912 +*
271.1913 +* This routine updates steepest-edge coefficients for the adjacent
271.1914 +* basis. */
271.1915 +
271.1916 +static void update_gamma(struct csa *csa)
271.1917 +{ int m = csa->m;
271.1918 +#ifdef GLP_DEBUG
271.1919 + int n = csa->n;
271.1920 +#endif
271.1921 + char *type = csa->type;
271.1922 + int *head = csa->head;
271.1923 + char *refsp = csa->refsp;
271.1924 + double *gamma = csa->gamma;
271.1925 + int p = csa->p;
271.1926 + int trow_nnz = csa->trow_nnz;
271.1927 + int *trow_ind = csa->trow_ind;
271.1928 + double *trow_vec = csa->trow_vec;
271.1929 + int q = csa->q;
271.1930 + int tcol_nnz = csa->tcol_nnz;
271.1931 + int *tcol_ind = csa->tcol_ind;
271.1932 + double *tcol_vec = csa->tcol_vec;
271.1933 + double *u = csa->work3;
271.1934 + int i, j, k,pos;
271.1935 + double gamma_p, eta_p, pivot, t, t1, t2;
271.1936 +#ifdef GLP_DEBUG
271.1937 + xassert(1 <= p && p <= m);
271.1938 + xassert(1 <= q && q <= n);
271.1939 +#endif
271.1940 + /* the basis changes, so decrease the count */
271.1941 + xassert(csa->refct > 0);
271.1942 + csa->refct--;
271.1943 + /* recompute gamma[p] for the current basis more accurately and
271.1944 + compute auxiliary vector u */
271.1945 +#ifdef GLP_DEBUG
271.1946 + xassert(type[head[p]] != GLP_FR);
271.1947 +#endif
271.1948 + gamma_p = eta_p = (refsp[head[p]] ? 1.0 : 0.0);
271.1949 + for (i = 1; i <= m; i++) u[i] = 0.0;
271.1950 + for (pos = 1; pos <= trow_nnz; pos++)
271.1951 + { j = trow_ind[pos];
271.1952 +#ifdef GLP_DEBUG
271.1953 + xassert(1 <= j && j <= n);
271.1954 +#endif
271.1955 + k = head[m+j]; /* x[k] = xN[j] */
271.1956 +#ifdef GLP_DEBUG
271.1957 + xassert(1 <= k && k <= m+n);
271.1958 + xassert(type[k] != GLP_FX);
271.1959 +#endif
271.1960 + if (!refsp[k]) continue;
271.1961 + t = trow_vec[j];
271.1962 + gamma_p += t * t;
271.1963 + /* u := u + N[j] * delta[j] * trow[j] */
271.1964 + if (k <= m)
271.1965 + { /* N[k] = k-j stolbec submatrix I */
271.1966 + u[k] += t;
271.1967 + }
271.1968 + else
271.1969 + { /* N[k] = k-m-k stolbec (-A) */
271.1970 + int *A_ptr = csa->A_ptr;
271.1971 + int *A_ind = csa->A_ind;
271.1972 + double *A_val = csa->A_val;
271.1973 + int beg, end, ptr;
271.1974 + beg = A_ptr[k-m];
271.1975 + end = A_ptr[k-m+1];
271.1976 + for (ptr = beg; ptr < end; ptr++)
271.1977 + u[A_ind[ptr]] -= t * A_val[ptr];
271.1978 + }
271.1979 + }
271.1980 + xassert(csa->valid);
271.1981 + bfd_ftran(csa->bfd, u);
271.1982 + /* update gamma[i] for other basic variables (except xB[p] and
271.1983 + free variables) */
271.1984 + pivot = tcol_vec[p];
271.1985 +#ifdef GLP_DEBUG
271.1986 + xassert(pivot != 0.0);
271.1987 +#endif
271.1988 + for (pos = 1; pos <= tcol_nnz; pos++)
271.1989 + { i = tcol_ind[pos];
271.1990 +#ifdef GLP_DEBUG
271.1991 + xassert(1 <= i && i <= m);
271.1992 +#endif
271.1993 + k = head[i];
271.1994 +#ifdef GLP_DEBUG
271.1995 + xassert(1 <= k && k <= m+n);
271.1996 +#endif
271.1997 + /* skip xB[p] */
271.1998 + if (i == p) continue;
271.1999 + /* skip free basic variable */
271.2000 + if (type[head[i]] == GLP_FR)
271.2001 + {
271.2002 +#ifdef GLP_DEBUG
271.2003 + xassert(gamma[i] == 1.0);
271.2004 +#endif
271.2005 + continue;
271.2006 + }
271.2007 + /* compute gamma[i] for the adjacent basis */
271.2008 + t = tcol_vec[i] / pivot;
271.2009 + t1 = gamma[i] + t * t * gamma_p + 2.0 * t * u[i];
271.2010 + t2 = (refsp[k] ? 1.0 : 0.0) + eta_p * t * t;
271.2011 + gamma[i] = (t1 >= t2 ? t1 : t2);
271.2012 + /* (though gamma[i] can be exact zero, because the reference
271.2013 + space does not include non-basic fixed variables) */
271.2014 + if (gamma[i] < DBL_EPSILON) gamma[i] = DBL_EPSILON;
271.2015 + }
271.2016 + /* compute gamma[p] for the adjacent basis */
271.2017 + if (type[head[m+q]] == GLP_FR)
271.2018 + gamma[p] = 1.0;
271.2019 + else
271.2020 + { gamma[p] = gamma_p / (pivot * pivot);
271.2021 + if (gamma[p] < DBL_EPSILON) gamma[p] = DBL_EPSILON;
271.2022 + }
271.2023 + /* if xB[p], which becomes xN[q] in the adjacent basis, is fixed
271.2024 + and belongs to the reference space, remove it from there, and
271.2025 + change all gamma's appropriately */
271.2026 + k = head[p];
271.2027 + if (type[k] == GLP_FX && refsp[k])
271.2028 + { refsp[k] = 0;
271.2029 + for (pos = 1; pos <= tcol_nnz; pos++)
271.2030 + { i = tcol_ind[pos];
271.2031 + if (i == p)
271.2032 + { if (type[head[m+q]] == GLP_FR) continue;
271.2033 + t = 1.0 / tcol_vec[p];
271.2034 + }
271.2035 + else
271.2036 + { if (type[head[i]] == GLP_FR) continue;
271.2037 + t = tcol_vec[i] / tcol_vec[p];
271.2038 + }
271.2039 + gamma[i] -= t * t;
271.2040 + if (gamma[i] < DBL_EPSILON) gamma[i] = DBL_EPSILON;
271.2041 + }
271.2042 + }
271.2043 + return;
271.2044 +}
271.2045 +
271.2046 +#if 1 /* copied from primal */
271.2047 +/***********************************************************************
271.2048 +* err_in_bbar - compute maximal relative error in primal solution
271.2049 +*
271.2050 +* This routine returns maximal relative error:
271.2051 +*
271.2052 +* max |beta[i] - bbar[i]| / (1 + |beta[i]|),
271.2053 +*
271.2054 +* where beta and bbar are, respectively, directly computed and the
271.2055 +* current (updated) values of basic variables.
271.2056 +*
271.2057 +* NOTE: The routine is intended only for debugginig purposes. */
271.2058 +
271.2059 +static double err_in_bbar(struct csa *csa)
271.2060 +{ int m = csa->m;
271.2061 + double *bbar = csa->bbar;
271.2062 + int i;
271.2063 + double e, emax, *beta;
271.2064 + beta = xcalloc(1+m, sizeof(double));
271.2065 + eval_beta(csa, beta);
271.2066 + emax = 0.0;
271.2067 + for (i = 1; i <= m; i++)
271.2068 + { e = fabs(beta[i] - bbar[i]) / (1.0 + fabs(beta[i]));
271.2069 + if (emax < e) emax = e;
271.2070 + }
271.2071 + xfree(beta);
271.2072 + return emax;
271.2073 +}
271.2074 +#endif
271.2075 +
271.2076 +#if 1 /* copied from primal */
271.2077 +/***********************************************************************
271.2078 +* err_in_cbar - compute maximal relative error in dual solution
271.2079 +*
271.2080 +* This routine returns maximal relative error:
271.2081 +*
271.2082 +* max |cost[j] - cbar[j]| / (1 + |cost[j]|),
271.2083 +*
271.2084 +* where cost and cbar are, respectively, directly computed and the
271.2085 +* current (updated) reduced costs of non-basic non-fixed variables.
271.2086 +*
271.2087 +* NOTE: The routine is intended only for debugginig purposes. */
271.2088 +
271.2089 +static double err_in_cbar(struct csa *csa)
271.2090 +{ int m = csa->m;
271.2091 + int n = csa->n;
271.2092 + char *stat = csa->stat;
271.2093 + double *cbar = csa->cbar;
271.2094 + int j;
271.2095 + double e, emax, cost, *pi;
271.2096 + pi = xcalloc(1+m, sizeof(double));
271.2097 + eval_pi(csa, pi);
271.2098 + emax = 0.0;
271.2099 + for (j = 1; j <= n; j++)
271.2100 + { if (stat[j] == GLP_NS) continue;
271.2101 + cost = eval_cost(csa, pi, j);
271.2102 + e = fabs(cost - cbar[j]) / (1.0 + fabs(cost));
271.2103 + if (emax < e) emax = e;
271.2104 + }
271.2105 + xfree(pi);
271.2106 + return emax;
271.2107 +}
271.2108 +#endif
271.2109 +
271.2110 +/***********************************************************************
271.2111 +* err_in_gamma - compute maximal relative error in steepest edge cff.
271.2112 +*
271.2113 +* This routine returns maximal relative error:
271.2114 +*
271.2115 +* max |gamma'[j] - gamma[j]| / (1 + |gamma'[j]),
271.2116 +*
271.2117 +* where gamma'[j] and gamma[j] are, respectively, directly computed
271.2118 +* and the current (updated) steepest edge coefficients for non-basic
271.2119 +* non-fixed variable x[j].
271.2120 +*
271.2121 +* NOTE: The routine is intended only for debugginig purposes. */
271.2122 +
271.2123 +static double err_in_gamma(struct csa *csa)
271.2124 +{ int m = csa->m;
271.2125 + char *type = csa->type;
271.2126 + int *head = csa->head;
271.2127 + double *gamma = csa->gamma;
271.2128 + double *exact = csa->work4;
271.2129 + int i;
271.2130 + double e, emax, temp;
271.2131 + eval_gamma(csa, exact);
271.2132 + emax = 0.0;
271.2133 + for (i = 1; i <= m; i++)
271.2134 + { if (type[head[i]] == GLP_FR)
271.2135 + { xassert(gamma[i] == 1.0);
271.2136 + xassert(exact[i] == 1.0);
271.2137 + continue;
271.2138 + }
271.2139 + temp = exact[i];
271.2140 + e = fabs(temp - gamma[i]) / (1.0 + fabs(temp));
271.2141 + if (emax < e) emax = e;
271.2142 + }
271.2143 + return emax;
271.2144 +}
271.2145 +
271.2146 +/***********************************************************************
271.2147 +* change_basis - change basis header
271.2148 +*
271.2149 +* This routine changes the basis header to make it corresponding to
271.2150 +* the adjacent basis. */
271.2151 +
271.2152 +static void change_basis(struct csa *csa)
271.2153 +{ int m = csa->m;
271.2154 +#ifdef GLP_DEBUG
271.2155 + int n = csa->n;
271.2156 +#endif
271.2157 + char *type = csa->type;
271.2158 + int *head = csa->head;
271.2159 +#if 1 /* 06/IV-2009 */
271.2160 + int *bind = csa->bind;
271.2161 +#endif
271.2162 + char *stat = csa->stat;
271.2163 + int p = csa->p;
271.2164 + double delta = csa->delta;
271.2165 + int q = csa->q;
271.2166 + int k;
271.2167 + /* xB[p] leaves the basis, xN[q] enters the basis */
271.2168 +#ifdef GLP_DEBUG
271.2169 + xassert(1 <= p && p <= m);
271.2170 + xassert(1 <= q && q <= n);
271.2171 +#endif
271.2172 + /* xB[p] <-> xN[q] */
271.2173 + k = head[p], head[p] = head[m+q], head[m+q] = k;
271.2174 +#if 1 /* 06/IV-2009 */
271.2175 + bind[head[p]] = p, bind[head[m+q]] = m + q;
271.2176 +#endif
271.2177 + if (type[k] == GLP_FX)
271.2178 + stat[q] = GLP_NS;
271.2179 + else if (delta > 0.0)
271.2180 + {
271.2181 +#ifdef GLP_DEBUG
271.2182 + xassert(type[k] == GLP_LO || type[k] == GLP_DB);
271.2183 +#endif
271.2184 + stat[q] = GLP_NL;
271.2185 + }
271.2186 + else /* delta < 0.0 */
271.2187 + {
271.2188 +#ifdef GLP_DEBUG
271.2189 + xassert(type[k] == GLP_UP || type[k] == GLP_DB);
271.2190 +#endif
271.2191 + stat[q] = GLP_NU;
271.2192 + }
271.2193 + return;
271.2194 +}
271.2195 +
271.2196 +/***********************************************************************
271.2197 +* check_feas - check dual feasibility of basic solution
271.2198 +*
271.2199 +* If the current basic solution is dual feasible within a tolerance,
271.2200 +* this routine returns zero, otherwise it returns non-zero. */
271.2201 +
271.2202 +static int check_feas(struct csa *csa, double tol_dj)
271.2203 +{ int m = csa->m;
271.2204 + int n = csa->n;
271.2205 + char *orig_type = csa->orig_type;
271.2206 + int *head = csa->head;
271.2207 + double *cbar = csa->cbar;
271.2208 + int j, k;
271.2209 + for (j = 1; j <= n; j++)
271.2210 + { k = head[m+j]; /* x[k] = xN[j] */
271.2211 +#ifdef GLP_DEBUG
271.2212 + xassert(1 <= k && k <= m+n);
271.2213 +#endif
271.2214 + if (cbar[j] < - tol_dj)
271.2215 + if (orig_type[k] == GLP_LO || orig_type[k] == GLP_FR)
271.2216 + return 1;
271.2217 + if (cbar[j] > + tol_dj)
271.2218 + if (orig_type[k] == GLP_UP || orig_type[k] == GLP_FR)
271.2219 + return 1;
271.2220 + }
271.2221 + return 0;
271.2222 +}
271.2223 +
271.2224 +/***********************************************************************
271.2225 +* set_aux_bnds - assign auxiliary bounds to variables
271.2226 +*
271.2227 +* This routine assigns auxiliary bounds to variables to construct an
271.2228 +* LP problem solved on phase I. */
271.2229 +
271.2230 +static void set_aux_bnds(struct csa *csa)
271.2231 +{ int m = csa->m;
271.2232 + int n = csa->n;
271.2233 + char *type = csa->type;
271.2234 + double *lb = csa->lb;
271.2235 + double *ub = csa->ub;
271.2236 + char *orig_type = csa->orig_type;
271.2237 + int *head = csa->head;
271.2238 + char *stat = csa->stat;
271.2239 + double *cbar = csa->cbar;
271.2240 + int j, k;
271.2241 + for (k = 1; k <= m+n; k++)
271.2242 + { switch (orig_type[k])
271.2243 + { case GLP_FR:
271.2244 +#if 0
271.2245 + type[k] = GLP_DB, lb[k] = -1.0, ub[k] = +1.0;
271.2246 +#else
271.2247 + /* to force free variables to enter the basis */
271.2248 + type[k] = GLP_DB, lb[k] = -1e3, ub[k] = +1e3;
271.2249 +#endif
271.2250 + break;
271.2251 + case GLP_LO:
271.2252 + type[k] = GLP_DB, lb[k] = 0.0, ub[k] = +1.0;
271.2253 + break;
271.2254 + case GLP_UP:
271.2255 + type[k] = GLP_DB, lb[k] = -1.0, ub[k] = 0.0;
271.2256 + break;
271.2257 + case GLP_DB:
271.2258 + case GLP_FX:
271.2259 + type[k] = GLP_FX, lb[k] = ub[k] = 0.0;
271.2260 + break;
271.2261 + default:
271.2262 + xassert(orig_type != orig_type);
271.2263 + }
271.2264 + }
271.2265 + for (j = 1; j <= n; j++)
271.2266 + { k = head[m+j]; /* x[k] = xN[j] */
271.2267 +#ifdef GLP_DEBUG
271.2268 + xassert(1 <= k && k <= m+n);
271.2269 +#endif
271.2270 + if (type[k] == GLP_FX)
271.2271 + stat[j] = GLP_NS;
271.2272 + else if (cbar[j] >= 0.0)
271.2273 + stat[j] = GLP_NL;
271.2274 + else
271.2275 + stat[j] = GLP_NU;
271.2276 + }
271.2277 + return;
271.2278 +}
271.2279 +
271.2280 +/***********************************************************************
271.2281 +* set_orig_bnds - restore original bounds of variables
271.2282 +*
271.2283 +* This routine restores original types and bounds of variables and
271.2284 +* determines statuses of non-basic variables assuming that the current
271.2285 +* basis is dual feasible. */
271.2286 +
271.2287 +static void set_orig_bnds(struct csa *csa)
271.2288 +{ int m = csa->m;
271.2289 + int n = csa->n;
271.2290 + char *type = csa->type;
271.2291 + double *lb = csa->lb;
271.2292 + double *ub = csa->ub;
271.2293 + char *orig_type = csa->orig_type;
271.2294 + double *orig_lb = csa->orig_lb;
271.2295 + double *orig_ub = csa->orig_ub;
271.2296 + int *head = csa->head;
271.2297 + char *stat = csa->stat;
271.2298 + double *cbar = csa->cbar;
271.2299 + int j, k;
271.2300 + memcpy(&type[1], &orig_type[1], (m+n) * sizeof(char));
271.2301 + memcpy(&lb[1], &orig_lb[1], (m+n) * sizeof(double));
271.2302 + memcpy(&ub[1], &orig_ub[1], (m+n) * sizeof(double));
271.2303 + for (j = 1; j <= n; j++)
271.2304 + { k = head[m+j]; /* x[k] = xN[j] */
271.2305 +#ifdef GLP_DEBUG
271.2306 + xassert(1 <= k && k <= m+n);
271.2307 +#endif
271.2308 + switch (type[k])
271.2309 + { case GLP_FR:
271.2310 + stat[j] = GLP_NF;
271.2311 + break;
271.2312 + case GLP_LO:
271.2313 + stat[j] = GLP_NL;
271.2314 + break;
271.2315 + case GLP_UP:
271.2316 + stat[j] = GLP_NU;
271.2317 + break;
271.2318 + case GLP_DB:
271.2319 + if (cbar[j] >= +DBL_EPSILON)
271.2320 + stat[j] = GLP_NL;
271.2321 + else if (cbar[j] <= -DBL_EPSILON)
271.2322 + stat[j] = GLP_NU;
271.2323 + else if (fabs(lb[k]) <= fabs(ub[k]))
271.2324 + stat[j] = GLP_NL;
271.2325 + else
271.2326 + stat[j] = GLP_NU;
271.2327 + break;
271.2328 + case GLP_FX:
271.2329 + stat[j] = GLP_NS;
271.2330 + break;
271.2331 + default:
271.2332 + xassert(type != type);
271.2333 + }
271.2334 + }
271.2335 + return;
271.2336 +}
271.2337 +
271.2338 +/***********************************************************************
271.2339 +* check_stab - check numerical stability of basic solution
271.2340 +*
271.2341 +* If the current basic solution is dual feasible within a tolerance,
271.2342 +* this routine returns zero, otherwise it returns non-zero. */
271.2343 +
271.2344 +static int check_stab(struct csa *csa, double tol_dj)
271.2345 +{ int n = csa->n;
271.2346 + char *stat = csa->stat;
271.2347 + double *cbar = csa->cbar;
271.2348 + int j;
271.2349 + for (j = 1; j <= n; j++)
271.2350 + { if (cbar[j] < - tol_dj)
271.2351 + if (stat[j] == GLP_NL || stat[j] == GLP_NF) return 1;
271.2352 + if (cbar[j] > + tol_dj)
271.2353 + if (stat[j] == GLP_NU || stat[j] == GLP_NF) return 1;
271.2354 + }
271.2355 + return 0;
271.2356 +}
271.2357 +
271.2358 +#if 1 /* copied from primal */
271.2359 +/***********************************************************************
271.2360 +* eval_obj - compute original objective function
271.2361 +*
271.2362 +* This routine computes the current value of the original objective
271.2363 +* function. */
271.2364 +
271.2365 +static double eval_obj(struct csa *csa)
271.2366 +{ int m = csa->m;
271.2367 + int n = csa->n;
271.2368 + double *obj = csa->obj;
271.2369 + int *head = csa->head;
271.2370 + double *bbar = csa->bbar;
271.2371 + int i, j, k;
271.2372 + double sum;
271.2373 + sum = obj[0];
271.2374 + /* walk through the list of basic variables */
271.2375 + for (i = 1; i <= m; i++)
271.2376 + { k = head[i]; /* x[k] = xB[i] */
271.2377 +#ifdef GLP_DEBUG
271.2378 + xassert(1 <= k && k <= m+n);
271.2379 +#endif
271.2380 + if (k > m)
271.2381 + sum += obj[k-m] * bbar[i];
271.2382 + }
271.2383 + /* walk through the list of non-basic variables */
271.2384 + for (j = 1; j <= n; j++)
271.2385 + { k = head[m+j]; /* x[k] = xN[j] */
271.2386 +#ifdef GLP_DEBUG
271.2387 + xassert(1 <= k && k <= m+n);
271.2388 +#endif
271.2389 + if (k > m)
271.2390 + sum += obj[k-m] * get_xN(csa, j);
271.2391 + }
271.2392 + return sum;
271.2393 +}
271.2394 +#endif
271.2395 +
271.2396 +/***********************************************************************
271.2397 +* display - display the search progress
271.2398 +*
271.2399 +* This routine displays some information about the search progress. */
271.2400 +
271.2401 +static void display(struct csa *csa, const glp_smcp *parm, int spec)
271.2402 +{ int m = csa->m;
271.2403 + int n = csa->n;
271.2404 + double *coef = csa->coef;
271.2405 + char *orig_type = csa->orig_type;
271.2406 + int *head = csa->head;
271.2407 + char *stat = csa->stat;
271.2408 + int phase = csa->phase;
271.2409 + double *bbar = csa->bbar;
271.2410 + double *cbar = csa->cbar;
271.2411 + int i, j, cnt;
271.2412 + double sum;
271.2413 + if (parm->msg_lev < GLP_MSG_ON) goto skip;
271.2414 + if (parm->out_dly > 0 &&
271.2415 + 1000.0 * xdifftime(xtime(), csa->tm_beg) < parm->out_dly)
271.2416 + goto skip;
271.2417 + if (csa->it_cnt == csa->it_dpy) goto skip;
271.2418 + if (!spec && csa->it_cnt % parm->out_frq != 0) goto skip;
271.2419 + /* compute the sum of dual infeasibilities */
271.2420 + sum = 0.0;
271.2421 + if (phase == 1)
271.2422 + { for (i = 1; i <= m; i++)
271.2423 + sum -= coef[head[i]] * bbar[i];
271.2424 + for (j = 1; j <= n; j++)
271.2425 + sum -= coef[head[m+j]] * get_xN(csa, j);
271.2426 + }
271.2427 + else
271.2428 + { for (j = 1; j <= n; j++)
271.2429 + { if (cbar[j] < 0.0)
271.2430 + if (stat[j] == GLP_NL || stat[j] == GLP_NF)
271.2431 + sum -= cbar[j];
271.2432 + if (cbar[j] > 0.0)
271.2433 + if (stat[j] == GLP_NU || stat[j] == GLP_NF)
271.2434 + sum += cbar[j];
271.2435 + }
271.2436 + }
271.2437 + /* determine the number of basic fixed variables */
271.2438 + cnt = 0;
271.2439 + for (i = 1; i <= m; i++)
271.2440 + if (orig_type[head[i]] == GLP_FX) cnt++;
271.2441 + if (csa->phase == 1)
271.2442 + xprintf(" %6d: %24s infeas = %10.3e (%d)\n",
271.2443 + csa->it_cnt, "", sum, cnt);
271.2444 + else
271.2445 + xprintf("|%6d: obj = %17.9e infeas = %10.3e (%d)\n",
271.2446 + csa->it_cnt, eval_obj(csa), sum, cnt);
271.2447 + csa->it_dpy = csa->it_cnt;
271.2448 +skip: return;
271.2449 +}
271.2450 +
271.2451 +#if 1 /* copied from primal */
271.2452 +/***********************************************************************
271.2453 +* store_sol - store basic solution back to the problem object
271.2454 +*
271.2455 +* This routine stores basic solution components back to the problem
271.2456 +* object. */
271.2457 +
271.2458 +static void store_sol(struct csa *csa, glp_prob *lp, int p_stat,
271.2459 + int d_stat, int ray)
271.2460 +{ int m = csa->m;
271.2461 + int n = csa->n;
271.2462 + double zeta = csa->zeta;
271.2463 + int *head = csa->head;
271.2464 + char *stat = csa->stat;
271.2465 + double *bbar = csa->bbar;
271.2466 + double *cbar = csa->cbar;
271.2467 + int i, j, k;
271.2468 +#ifdef GLP_DEBUG
271.2469 + xassert(lp->m == m);
271.2470 + xassert(lp->n == n);
271.2471 +#endif
271.2472 + /* basis factorization */
271.2473 +#ifdef GLP_DEBUG
271.2474 + xassert(!lp->valid && lp->bfd == NULL);
271.2475 + xassert(csa->valid && csa->bfd != NULL);
271.2476 +#endif
271.2477 + lp->valid = 1, csa->valid = 0;
271.2478 + lp->bfd = csa->bfd, csa->bfd = NULL;
271.2479 + memcpy(&lp->head[1], &head[1], m * sizeof(int));
271.2480 + /* basic solution status */
271.2481 + lp->pbs_stat = p_stat;
271.2482 + lp->dbs_stat = d_stat;
271.2483 + /* objective function value */
271.2484 + lp->obj_val = eval_obj(csa);
271.2485 + /* simplex iteration count */
271.2486 + lp->it_cnt = csa->it_cnt;
271.2487 + /* unbounded ray */
271.2488 + lp->some = ray;
271.2489 + /* basic variables */
271.2490 + for (i = 1; i <= m; i++)
271.2491 + { k = head[i]; /* x[k] = xB[i] */
271.2492 +#ifdef GLP_DEBUG
271.2493 + xassert(1 <= k && k <= m+n);
271.2494 +#endif
271.2495 + if (k <= m)
271.2496 + { GLPROW *row = lp->row[k];
271.2497 + row->stat = GLP_BS;
271.2498 + row->bind = i;
271.2499 + row->prim = bbar[i] / row->rii;
271.2500 + row->dual = 0.0;
271.2501 + }
271.2502 + else
271.2503 + { GLPCOL *col = lp->col[k-m];
271.2504 + col->stat = GLP_BS;
271.2505 + col->bind = i;
271.2506 + col->prim = bbar[i] * col->sjj;
271.2507 + col->dual = 0.0;
271.2508 + }
271.2509 + }
271.2510 + /* non-basic variables */
271.2511 + for (j = 1; j <= n; j++)
271.2512 + { k = head[m+j]; /* x[k] = xN[j] */
271.2513 +#ifdef GLP_DEBUG
271.2514 + xassert(1 <= k && k <= m+n);
271.2515 +#endif
271.2516 + if (k <= m)
271.2517 + { GLPROW *row = lp->row[k];
271.2518 + row->stat = stat[j];
271.2519 + row->bind = 0;
271.2520 +#if 0
271.2521 + row->prim = get_xN(csa, j) / row->rii;
271.2522 +#else
271.2523 + switch (stat[j])
271.2524 + { case GLP_NL:
271.2525 + row->prim = row->lb; break;
271.2526 + case GLP_NU:
271.2527 + row->prim = row->ub; break;
271.2528 + case GLP_NF:
271.2529 + row->prim = 0.0; break;
271.2530 + case GLP_NS:
271.2531 + row->prim = row->lb; break;
271.2532 + default:
271.2533 + xassert(stat != stat);
271.2534 + }
271.2535 +#endif
271.2536 + row->dual = (cbar[j] * row->rii) / zeta;
271.2537 + }
271.2538 + else
271.2539 + { GLPCOL *col = lp->col[k-m];
271.2540 + col->stat = stat[j];
271.2541 + col->bind = 0;
271.2542 +#if 0
271.2543 + col->prim = get_xN(csa, j) * col->sjj;
271.2544 +#else
271.2545 + switch (stat[j])
271.2546 + { case GLP_NL:
271.2547 + col->prim = col->lb; break;
271.2548 + case GLP_NU:
271.2549 + col->prim = col->ub; break;
271.2550 + case GLP_NF:
271.2551 + col->prim = 0.0; break;
271.2552 + case GLP_NS:
271.2553 + col->prim = col->lb; break;
271.2554 + default:
271.2555 + xassert(stat != stat);
271.2556 + }
271.2557 +#endif
271.2558 + col->dual = (cbar[j] / col->sjj) / zeta;
271.2559 + }
271.2560 + }
271.2561 + return;
271.2562 +}
271.2563 +#endif
271.2564 +
271.2565 +/***********************************************************************
271.2566 +* free_csa - deallocate common storage area
271.2567 +*
271.2568 +* This routine frees all the memory allocated to arrays in the common
271.2569 +* storage area (CSA). */
271.2570 +
271.2571 +static void free_csa(struct csa *csa)
271.2572 +{ xfree(csa->type);
271.2573 + xfree(csa->lb);
271.2574 + xfree(csa->ub);
271.2575 + xfree(csa->coef);
271.2576 + xfree(csa->orig_type);
271.2577 + xfree(csa->orig_lb);
271.2578 + xfree(csa->orig_ub);
271.2579 + xfree(csa->obj);
271.2580 + xfree(csa->A_ptr);
271.2581 + xfree(csa->A_ind);
271.2582 + xfree(csa->A_val);
271.2583 +#if 1 /* 06/IV-2009 */
271.2584 + xfree(csa->AT_ptr);
271.2585 + xfree(csa->AT_ind);
271.2586 + xfree(csa->AT_val);
271.2587 +#endif
271.2588 + xfree(csa->head);
271.2589 +#if 1 /* 06/IV-2009 */
271.2590 + xfree(csa->bind);
271.2591 +#endif
271.2592 + xfree(csa->stat);
271.2593 +#if 0 /* 06/IV-2009 */
271.2594 + xfree(csa->N_ptr);
271.2595 + xfree(csa->N_len);
271.2596 + xfree(csa->N_ind);
271.2597 + xfree(csa->N_val);
271.2598 +#endif
271.2599 + xfree(csa->bbar);
271.2600 + xfree(csa->cbar);
271.2601 + xfree(csa->refsp);
271.2602 + xfree(csa->gamma);
271.2603 + xfree(csa->trow_ind);
271.2604 + xfree(csa->trow_vec);
271.2605 +#ifdef GLP_LONG_STEP /* 07/IV-2009 */
271.2606 + xfree(csa->bkpt);
271.2607 +#endif
271.2608 + xfree(csa->tcol_ind);
271.2609 + xfree(csa->tcol_vec);
271.2610 + xfree(csa->work1);
271.2611 + xfree(csa->work2);
271.2612 + xfree(csa->work3);
271.2613 + xfree(csa->work4);
271.2614 + xfree(csa);
271.2615 + return;
271.2616 +}
271.2617 +
271.2618 +/***********************************************************************
271.2619 +* spx_dual - core LP solver based on the dual simplex method
271.2620 +*
271.2621 +* SYNOPSIS
271.2622 +*
271.2623 +* #include "glpspx.h"
271.2624 +* int spx_dual(glp_prob *lp, const glp_smcp *parm);
271.2625 +*
271.2626 +* DESCRIPTION
271.2627 +*
271.2628 +* The routine spx_dual is a core LP solver based on the two-phase dual
271.2629 +* simplex method.
271.2630 +*
271.2631 +* RETURNS
271.2632 +*
271.2633 +* 0 LP instance has been successfully solved.
271.2634 +*
271.2635 +* GLP_EOBJLL
271.2636 +* Objective lower limit has been reached (maximization).
271.2637 +*
271.2638 +* GLP_EOBJUL
271.2639 +* Objective upper limit has been reached (minimization).
271.2640 +*
271.2641 +* GLP_EITLIM
271.2642 +* Iteration limit has been exhausted.
271.2643 +*
271.2644 +* GLP_ETMLIM
271.2645 +* Time limit has been exhausted.
271.2646 +*
271.2647 +* GLP_EFAIL
271.2648 +* The solver failed to solve LP instance. */
271.2649 +
271.2650 +int spx_dual(glp_prob *lp, const glp_smcp *parm)
271.2651 +{ struct csa *csa;
271.2652 + int binv_st = 2;
271.2653 + /* status of basis matrix factorization:
271.2654 + 0 - invalid; 1 - just computed; 2 - updated */
271.2655 + int bbar_st = 0;
271.2656 + /* status of primal values of basic variables:
271.2657 + 0 - invalid; 1 - just computed; 2 - updated */
271.2658 + int cbar_st = 0;
271.2659 + /* status of reduced costs of non-basic variables:
271.2660 + 0 - invalid; 1 - just computed; 2 - updated */
271.2661 + int rigorous = 0;
271.2662 + /* rigorous mode flag; this flag is used to enable iterative
271.2663 + refinement on computing pivot rows and columns of the simplex
271.2664 + table */
271.2665 + int check = 0;
271.2666 + int p_stat, d_stat, ret;
271.2667 + /* allocate and initialize the common storage area */
271.2668 + csa = alloc_csa(lp);
271.2669 + init_csa(csa, lp);
271.2670 + if (parm->msg_lev >= GLP_MSG_DBG)
271.2671 + xprintf("Objective scale factor = %g\n", csa->zeta);
271.2672 +loop: /* main loop starts here */
271.2673 + /* compute factorization of the basis matrix */
271.2674 + if (binv_st == 0)
271.2675 + { ret = invert_B(csa);
271.2676 + if (ret != 0)
271.2677 + { if (parm->msg_lev >= GLP_MSG_ERR)
271.2678 + { xprintf("Error: unable to factorize the basis matrix (%d"
271.2679 + ")\n", ret);
271.2680 + xprintf("Sorry, basis recovery procedure not implemented"
271.2681 + " yet\n");
271.2682 + }
271.2683 + xassert(!lp->valid && lp->bfd == NULL);
271.2684 + lp->bfd = csa->bfd, csa->bfd = NULL;
271.2685 + lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
271.2686 + lp->obj_val = 0.0;
271.2687 + lp->it_cnt = csa->it_cnt;
271.2688 + lp->some = 0;
271.2689 + ret = GLP_EFAIL;
271.2690 + goto done;
271.2691 + }
271.2692 + csa->valid = 1;
271.2693 + binv_st = 1; /* just computed */
271.2694 + /* invalidate basic solution components */
271.2695 + bbar_st = cbar_st = 0;
271.2696 + }
271.2697 + /* compute reduced costs of non-basic variables */
271.2698 + if (cbar_st == 0)
271.2699 + { eval_cbar(csa);
271.2700 + cbar_st = 1; /* just computed */
271.2701 + /* determine the search phase, if not determined yet */
271.2702 + if (csa->phase == 0)
271.2703 + { if (check_feas(csa, 0.90 * parm->tol_dj) != 0)
271.2704 + { /* current basic solution is dual infeasible */
271.2705 + /* start searching for dual feasible solution */
271.2706 + csa->phase = 1;
271.2707 + set_aux_bnds(csa);
271.2708 + }
271.2709 + else
271.2710 + { /* current basic solution is dual feasible */
271.2711 + /* start searching for optimal solution */
271.2712 + csa->phase = 2;
271.2713 + set_orig_bnds(csa);
271.2714 + }
271.2715 + xassert(check_stab(csa, parm->tol_dj) == 0);
271.2716 + /* some non-basic double-bounded variables might become
271.2717 + fixed (on phase I) or vice versa (on phase II) */
271.2718 +#if 0 /* 06/IV-2009 */
271.2719 + build_N(csa);
271.2720 +#endif
271.2721 + csa->refct = 0;
271.2722 + /* bounds of non-basic variables have been changed, so
271.2723 + invalidate primal values */
271.2724 + bbar_st = 0;
271.2725 + }
271.2726 + /* make sure that the current basic solution remains dual
271.2727 + feasible */
271.2728 + if (check_stab(csa, parm->tol_dj) != 0)
271.2729 + { if (parm->msg_lev >= GLP_MSG_ERR)
271.2730 + xprintf("Warning: numerical instability (dual simplex, p"
271.2731 + "hase %s)\n", csa->phase == 1 ? "I" : "II");
271.2732 +#if 1
271.2733 + if (parm->meth == GLP_DUALP)
271.2734 + { store_sol(csa, lp, GLP_UNDEF, GLP_UNDEF, 0);
271.2735 + ret = GLP_EFAIL;
271.2736 + goto done;
271.2737 + }
271.2738 +#endif
271.2739 + /* restart the search */
271.2740 + csa->phase = 0;
271.2741 + binv_st = 0;
271.2742 + rigorous = 5;
271.2743 + goto loop;
271.2744 + }
271.2745 + }
271.2746 + xassert(csa->phase == 1 || csa->phase == 2);
271.2747 + /* on phase I we do not need to wait until the current basic
271.2748 + solution becomes primal feasible; it is sufficient to make
271.2749 + sure that all reduced costs have correct signs */
271.2750 + if (csa->phase == 1 && check_feas(csa, parm->tol_dj) == 0)
271.2751 + { /* the current basis is dual feasible; switch to phase II */
271.2752 + display(csa, parm, 1);
271.2753 + csa->phase = 2;
271.2754 + if (cbar_st != 1)
271.2755 + { eval_cbar(csa);
271.2756 + cbar_st = 1;
271.2757 + }
271.2758 + set_orig_bnds(csa);
271.2759 +#if 0 /* 06/IV-2009 */
271.2760 + build_N(csa);
271.2761 +#endif
271.2762 + csa->refct = 0;
271.2763 + bbar_st = 0;
271.2764 + }
271.2765 + /* compute primal values of basic variables */
271.2766 + if (bbar_st == 0)
271.2767 + { eval_bbar(csa);
271.2768 + if (csa->phase == 2)
271.2769 + csa->bbar[0] = eval_obj(csa);
271.2770 + bbar_st = 1; /* just computed */
271.2771 + }
271.2772 + /* redefine the reference space, if required */
271.2773 + switch (parm->pricing)
271.2774 + { case GLP_PT_STD:
271.2775 + break;
271.2776 + case GLP_PT_PSE:
271.2777 + if (csa->refct == 0) reset_refsp(csa);
271.2778 + break;
271.2779 + default:
271.2780 + xassert(parm != parm);
271.2781 + }
271.2782 + /* at this point the basis factorization and all basic solution
271.2783 + components are valid */
271.2784 + xassert(binv_st && bbar_st && cbar_st);
271.2785 + /* check accuracy of current basic solution components (only for
271.2786 + debugging) */
271.2787 + if (check)
271.2788 + { double e_bbar = err_in_bbar(csa);
271.2789 + double e_cbar = err_in_cbar(csa);
271.2790 + double e_gamma =
271.2791 + (parm->pricing == GLP_PT_PSE ? err_in_gamma(csa) : 0.0);
271.2792 + xprintf("e_bbar = %10.3e; e_cbar = %10.3e; e_gamma = %10.3e\n",
271.2793 + e_bbar, e_cbar, e_gamma);
271.2794 + xassert(e_bbar <= 1e-5 && e_cbar <= 1e-5 && e_gamma <= 1e-3);
271.2795 + }
271.2796 + /* if the objective has to be maximized, check if it has reached
271.2797 + its lower limit */
271.2798 + if (csa->phase == 2 && csa->zeta < 0.0 &&
271.2799 + parm->obj_ll > -DBL_MAX && csa->bbar[0] <= parm->obj_ll)
271.2800 + { if (bbar_st != 1 || cbar_st != 1)
271.2801 + { if (bbar_st != 1) bbar_st = 0;
271.2802 + if (cbar_st != 1) cbar_st = 0;
271.2803 + goto loop;
271.2804 + }
271.2805 + display(csa, parm, 1);
271.2806 + if (parm->msg_lev >= GLP_MSG_ALL)
271.2807 + xprintf("OBJECTIVE LOWER LIMIT REACHED; SEARCH TERMINATED\n"
271.2808 + );
271.2809 + store_sol(csa, lp, GLP_INFEAS, GLP_FEAS, 0);
271.2810 + ret = GLP_EOBJLL;
271.2811 + goto done;
271.2812 + }
271.2813 + /* if the objective has to be minimized, check if it has reached
271.2814 + its upper limit */
271.2815 + if (csa->phase == 2 && csa->zeta > 0.0 &&
271.2816 + parm->obj_ul < +DBL_MAX && csa->bbar[0] >= parm->obj_ul)
271.2817 + { if (bbar_st != 1 || cbar_st != 1)
271.2818 + { if (bbar_st != 1) bbar_st = 0;
271.2819 + if (cbar_st != 1) cbar_st = 0;
271.2820 + goto loop;
271.2821 + }
271.2822 + display(csa, parm, 1);
271.2823 + if (parm->msg_lev >= GLP_MSG_ALL)
271.2824 + xprintf("OBJECTIVE UPPER LIMIT REACHED; SEARCH TERMINATED\n"
271.2825 + );
271.2826 + store_sol(csa, lp, GLP_INFEAS, GLP_FEAS, 0);
271.2827 + ret = GLP_EOBJUL;
271.2828 + goto done;
271.2829 + }
271.2830 + /* check if the iteration limit has been exhausted */
271.2831 + if (parm->it_lim < INT_MAX &&
271.2832 + csa->it_cnt - csa->it_beg >= parm->it_lim)
271.2833 + { if (csa->phase == 2 && bbar_st != 1 || cbar_st != 1)
271.2834 + { if (csa->phase == 2 && bbar_st != 1) bbar_st = 0;
271.2835 + if (cbar_st != 1) cbar_st = 0;
271.2836 + goto loop;
271.2837 + }
271.2838 + display(csa, parm, 1);
271.2839 + if (parm->msg_lev >= GLP_MSG_ALL)
271.2840 + xprintf("ITERATION LIMIT EXCEEDED; SEARCH TERMINATED\n");
271.2841 + switch (csa->phase)
271.2842 + { case 1:
271.2843 + d_stat = GLP_INFEAS;
271.2844 + set_orig_bnds(csa);
271.2845 + eval_bbar(csa);
271.2846 + break;
271.2847 + case 2:
271.2848 + d_stat = GLP_FEAS;
271.2849 + break;
271.2850 + default:
271.2851 + xassert(csa != csa);
271.2852 + }
271.2853 + store_sol(csa, lp, GLP_INFEAS, d_stat, 0);
271.2854 + ret = GLP_EITLIM;
271.2855 + goto done;
271.2856 + }
271.2857 + /* check if the time limit has been exhausted */
271.2858 + if (parm->tm_lim < INT_MAX &&
271.2859 + 1000.0 * xdifftime(xtime(), csa->tm_beg) >= parm->tm_lim)
271.2860 + { if (csa->phase == 2 && bbar_st != 1 || cbar_st != 1)
271.2861 + { if (csa->phase == 2 && bbar_st != 1) bbar_st = 0;
271.2862 + if (cbar_st != 1) cbar_st = 0;
271.2863 + goto loop;
271.2864 + }
271.2865 + display(csa, parm, 1);
271.2866 + if (parm->msg_lev >= GLP_MSG_ALL)
271.2867 + xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
271.2868 + switch (csa->phase)
271.2869 + { case 1:
271.2870 + d_stat = GLP_INFEAS;
271.2871 + set_orig_bnds(csa);
271.2872 + eval_bbar(csa);
271.2873 + break;
271.2874 + case 2:
271.2875 + d_stat = GLP_FEAS;
271.2876 + break;
271.2877 + default:
271.2878 + xassert(csa != csa);
271.2879 + }
271.2880 + store_sol(csa, lp, GLP_INFEAS, d_stat, 0);
271.2881 + ret = GLP_ETMLIM;
271.2882 + goto done;
271.2883 + }
271.2884 + /* display the search progress */
271.2885 + display(csa, parm, 0);
271.2886 + /* choose basic variable xB[p] */
271.2887 + chuzr(csa, parm->tol_bnd);
271.2888 + if (csa->p == 0)
271.2889 + { if (bbar_st != 1 || cbar_st != 1)
271.2890 + { if (bbar_st != 1) bbar_st = 0;
271.2891 + if (cbar_st != 1) cbar_st = 0;
271.2892 + goto loop;
271.2893 + }
271.2894 + display(csa, parm, 1);
271.2895 + switch (csa->phase)
271.2896 + { case 1:
271.2897 + if (parm->msg_lev >= GLP_MSG_ALL)
271.2898 + xprintf("PROBLEM HAS NO DUAL FEASIBLE SOLUTION\n");
271.2899 + set_orig_bnds(csa);
271.2900 + eval_bbar(csa);
271.2901 + p_stat = GLP_INFEAS, d_stat = GLP_NOFEAS;
271.2902 + break;
271.2903 + case 2:
271.2904 + if (parm->msg_lev >= GLP_MSG_ALL)
271.2905 + xprintf("OPTIMAL SOLUTION FOUND\n");
271.2906 + p_stat = d_stat = GLP_FEAS;
271.2907 + break;
271.2908 + default:
271.2909 + xassert(csa != csa);
271.2910 + }
271.2911 + store_sol(csa, lp, p_stat, d_stat, 0);
271.2912 + ret = 0;
271.2913 + goto done;
271.2914 + }
271.2915 + /* compute pivot row of the simplex table */
271.2916 + { double *rho = csa->work4;
271.2917 + eval_rho(csa, rho);
271.2918 + if (rigorous) refine_rho(csa, rho);
271.2919 + eval_trow(csa, rho);
271.2920 + sort_trow(csa, parm->tol_bnd);
271.2921 + }
271.2922 + /* unlike primal simplex there is no need to check accuracy of
271.2923 + the primal value of xB[p] (which might be computed using the
271.2924 + pivot row), since bbar is a result of FTRAN */
271.2925 +#ifdef GLP_LONG_STEP /* 07/IV-2009 */
271.2926 + long_step(csa);
271.2927 + if (csa->nbps > 0)
271.2928 + { csa->q = csa->bkpt[csa->nbps].j;
271.2929 + if (csa->delta > 0.0)
271.2930 + csa->new_dq = + csa->bkpt[csa->nbps].t;
271.2931 + else
271.2932 + csa->new_dq = - csa->bkpt[csa->nbps].t;
271.2933 + }
271.2934 + else
271.2935 +#endif
271.2936 + /* choose non-basic variable xN[q] */
271.2937 + switch (parm->r_test)
271.2938 + { case GLP_RT_STD:
271.2939 + chuzc(csa, 0.0);
271.2940 + break;
271.2941 + case GLP_RT_HAR:
271.2942 + chuzc(csa, 0.30 * parm->tol_dj);
271.2943 + break;
271.2944 + default:
271.2945 + xassert(parm != parm);
271.2946 + }
271.2947 + if (csa->q == 0)
271.2948 + { if (bbar_st != 1 || cbar_st != 1 || !rigorous)
271.2949 + { if (bbar_st != 1) bbar_st = 0;
271.2950 + if (cbar_st != 1) cbar_st = 0;
271.2951 + rigorous = 1;
271.2952 + goto loop;
271.2953 + }
271.2954 + display(csa, parm, 1);
271.2955 + switch (csa->phase)
271.2956 + { case 1:
271.2957 + if (parm->msg_lev >= GLP_MSG_ERR)
271.2958 + xprintf("Error: unable to choose basic variable on ph"
271.2959 + "ase I\n");
271.2960 + xassert(!lp->valid && lp->bfd == NULL);
271.2961 + lp->bfd = csa->bfd, csa->bfd = NULL;
271.2962 + lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
271.2963 + lp->obj_val = 0.0;
271.2964 + lp->it_cnt = csa->it_cnt;
271.2965 + lp->some = 0;
271.2966 + ret = GLP_EFAIL;
271.2967 + break;
271.2968 + case 2:
271.2969 + if (parm->msg_lev >= GLP_MSG_ALL)
271.2970 + xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n");
271.2971 + store_sol(csa, lp, GLP_NOFEAS, GLP_FEAS,
271.2972 + csa->head[csa->p]);
271.2973 + ret = 0;
271.2974 + break;
271.2975 + default:
271.2976 + xassert(csa != csa);
271.2977 + }
271.2978 + goto done;
271.2979 + }
271.2980 + /* check if the pivot element is acceptable */
271.2981 + { double piv = csa->trow_vec[csa->q];
271.2982 + double eps = 1e-5 * (1.0 + 0.01 * csa->trow_max);
271.2983 + if (fabs(piv) < eps)
271.2984 + { if (parm->msg_lev >= GLP_MSG_DBG)
271.2985 + xprintf("piv = %.12g; eps = %g\n", piv, eps);
271.2986 + if (!rigorous)
271.2987 + { rigorous = 5;
271.2988 + goto loop;
271.2989 + }
271.2990 + }
271.2991 + }
271.2992 + /* now xN[q] and xB[p] have been chosen anyhow */
271.2993 + /* compute pivot column of the simplex table */
271.2994 + eval_tcol(csa);
271.2995 + if (rigorous) refine_tcol(csa);
271.2996 + /* accuracy check based on the pivot element */
271.2997 + { double piv1 = csa->tcol_vec[csa->p]; /* more accurate */
271.2998 + double piv2 = csa->trow_vec[csa->q]; /* less accurate */
271.2999 + xassert(piv1 != 0.0);
271.3000 + if (fabs(piv1 - piv2) > 1e-8 * (1.0 + fabs(piv1)) ||
271.3001 + !(piv1 > 0.0 && piv2 > 0.0 || piv1 < 0.0 && piv2 < 0.0))
271.3002 + { if (parm->msg_lev >= GLP_MSG_DBG)
271.3003 + xprintf("piv1 = %.12g; piv2 = %.12g\n", piv1, piv2);
271.3004 + if (binv_st != 1 || !rigorous)
271.3005 + { if (binv_st != 1) binv_st = 0;
271.3006 + rigorous = 5;
271.3007 + goto loop;
271.3008 + }
271.3009 + /* (not a good idea; should be revised later) */
271.3010 + if (csa->tcol_vec[csa->p] == 0.0)
271.3011 + { csa->tcol_nnz++;
271.3012 + xassert(csa->tcol_nnz <= csa->m);
271.3013 + csa->tcol_ind[csa->tcol_nnz] = csa->p;
271.3014 + }
271.3015 + csa->tcol_vec[csa->p] = piv2;
271.3016 + }
271.3017 + }
271.3018 + /* update primal values of basic variables */
271.3019 +#ifdef GLP_LONG_STEP /* 07/IV-2009 */
271.3020 + if (csa->nbps > 0)
271.3021 + { int kk, j, k;
271.3022 + for (kk = 1; kk < csa->nbps; kk++)
271.3023 + { if (csa->bkpt[kk].t >= csa->bkpt[csa->nbps].t) continue;
271.3024 + j = csa->bkpt[kk].j;
271.3025 + k = csa->head[csa->m + j];
271.3026 + xassert(csa->type[k] == GLP_DB);
271.3027 + if (csa->stat[j] == GLP_NL)
271.3028 + csa->stat[j] = GLP_NU;
271.3029 + else
271.3030 + csa->stat[j] = GLP_NL;
271.3031 + }
271.3032 + }
271.3033 + bbar_st = 0;
271.3034 +#else
271.3035 + update_bbar(csa);
271.3036 + if (csa->phase == 2)
271.3037 + csa->bbar[0] += (csa->cbar[csa->q] / csa->zeta) *
271.3038 + (csa->delta / csa->tcol_vec[csa->p]);
271.3039 + bbar_st = 2; /* updated */
271.3040 +#endif
271.3041 + /* update reduced costs of non-basic variables */
271.3042 + update_cbar(csa);
271.3043 + cbar_st = 2; /* updated */
271.3044 + /* update steepest edge coefficients */
271.3045 + switch (parm->pricing)
271.3046 + { case GLP_PT_STD:
271.3047 + break;
271.3048 + case GLP_PT_PSE:
271.3049 + if (csa->refct > 0) update_gamma(csa);
271.3050 + break;
271.3051 + default:
271.3052 + xassert(parm != parm);
271.3053 + }
271.3054 + /* update factorization of the basis matrix */
271.3055 + ret = update_B(csa, csa->p, csa->head[csa->m+csa->q]);
271.3056 + if (ret == 0)
271.3057 + binv_st = 2; /* updated */
271.3058 + else
271.3059 + { csa->valid = 0;
271.3060 + binv_st = 0; /* invalid */
271.3061 + }
271.3062 +#if 0 /* 06/IV-2009 */
271.3063 + /* update matrix N */
271.3064 + del_N_col(csa, csa->q, csa->head[csa->m+csa->q]);
271.3065 + if (csa->type[csa->head[csa->p]] != GLP_FX)
271.3066 + add_N_col(csa, csa->q, csa->head[csa->p]);
271.3067 +#endif
271.3068 + /* change the basis header */
271.3069 + change_basis(csa);
271.3070 + /* iteration complete */
271.3071 + csa->it_cnt++;
271.3072 + if (rigorous > 0) rigorous--;
271.3073 + goto loop;
271.3074 +done: /* deallocate the common storage area */
271.3075 + free_csa(csa);
271.3076 + /* return to the calling program */
271.3077 + return ret;
271.3078 +}
271.3079 +
271.3080 +/* eof */
272.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
272.2 +++ b/src/glpsql.c Mon Dec 06 13:09:21 2010 +0100
272.3 @@ -0,0 +1,1627 @@
272.4 +/* glpsql.c */
272.5 +
272.6 +/***********************************************************************
272.7 +* This code is part of GLPK (GNU Linear Programming Kit).
272.8 +*
272.9 +* Author: Heinrich Schuchardt <xypron.glpk@gmx.de>.
272.10 +*
272.11 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
272.12 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
272.13 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
272.14 +* E-mail: <mao@gnu.org>.
272.15 +*
272.16 +* GLPK is free software: you can redistribute it and/or modify it
272.17 +* under the terms of the GNU General Public License as published by
272.18 +* the Free Software Foundation, either version 3 of the License, or
272.19 +* (at your option) any later version.
272.20 +*
272.21 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
272.22 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
272.23 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
272.24 +* License for more details.
272.25 +*
272.26 +* You should have received a copy of the GNU General Public License
272.27 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
272.28 +***********************************************************************/
272.29 +
272.30 +#ifdef HAVE_CONFIG_H
272.31 +#include <config.h>
272.32 +#endif
272.33 +
272.34 +#include "glpmpl.h"
272.35 +#include "glpsql.h"
272.36 +
272.37 +#ifdef ODBC_DLNAME
272.38 +#define HAVE_ODBC
272.39 +#define libodbc ODBC_DLNAME
272.40 +#define h_odbc (get_env_ptr()->h_odbc)
272.41 +#endif
272.42 +
272.43 +#ifdef MYSQL_DLNAME
272.44 +#define HAVE_MYSQL
272.45 +#define libmysql MYSQL_DLNAME
272.46 +#define h_mysql (get_env_ptr()->h_mysql)
272.47 +#endif
272.48 +
272.49 +static void *db_iodbc_open_int(TABDCA *dca, int mode, const char
272.50 + **sqllines);
272.51 +static void *db_mysql_open_int(TABDCA *dca, int mode, const char
272.52 + **sqllines);
272.53 +
272.54 +/**********************************************************************/
272.55 +
272.56 +#if defined(HAVE_ODBC) || defined(HAVE_MYSQL)
272.57 +
272.58 +#define SQL_FIELD_MAX 100
272.59 +/* maximal field count */
272.60 +
272.61 +#define SQL_FDLEN_MAX 255
272.62 +/* maximal field length */
272.63 +
272.64 +/***********************************************************************
272.65 +* NAME
272.66 +*
272.67 +* args_concat - concatenate arguments
272.68 +*
272.69 +* SYNOPSIS
272.70 +*
272.71 +* static char **args_concat(TABDCA *dca);
272.72 +*
272.73 +* DESCRIPTION
272.74 +*
272.75 +* The arguments passed in dca are SQL statements. A SQL statement may
272.76 +* be split over multiple arguments. The last argument of a SQL
272.77 +* statement will be terminated with a semilocon. Each SQL statement is
272.78 +* merged into a single zero terminated string. Boundaries between
272.79 +* arguments are replaced by space.
272.80 +*
272.81 +* RETURNS
272.82 +*
272.83 +* Buffer with SQL statements */
272.84 +
272.85 +static char **args_concat(TABDCA *dca)
272.86 +{
272.87 + const char *arg;
272.88 + int i;
272.89 + int j;
272.90 + int j0;
272.91 + int j1;
272.92 + int len;
272.93 + int lentot;
272.94 + int narg;
272.95 + int nline = 0;
272.96 + void *ret;
272.97 + char **sqllines = NULL;
272.98 +
272.99 + narg = mpl_tab_num_args(dca);
272.100 + /* The SQL statements start with argument 3. */
272.101 + if (narg < 3)
272.102 + return NULL;
272.103 + /* Count the SQL statements */
272.104 + for (j = 3; j <= narg; j++)
272.105 + {
272.106 + arg = mpl_tab_get_arg(dca, j);
272.107 + len = strlen(arg);
272.108 + if (arg[len-1] == ';' || j == narg)
272.109 + nline ++;
272.110 + }
272.111 + /* Allocate string buffer. */
272.112 + sqllines = (char **) xmalloc((nline+1) * sizeof(char **));
272.113 + /* Join arguments */
272.114 + sqllines[0] = NULL;
272.115 + j0 = 3;
272.116 + i = 0;
272.117 + lentot = 0;
272.118 + for (j = 3; j <= narg; j++)
272.119 + {
272.120 + arg = mpl_tab_get_arg(dca, j);
272.121 + len = strlen(arg);
272.122 + lentot += len;
272.123 + if (arg[len-1] == ';' || j == narg)
272.124 + { /* Join arguments for a single SQL statement */
272.125 + sqllines[i] = xmalloc(lentot+1);
272.126 + sqllines[i+1] = NULL;
272.127 + sqllines[i][0] = 0x00;
272.128 + for (j1 = j0; j1 <= j; j1++)
272.129 + { if(j1>j0)
272.130 + strcat(sqllines[i], " ");
272.131 + strcat(sqllines[i], mpl_tab_get_arg(dca, j1));
272.132 + }
272.133 + len = strlen(sqllines[i]);
272.134 + if (sqllines[i][len-1] == ';')
272.135 + sqllines[i][len-1] = 0x00;
272.136 + j0 = j+1;
272.137 + i++;
272.138 + lentot = 0;
272.139 + }
272.140 + }
272.141 + return sqllines;
272.142 +}
272.143 +
272.144 +/***********************************************************************
272.145 +* NAME
272.146 +*
272.147 +* free_buffer - free multiline string buffer
272.148 +*
272.149 +* SYNOPSIS
272.150 +*
272.151 +* static void free_buffer(char **buf);
272.152 +*
272.153 +* DESCRIPTION
272.154 +*
272.155 +* buf is a list of strings terminated by NULL.
272.156 +* The memory for the strings and for the list is released. */
272.157 +
272.158 +static void free_buffer(char **buf)
272.159 +{ int i;
272.160 +
272.161 + for(i = 0; buf[i] != NULL; i++)
272.162 + xfree(buf[i]);
272.163 + xfree(buf);
272.164 +}
272.165 +
272.166 +static int db_escaped_string_length(const char* from)
272.167 +/* length of escaped string */
272.168 +{
272.169 + int count;
272.170 + const char *pointer;
272.171 +
272.172 + for (pointer = from, count = 0; *pointer != (char) '\0'; pointer++,
272.173 + count++)
272.174 + {
272.175 + switch (*pointer)
272.176 + {
272.177 + case '\'':
272.178 + count++;
272.179 + break;
272.180 + }
272.181 + }
272.182 +
272.183 + return count;
272.184 +}
272.185 +
272.186 +static int db_escape_string (char *to, const char *from)
272.187 +/* escape string*/
272.188 +{
272.189 + const char *source = from;
272.190 + char *target = to;
272.191 + unsigned int remaining;
272.192 +
272.193 + remaining = strlen(from);
272.194 +
272.195 + if (to == NULL)
272.196 + to = (char *) (from + remaining);
272.197 +
272.198 + while (remaining > 0)
272.199 + {
272.200 + switch (*source)
272.201 + {
272.202 + case '\'':
272.203 + *target = '\'';
272.204 + target++;
272.205 + *target = '\'';
272.206 + break;
272.207 +
272.208 + default:
272.209 + *target = *source;
272.210 + }
272.211 + source++;
272.212 + target++;
272.213 + remaining--;
272.214 + }
272.215 +
272.216 + /* Write the terminating NUL character. */
272.217 + *target = '\0';
272.218 +
272.219 + return target - to;
272.220 +}
272.221 +
272.222 +static char *db_generate_select_stmt(TABDCA *dca)
272.223 +/* generate select statement */
272.224 +{
272.225 + char *arg;
272.226 + char const *field;
272.227 + char *query;
272.228 + int j;
272.229 + int narg;
272.230 + int nf;
272.231 + int total;
272.232 +
272.233 + total = 50;
272.234 + nf = mpl_tab_num_flds(dca);
272.235 + narg = mpl_tab_num_args(dca);
272.236 + for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
272.237 + {
272.238 + field = mpl_tab_get_name(dca, j);
272.239 + total += strlen(field);
272.240 + total += 2;
272.241 + }
272.242 + arg = (char *) mpl_tab_get_arg(dca, narg);
272.243 + total += strlen(arg);
272.244 + query = xmalloc( total * sizeof(char));
272.245 + strcpy (query, "SELECT ");
272.246 + for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
272.247 + {
272.248 + field = mpl_tab_get_name(dca, j);
272.249 + strcat(query, field);
272.250 + if ( j < nf )
272.251 + strcat(query, ", ");
272.252 + }
272.253 + strcat(query, " FROM ");
272.254 + strcat(query, arg);
272.255 + return query;
272.256 +}
272.257 +
272.258 +static char *db_generate_insert_stmt(TABDCA *dca)
272.259 +/* generate insert statement */
272.260 +{
272.261 + char *arg;
272.262 + char const *field;
272.263 + char *query;
272.264 + int j;
272.265 + int narg;
272.266 + int nf;
272.267 + int total;
272.268 +
272.269 + total = 50;
272.270 + nf = mpl_tab_num_flds(dca);
272.271 + narg = mpl_tab_num_args(dca);
272.272 + for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
272.273 + {
272.274 + field = mpl_tab_get_name(dca, j);
272.275 + total += strlen(field);
272.276 + total += 5;
272.277 + }
272.278 + arg = (char *) mpl_tab_get_arg(dca, narg);
272.279 + total += strlen(arg);
272.280 + query = xmalloc( (total+1) * sizeof(char));
272.281 + strcpy (query, "INSERT INTO ");
272.282 + strcat(query, arg);
272.283 + strcat(query, " ( ");
272.284 + for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
272.285 + {
272.286 + field = mpl_tab_get_name(dca, j);
272.287 + strcat(query, field);
272.288 + if ( j < nf )
272.289 + strcat(query, ", ");
272.290 + }
272.291 + strcat(query, " ) VALUES ( ");
272.292 + for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
272.293 + {
272.294 + strcat(query, "?");
272.295 + if ( j < nf )
272.296 + strcat(query, ", ");
272.297 + }
272.298 + strcat(query, " )");
272.299 + return query;
272.300 +}
272.301 +
272.302 +#endif
272.303 +
272.304 +/**********************************************************************/
272.305 +
272.306 +#ifndef HAVE_ODBC
272.307 +
272.308 +void *db_iodbc_open(TABDCA *dca, int mode)
272.309 +{ xassert(dca == dca);
272.310 + xassert(mode == mode);
272.311 + xprintf("iODBC table driver not supported\n");
272.312 + return NULL;
272.313 +}
272.314 +
272.315 +int db_iodbc_read(TABDCA *dca, void *link)
272.316 +{ xassert(dca != dca);
272.317 + xassert(link != link);
272.318 + return 0;
272.319 +}
272.320 +
272.321 +int db_iodbc_write(TABDCA *dca, void *link)
272.322 +{ xassert(dca != dca);
272.323 + xassert(link != link);
272.324 + return 0;
272.325 +}
272.326 +
272.327 +int db_iodbc_close(TABDCA *dca, void *link)
272.328 +{ xassert(dca != dca);
272.329 + xassert(link != link);
272.330 + return 0;
272.331 +}
272.332 +
272.333 +#else
272.334 +
272.335 +#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WOE__)
272.336 +#include <windows.h>
272.337 +#endif
272.338 +
272.339 +#include <sql.h>
272.340 +#include <sqlext.h>
272.341 +
272.342 +struct db_odbc
272.343 +{
272.344 + int mode; /*'R' = Read, 'W' = Write*/
272.345 + SQLHDBC hdbc; /*connection handle*/
272.346 + SQLHENV henv; /*environment handle*/
272.347 + SQLHSTMT hstmt; /*statement handle*/
272.348 + SQLSMALLINT nresultcols; /* columns in result*/
272.349 + SQLULEN collen[SQL_FIELD_MAX+1];
272.350 + SQLLEN outlen[SQL_FIELD_MAX+1];
272.351 + SQLSMALLINT coltype[SQL_FIELD_MAX+1];
272.352 + SQLCHAR data[SQL_FIELD_MAX+1][SQL_FDLEN_MAX+1];
272.353 + SQLCHAR colname[SQL_FIELD_MAX+1][SQL_FDLEN_MAX+1];
272.354 + int isnumeric[SQL_FIELD_MAX+1];
272.355 + int nf;
272.356 + /* number of fields in the csv file */
272.357 + int ref[1+SQL_FIELD_MAX];
272.358 + /* ref[k] = k', if k-th field of the csv file corresponds to
272.359 + k'-th field in the table statement; if ref[k] = 0, k-th field
272.360 + of the csv file is ignored */
272.361 + SQLCHAR *query;
272.362 + /* query generated by db_iodbc_open */
272.363 +};
272.364 +
272.365 +SQLRETURN SQL_API dl_SQLAllocHandle (
272.366 + SQLSMALLINT HandleType,
272.367 + SQLHANDLE InputHandle,
272.368 + SQLHANDLE *OutputHandle)
272.369 +{
272.370 + typedef SQLRETURN SQL_API ep_SQLAllocHandle(
272.371 + SQLSMALLINT HandleType,
272.372 + SQLHANDLE InputHandle,
272.373 + SQLHANDLE *OutputHandle);
272.374 +
272.375 + ep_SQLAllocHandle *fn;
272.376 + fn = (ep_SQLAllocHandle *) xdlsym(h_odbc, "SQLAllocHandle");
272.377 + xassert(fn != NULL);
272.378 + return (*fn)(HandleType, InputHandle, OutputHandle);
272.379 +}
272.380 +
272.381 +SQLRETURN SQL_API dl_SQLBindCol (
272.382 + SQLHSTMT StatementHandle,
272.383 + SQLUSMALLINT ColumnNumber,
272.384 + SQLSMALLINT TargetType,
272.385 + SQLPOINTER TargetValue,
272.386 + SQLLEN BufferLength,
272.387 + SQLLEN *StrLen_or_Ind)
272.388 +{
272.389 + typedef SQLRETURN SQL_API ep_SQLBindCol(
272.390 + SQLHSTMT StatementHandle,
272.391 + SQLUSMALLINT ColumnNumber,
272.392 + SQLSMALLINT TargetType,
272.393 + SQLPOINTER TargetValue,
272.394 + SQLLEN BufferLength,
272.395 + SQLLEN *StrLen_or_Ind);
272.396 + ep_SQLBindCol *fn;
272.397 + fn = (ep_SQLBindCol *) xdlsym(h_odbc, "SQLBindCol");
272.398 + xassert(fn != NULL);
272.399 + return (*fn)(StatementHandle, ColumnNumber, TargetType,
272.400 + TargetValue, BufferLength, StrLen_or_Ind);
272.401 +}
272.402 +
272.403 +SQLRETURN SQL_API dl_SQLCloseCursor (
272.404 + SQLHSTMT StatementHandle)
272.405 +{
272.406 + typedef SQLRETURN SQL_API ep_SQLCloseCursor (
272.407 + SQLHSTMT StatementHandle);
272.408 +
272.409 + ep_SQLCloseCursor *fn;
272.410 + fn = (ep_SQLCloseCursor *) xdlsym(h_odbc, "SQLCloseCursor");
272.411 + xassert(fn != NULL);
272.412 + return (*fn)(StatementHandle);
272.413 +}
272.414 +
272.415 +
272.416 +SQLRETURN SQL_API dl_SQLDisconnect (
272.417 + SQLHDBC ConnectionHandle)
272.418 +{
272.419 + typedef SQLRETURN SQL_API ep_SQLDisconnect(
272.420 + SQLHDBC ConnectionHandle);
272.421 +
272.422 + ep_SQLDisconnect *fn;
272.423 + fn = (ep_SQLDisconnect *) xdlsym(h_odbc, "SQLDisconnect");
272.424 + xassert(fn != NULL);
272.425 + return (*fn)(ConnectionHandle);
272.426 +}
272.427 +
272.428 +SQLRETURN SQL_API dl_SQLDriverConnect (
272.429 + SQLHDBC hdbc,
272.430 + SQLHWND hwnd,
272.431 + SQLCHAR *szConnStrIn,
272.432 + SQLSMALLINT cbConnStrIn,
272.433 + SQLCHAR *szConnStrOut,
272.434 + SQLSMALLINT cbConnStrOutMax,
272.435 + SQLSMALLINT *pcbConnStrOut,
272.436 + SQLUSMALLINT fDriverCompletion)
272.437 +{
272.438 + typedef SQLRETURN SQL_API ep_SQLDriverConnect(
272.439 + SQLHDBC hdbc,
272.440 + SQLHWND hwnd,
272.441 + SQLCHAR * szConnStrIn,
272.442 + SQLSMALLINT cbConnStrIn,
272.443 + SQLCHAR * szConnStrOut,
272.444 + SQLSMALLINT cbConnStrOutMax,
272.445 + SQLSMALLINT * pcbConnStrOut,
272.446 + SQLUSMALLINT fDriverCompletion);
272.447 +
272.448 + ep_SQLDriverConnect *fn;
272.449 + fn = (ep_SQLDriverConnect *) xdlsym(h_odbc, "SQLDriverConnect");
272.450 + xassert(fn != NULL);
272.451 + return (*fn)(hdbc, hwnd, szConnStrIn, cbConnStrIn, szConnStrOut,
272.452 + cbConnStrOutMax, pcbConnStrOut, fDriverCompletion);
272.453 +}
272.454 +
272.455 +SQLRETURN SQL_API dl_SQLEndTran (
272.456 + SQLSMALLINT HandleType,
272.457 + SQLHANDLE Handle,
272.458 + SQLSMALLINT CompletionType)
272.459 +{
272.460 + typedef SQLRETURN SQL_API ep_SQLEndTran (
272.461 + SQLSMALLINT HandleType,
272.462 + SQLHANDLE Handle,
272.463 + SQLSMALLINT CompletionType);
272.464 +
272.465 + ep_SQLEndTran *fn;
272.466 + fn = (ep_SQLEndTran *) xdlsym(h_odbc, "SQLEndTran");
272.467 + xassert(fn != NULL);
272.468 + return (*fn)(HandleType, Handle, CompletionType);
272.469 +}
272.470 +
272.471 +SQLRETURN SQL_API dl_SQLExecDirect (
272.472 + SQLHSTMT StatementHandle,
272.473 + SQLCHAR * StatementText,
272.474 + SQLINTEGER TextLength)
272.475 +{
272.476 + typedef SQLRETURN SQL_API ep_SQLExecDirect (
272.477 + SQLHSTMT StatementHandle,
272.478 + SQLCHAR * StatementText,
272.479 + SQLINTEGER TextLength);
272.480 +
272.481 + ep_SQLExecDirect *fn;
272.482 + fn = (ep_SQLExecDirect *) xdlsym(h_odbc, "SQLExecDirect");
272.483 + xassert(fn != NULL);
272.484 + return (*fn)(StatementHandle, StatementText, TextLength);
272.485 +}
272.486 +
272.487 +SQLRETURN SQL_API dl_SQLFetch (
272.488 + SQLHSTMT StatementHandle)
272.489 +{
272.490 + typedef SQLRETURN SQL_API ep_SQLFetch (
272.491 + SQLHSTMT StatementHandle);
272.492 +
272.493 + ep_SQLFetch *fn;
272.494 + fn = (ep_SQLFetch*) xdlsym(h_odbc, "SQLFetch");
272.495 + xassert(fn != NULL);
272.496 + return (*fn)(StatementHandle);
272.497 +}
272.498 +
272.499 +SQLRETURN SQL_API dl_SQLFreeHandle (
272.500 + SQLSMALLINT HandleType,
272.501 + SQLHANDLE Handle)
272.502 +{
272.503 + typedef SQLRETURN SQL_API ep_SQLFreeHandle (
272.504 + SQLSMALLINT HandleType,
272.505 + SQLHANDLE Handle);
272.506 +
272.507 + ep_SQLFreeHandle *fn;
272.508 + fn = (ep_SQLFreeHandle *) xdlsym(h_odbc, "SQLFreeHandle");
272.509 + xassert(fn != NULL);
272.510 + return (*fn)(HandleType, Handle);
272.511 +}
272.512 +
272.513 +SQLRETURN SQL_API dl_SQLDescribeCol (
272.514 + SQLHSTMT StatementHandle,
272.515 + SQLUSMALLINT ColumnNumber,
272.516 + SQLCHAR * ColumnName,
272.517 + SQLSMALLINT BufferLength,
272.518 + SQLSMALLINT * NameLength,
272.519 + SQLSMALLINT * DataType,
272.520 + SQLULEN * ColumnSize,
272.521 + SQLSMALLINT * DecimalDigits,
272.522 + SQLSMALLINT * Nullable)
272.523 +{
272.524 + typedef SQLRETURN SQL_API ep_SQLDescribeCol (
272.525 + SQLHSTMT StatementHandle,
272.526 + SQLUSMALLINT ColumnNumber,
272.527 + SQLCHAR *ColumnName,
272.528 + SQLSMALLINT BufferLength,
272.529 + SQLSMALLINT *NameLength,
272.530 + SQLSMALLINT *DataType,
272.531 + SQLULEN *ColumnSize,
272.532 + SQLSMALLINT *DecimalDigits,
272.533 + SQLSMALLINT *Nullable);
272.534 +
272.535 + ep_SQLDescribeCol *fn;
272.536 + fn = (ep_SQLDescribeCol *) xdlsym(h_odbc, "SQLDescribeCol");
272.537 + xassert(fn != NULL);
272.538 + return (*fn)(StatementHandle, ColumnNumber, ColumnName,
272.539 + BufferLength, NameLength,
272.540 + DataType, ColumnSize, DecimalDigits, Nullable);
272.541 +}
272.542 +
272.543 +SQLRETURN SQL_API dl_SQLGetDiagRec (
272.544 + SQLSMALLINT HandleType,
272.545 + SQLHANDLE Handle,
272.546 + SQLSMALLINT RecNumber,
272.547 + SQLCHAR *Sqlstate,
272.548 + SQLINTEGER *NativeError,
272.549 + SQLCHAR *MessageText,
272.550 + SQLSMALLINT BufferLength,
272.551 + SQLSMALLINT *TextLength)
272.552 +{
272.553 + typedef SQLRETURN SQL_API ep_SQLGetDiagRec (
272.554 + SQLSMALLINT HandleType,
272.555 + SQLHANDLE Handle,
272.556 + SQLSMALLINT RecNumber,
272.557 + SQLCHAR *Sqlstate,
272.558 + SQLINTEGER *NativeError,
272.559 + SQLCHAR *MessageText,
272.560 + SQLSMALLINT BufferLength,
272.561 + SQLSMALLINT *TextLength);
272.562 +
272.563 + ep_SQLGetDiagRec *fn;
272.564 + fn = (ep_SQLGetDiagRec *) xdlsym(h_odbc, "SQLGetDiagRec");
272.565 + xassert(fn != NULL);
272.566 + return (*fn)(HandleType, Handle, RecNumber, Sqlstate,
272.567 + NativeError, MessageText, BufferLength, TextLength);
272.568 +}
272.569 +
272.570 +SQLRETURN SQL_API dl_SQLGetInfo (
272.571 + SQLHDBC ConnectionHandle,
272.572 + SQLUSMALLINT InfoType,
272.573 + SQLPOINTER InfoValue,
272.574 + SQLSMALLINT BufferLength,
272.575 + SQLSMALLINT *StringLength)
272.576 +{
272.577 + typedef SQLRETURN SQL_API ep_SQLGetInfo (
272.578 + SQLHDBC ConnectionHandle,
272.579 + SQLUSMALLINT InfoType,
272.580 + SQLPOINTER InfoValue,
272.581 + SQLSMALLINT BufferLength,
272.582 + SQLSMALLINT *StringLength);
272.583 +
272.584 + ep_SQLGetInfo *fn;
272.585 + fn = (ep_SQLGetInfo *) xdlsym(h_odbc, "SQLGetInfo");
272.586 + xassert(fn != NULL);
272.587 + return (*fn)(ConnectionHandle, InfoType, InfoValue, BufferLength,
272.588 + StringLength);
272.589 +}
272.590 +
272.591 +SQLRETURN SQL_API dl_SQLNumResultCols (
272.592 + SQLHSTMT StatementHandle,
272.593 + SQLSMALLINT *ColumnCount)
272.594 +{
272.595 + typedef SQLRETURN SQL_API ep_SQLNumResultCols (
272.596 + SQLHSTMT StatementHandle,
272.597 + SQLSMALLINT *ColumnCount);
272.598 +
272.599 + ep_SQLNumResultCols *fn;
272.600 + fn = (ep_SQLNumResultCols *) xdlsym(h_odbc, "SQLNumResultCols");
272.601 + xassert(fn != NULL);
272.602 + return (*fn)(StatementHandle, ColumnCount);
272.603 +}
272.604 +
272.605 +SQLRETURN SQL_API dl_SQLSetConnectAttr (
272.606 + SQLHDBC ConnectionHandle,
272.607 + SQLINTEGER Attribute,
272.608 + SQLPOINTER Value,
272.609 + SQLINTEGER StringLength)
272.610 +{
272.611 + typedef SQLRETURN SQL_API ep_SQLSetConnectAttr (
272.612 + SQLHDBC ConnectionHandle,
272.613 + SQLINTEGER Attribute,
272.614 + SQLPOINTER Value,
272.615 + SQLINTEGER StringLength);
272.616 +
272.617 + ep_SQLSetConnectAttr *fn;
272.618 + fn = (ep_SQLSetConnectAttr *) xdlsym(h_odbc, "SQLSetConnectAttr");
272.619 + xassert(fn != NULL);
272.620 + return (*fn)(ConnectionHandle, Attribute, Value, StringLength);
272.621 +}
272.622 +
272.623 +SQLRETURN SQL_API dl_SQLSetEnvAttr (
272.624 + SQLHENV EnvironmentHandle,
272.625 + SQLINTEGER Attribute,
272.626 + SQLPOINTER Value,
272.627 + SQLINTEGER StringLength)
272.628 +{
272.629 + typedef SQLRETURN SQL_API ep_SQLSetEnvAttr (
272.630 + SQLHENV EnvironmentHandle,
272.631 + SQLINTEGER Attribute,
272.632 + SQLPOINTER Value,
272.633 + SQLINTEGER StringLength);
272.634 +
272.635 + ep_SQLSetEnvAttr *fn;
272.636 + fn = (ep_SQLSetEnvAttr *) xdlsym(h_odbc, "SQLSetEnvAttr");
272.637 + xassert(fn != NULL);
272.638 + return (*fn)(EnvironmentHandle, Attribute, Value, StringLength);
272.639 +}
272.640 +
272.641 +static void extract_error(
272.642 + char *fn,
272.643 + SQLHANDLE handle,
272.644 + SQLSMALLINT type);
272.645 +
272.646 +static int is_numeric(
272.647 + SQLSMALLINT coltype);
272.648 +
272.649 +/***********************************************************************
272.650 +* NAME
272.651 +*
272.652 +* db_iodbc_open - open connection to ODBC data base
272.653 +*
272.654 +* SYNOPSIS
272.655 +*
272.656 +* #include "glpsql.h"
272.657 +* void *db_iodbc_open(TABDCA *dca, int mode);
272.658 +*
272.659 +* DESCRIPTION
272.660 +*
272.661 +* The routine db_iodbc_open opens a connection to an ODBC data base.
272.662 +* It then executes the sql statements passed.
272.663 +*
272.664 +* In the case of table read the SELECT statement is executed.
272.665 +*
272.666 +* In the case of table write the INSERT statement is prepared.
272.667 +* RETURNS
272.668 +*
272.669 +* The routine returns a pointer to data storage area created. */
272.670 +void *db_iodbc_open(TABDCA *dca, int mode)
272.671 +{ void *ret;
272.672 + char **sqllines;
272.673 +
272.674 + sqllines = args_concat(dca);
272.675 + if (sqllines == NULL)
272.676 + { xprintf("Missing arguments in table statement.\n"
272.677 + "Please, supply table driver, dsn, and query.\n");
272.678 + return NULL;
272.679 + }
272.680 + ret = db_iodbc_open_int(dca, mode, (const char **) sqllines);
272.681 + free_buffer(sqllines);
272.682 + return ret;
272.683 +}
272.684 +
272.685 +static void *db_iodbc_open_int(TABDCA *dca, int mode, const char
272.686 + **sqllines)
272.687 +{
272.688 + struct db_odbc *sql;
272.689 + SQLRETURN ret;
272.690 + SQLCHAR FAR *dsn;
272.691 + SQLCHAR info[256];
272.692 + SQLSMALLINT colnamelen;
272.693 + SQLSMALLINT nullable;
272.694 + SQLSMALLINT scale;
272.695 + const char *arg;
272.696 + int narg;
272.697 + int i, j;
272.698 + int total;
272.699 +
272.700 + if (libodbc == NULL)
272.701 + {
272.702 + xprintf("No loader for shared ODBC library available\n");
272.703 + return NULL;
272.704 + }
272.705 +
272.706 + if (h_odbc == NULL)
272.707 + {
272.708 + h_odbc = xdlopen(libodbc);
272.709 + if (h_odbc == NULL)
272.710 + { xprintf("unable to open library %s\n", libodbc);
272.711 + xprintf("%s\n", xerrmsg());
272.712 + return NULL;
272.713 + }
272.714 + }
272.715 +
272.716 + sql = (struct db_odbc *) xmalloc(sizeof(struct db_odbc));
272.717 + if (sql == NULL)
272.718 + return NULL;
272.719 +
272.720 + sql->mode = mode;
272.721 + sql->hdbc = NULL;
272.722 + sql->henv = NULL;
272.723 + sql->hstmt = NULL;
272.724 + sql->query = NULL;
272.725 + narg = mpl_tab_num_args(dca);
272.726 +
272.727 + dsn = (SQLCHAR FAR *) mpl_tab_get_arg(dca, 2);
272.728 + /* allocate an environment handle */
272.729 + ret = dl_SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
272.730 + &(sql->henv));
272.731 + /* set attribute to enable application to run as ODBC 3.0
272.732 + application */
272.733 + ret = dl_SQLSetEnvAttr(sql->henv, SQL_ATTR_ODBC_VERSION,
272.734 + (void *) SQL_OV_ODBC3, 0);
272.735 + /* allocate a connection handle */
272.736 + ret = dl_SQLAllocHandle(SQL_HANDLE_DBC, sql->henv, &(sql->hdbc));
272.737 + /* connect */
272.738 + ret = dl_SQLDriverConnect(sql->hdbc, NULL, dsn, SQL_NTS, NULL, 0,
272.739 + NULL, SQL_DRIVER_COMPLETE);
272.740 + if (SQL_SUCCEEDED(ret))
272.741 + { /* output information about data base connection */
272.742 + xprintf("Connected to ");
272.743 + dl_SQLGetInfo(sql->hdbc, SQL_DBMS_NAME, (SQLPOINTER)info,
272.744 + sizeof(info), NULL);
272.745 + xprintf("%s ", info);
272.746 + dl_SQLGetInfo(sql->hdbc, SQL_DBMS_VER, (SQLPOINTER)info,
272.747 + sizeof(info), NULL);
272.748 + xprintf("%s - ", info);
272.749 + dl_SQLGetInfo(sql->hdbc, SQL_DATABASE_NAME, (SQLPOINTER)info,
272.750 + sizeof(info), NULL);
272.751 + xprintf("%s\n", info);
272.752 + }
272.753 + else
272.754 + { /* describe error */
272.755 + xprintf("Failed to connect\n");
272.756 + extract_error("SQLDriverConnect", sql->hdbc, SQL_HANDLE_DBC);
272.757 + dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
272.758 + dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
272.759 + xfree(sql);
272.760 + return NULL;
272.761 + }
272.762 + /* set AUTOCOMMIT on*/
272.763 + ret = dl_SQLSetConnectAttr(sql->hdbc, SQL_ATTR_AUTOCOMMIT,
272.764 + (SQLPOINTER)SQL_AUTOCOMMIT_ON, 0);
272.765 + /* allocate a statement handle */
272.766 + ret = dl_SQLAllocHandle(SQL_HANDLE_STMT, sql->hdbc, &(sql->hstmt));
272.767 +
272.768 + /* initialization queries */
272.769 + for(j = 0; sqllines[j+1] != NULL; j++)
272.770 + {
272.771 + sql->query = (SQLCHAR *) sqllines[j];
272.772 + xprintf("%s\n", sql->query);
272.773 + ret = dl_SQLExecDirect(sql->hstmt, sql->query, SQL_NTS);
272.774 + switch (ret)
272.775 + {
272.776 + case SQL_SUCCESS:
272.777 + case SQL_SUCCESS_WITH_INFO:
272.778 + case SQL_NO_DATA_FOUND:
272.779 + break;
272.780 + default:
272.781 + xprintf("db_iodbc_open: Query\n\"%s\"\nfailed.\n",
272.782 + sql->query);
272.783 + extract_error("SQLExecDirect", sql->hstmt, SQL_HANDLE_STMT);
272.784 + dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
272.785 + dl_SQLDisconnect(sql->hdbc);
272.786 + dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
272.787 + dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
272.788 + xfree(sql);
272.789 + return NULL;
272.790 + }
272.791 + /* commit statement */
272.792 + dl_SQLEndTran(SQL_HANDLE_ENV, sql->henv, SQL_COMMIT);
272.793 + }
272.794 +
272.795 + if ( sql->mode == 'R' )
272.796 + { sql->nf = mpl_tab_num_flds(dca);
272.797 + for(j = 0; sqllines[j] != NULL; j++)
272.798 + arg = sqllines[j];
272.799 + total = strlen(arg);
272.800 + if (total > 7 && 0 == strncmp(arg, "SELECT ", 7))
272.801 + {
272.802 + total = strlen(arg);
272.803 + sql->query = xmalloc( (total+1) * sizeof(char));
272.804 + strcpy (sql->query, arg);
272.805 + }
272.806 + else
272.807 + {
272.808 + sql->query = db_generate_select_stmt(dca);
272.809 + }
272.810 + xprintf("%s\n", sql->query);
272.811 + if (dl_SQLExecDirect(sql->hstmt, sql->query, SQL_NTS) !=
272.812 + SQL_SUCCESS)
272.813 + {
272.814 + xprintf("db_iodbc_open: Query\n\"%s\"\nfailed.\n", sql->query);
272.815 + extract_error("SQLExecDirect", sql->hstmt, SQL_HANDLE_STMT);
272.816 + dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
272.817 + dl_SQLDisconnect(sql->hdbc);
272.818 + dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
272.819 + dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
272.820 + xfree(sql->query);
272.821 + xfree(sql);
272.822 + return NULL;
272.823 + }
272.824 + xfree(sql->query);
272.825 + /* determine number of result columns */
272.826 + ret = dl_SQLNumResultCols(sql->hstmt, &sql->nresultcols);
272.827 + total = sql->nresultcols;
272.828 + if (total > SQL_FIELD_MAX)
272.829 + { xprintf("db_iodbc_open: Too many fields (> %d) in query.\n"
272.830 + "\"%s\"\n", SQL_FIELD_MAX, sql->query);
272.831 + dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
272.832 + dl_SQLDisconnect(sql->hdbc);
272.833 + dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
272.834 + dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
272.835 + xfree(sql->query);
272.836 + return NULL;
272.837 + }
272.838 + for (i = 1; i <= total; i++)
272.839 + { /* return a set of attributes for a column */
272.840 + ret = dl_SQLDescribeCol(sql->hstmt, (SQLSMALLINT) i,
272.841 + sql->colname[i], SQL_FDLEN_MAX,
272.842 + &colnamelen, &(sql->coltype[i]), &(sql->collen[i]), &scale,
272.843 + &nullable);
272.844 + sql->isnumeric[i] = is_numeric(sql->coltype[i]);
272.845 + /* bind columns to program vars, converting all types to CHAR*/
272.846 + dl_SQLBindCol(sql->hstmt, i, SQL_CHAR, sql->data[i],
272.847 + SQL_FDLEN_MAX, &(sql->outlen[i]));
272.848 + for (j = sql->nf; j >= 1; j--)
272.849 + { if (strcmp(mpl_tab_get_name(dca, j), sql->colname[i]) == 0)
272.850 + break;
272.851 + }
272.852 + sql->ref[i] = j;
272.853 + }
272.854 + }
272.855 + else if ( sql->mode == 'W' )
272.856 + { for(j = 0; sqllines[j] != NULL; j++)
272.857 + arg = sqllines[j];
272.858 + if ( NULL != strchr(arg, '?') )
272.859 + {
272.860 + total = strlen(arg);
272.861 + sql->query = xmalloc( (total+1) * sizeof(char));
272.862 + strcpy (sql->query, arg);
272.863 + }
272.864 + else
272.865 + {
272.866 + sql->query = db_generate_insert_stmt(dca);
272.867 + }
272.868 + xprintf("%s\n", sql->query);
272.869 + }
272.870 + return sql;
272.871 +}
272.872 +
272.873 +int db_iodbc_read(TABDCA *dca, void *link)
272.874 +{
272.875 + struct db_odbc *sql;
272.876 + SQLRETURN ret;
272.877 + char buf[SQL_FDLEN_MAX+1];
272.878 + int i;
272.879 + int len;
272.880 + double num;
272.881 +
272.882 + sql = (struct db_odbc *) link;
272.883 +
272.884 + xassert(sql != NULL);
272.885 + xassert(sql->mode == 'R');
272.886 +
272.887 + ret=dl_SQLFetch(sql->hstmt);
272.888 + if (ret== SQL_ERROR)
272.889 + return -1;
272.890 + if (ret== SQL_NO_DATA_FOUND)
272.891 + return -1; /*EOF*/
272.892 + for (i=1; i <= sql->nresultcols; i++)
272.893 + {
272.894 + if (sql->ref[i] > 0)
272.895 + {
272.896 + len = sql->outlen[i];
272.897 + if (len != SQL_NULL_DATA)
272.898 + {
272.899 + if (len > SQL_FDLEN_MAX)
272.900 + len = SQL_FDLEN_MAX;
272.901 + else if (len < 0)
272.902 + len = 0;
272.903 + strncpy(buf, (const char *) sql->data[i], len);
272.904 + buf[len] = 0x00;
272.905 + if (0 != (sql->isnumeric[i]))
272.906 + { strspx(buf); /* remove spaces*/
272.907 + if (str2num(buf, &num) != 0)
272.908 + { xprintf("'%s' cannot be converted to a number.\n",
272.909 + buf);
272.910 + return 1;
272.911 + }
272.912 + mpl_tab_set_num(dca, sql->ref[i], num);
272.913 + }
272.914 + else
272.915 + { mpl_tab_set_str(dca, sql->ref[i], strtrim(buf));
272.916 + }
272.917 + }
272.918 + }
272.919 + }
272.920 + return 0;
272.921 +}
272.922 +
272.923 +int db_iodbc_write(TABDCA *dca, void *link)
272.924 +{
272.925 + struct db_odbc *sql;
272.926 + char *part;
272.927 + char *query;
272.928 + char *template;
272.929 + char num[50];
272.930 + int k;
272.931 + int len;
272.932 + int nf;
272.933 +
272.934 + sql = (struct db_odbc *) link;
272.935 + xassert(sql != NULL);
272.936 + xassert(sql->mode == 'W');
272.937 +
272.938 + len = strlen(sql->query);
272.939 + template = (char *) xmalloc( (len + 1) * sizeof(char) );
272.940 + strcpy(template, sql->query);
272.941 +
272.942 + nf = mpl_tab_num_flds(dca);
272.943 + for (k = 1; k <= nf; k++)
272.944 + { switch (mpl_tab_get_type(dca, k))
272.945 + { case 'N':
272.946 + len += 20;
272.947 + break;
272.948 + case 'S':
272.949 + len += db_escaped_string_length(mpl_tab_get_str(dca, k));
272.950 + len += 2;
272.951 + break;
272.952 + default:
272.953 + xassert(dca != dca);
272.954 + }
272.955 + }
272.956 + query = xmalloc( (len + 1 ) * sizeof(char) );
272.957 + query[0] = 0x00;
272.958 + for (k = 1, part = strtok (template, "?"); (part != NULL);
272.959 + part = strtok (NULL, "?"), k++)
272.960 + {
272.961 + if (k > nf) break;
272.962 + strcat( query, part );
272.963 + switch (mpl_tab_get_type(dca, k))
272.964 + { case 'N':
272.965 +#if 0 /* 02/XI-2010 by xypron */
272.966 + sprintf(num, "%-18g",mpl_tab_get_num(dca, k));
272.967 +#else
272.968 + sprintf(num, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k));
272.969 +#endif
272.970 + strcat( query, num );
272.971 + break;
272.972 + case 'S':
272.973 + strcat( query, "'");
272.974 + db_escape_string( query + strlen(query),
272.975 + mpl_tab_get_str(dca, k) );
272.976 + strcat( query, "'");
272.977 + break;
272.978 + default:
272.979 + xassert(dca != dca);
272.980 + }
272.981 + }
272.982 + if (part != NULL)
272.983 + strcat(query, part);
272.984 + if (dl_SQLExecDirect(sql->hstmt, (SQLCHAR *) query, SQL_NTS)
272.985 + != SQL_SUCCESS)
272.986 + {
272.987 + xprintf("db_iodbc_write: Query\n\"%s\"\nfailed.\n", query);
272.988 + extract_error("SQLExecDirect", sql->hdbc, SQL_HANDLE_DBC);
272.989 + xfree(query);
272.990 + xfree(template);
272.991 + return 1;
272.992 + }
272.993 +
272.994 + xfree(query);
272.995 + xfree(template);
272.996 + return 0;
272.997 +}
272.998 +
272.999 +int db_iodbc_close(TABDCA *dca, void *link)
272.1000 +{
272.1001 + struct db_odbc *sql;
272.1002 +
272.1003 + sql = (struct db_odbc *) link;
272.1004 + xassert(sql != NULL);
272.1005 + /* Commit */
272.1006 + if ( sql->mode == 'W' )
272.1007 + dl_SQLEndTran(SQL_HANDLE_ENV, sql->henv, SQL_COMMIT);
272.1008 + if ( sql->mode == 'R' )
272.1009 + dl_SQLCloseCursor(sql->hstmt);
272.1010 +
272.1011 + dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
272.1012 + dl_SQLDisconnect(sql->hdbc);
272.1013 + dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
272.1014 + dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
272.1015 + if ( sql->mode == 'W' )
272.1016 + xfree(sql->query);
272.1017 + xfree(sql);
272.1018 + dca->link = NULL;
272.1019 + return 0;
272.1020 +}
272.1021 +
272.1022 +static void extract_error(
272.1023 + char *fn,
272.1024 + SQLHANDLE handle,
272.1025 + SQLSMALLINT type)
272.1026 +{
272.1027 + SQLINTEGER i = 0;
272.1028 + SQLINTEGER native;
272.1029 + SQLCHAR state[ 7 ];
272.1030 + SQLCHAR text[256];
272.1031 + SQLSMALLINT len;
272.1032 + SQLRETURN ret;
272.1033 +
272.1034 + xprintf("\nThe driver reported the following diagnostics whilst "
272.1035 + "running %s\n", fn);
272.1036 +
272.1037 + do
272.1038 + {
272.1039 + ret = dl_SQLGetDiagRec(type, handle, ++i, state, &native, text,
272.1040 + sizeof(text), &len );
272.1041 + if (SQL_SUCCEEDED(ret))
272.1042 + xprintf("%s:%ld:%ld:%s\n", state, i, native, text);
272.1043 + }
272.1044 + while( ret == SQL_SUCCESS );
272.1045 +}
272.1046 +
272.1047 +static int is_numeric(SQLSMALLINT coltype)
272.1048 +{
272.1049 + int ret = 0;
272.1050 + switch (coltype)
272.1051 + {
272.1052 + case SQL_DECIMAL:
272.1053 + case SQL_NUMERIC:
272.1054 + case SQL_SMALLINT:
272.1055 + case SQL_INTEGER:
272.1056 + case SQL_REAL:
272.1057 + case SQL_FLOAT:
272.1058 + case SQL_DOUBLE:
272.1059 + case SQL_TINYINT:
272.1060 + case SQL_BIGINT:
272.1061 + ret = 1;
272.1062 + break;
272.1063 + }
272.1064 + return ret;
272.1065 +}
272.1066 +
272.1067 +#endif
272.1068 +
272.1069 +/**********************************************************************/
272.1070 +
272.1071 +#ifndef HAVE_MYSQL
272.1072 +
272.1073 +void *db_mysql_open(TABDCA *dca, int mode)
272.1074 +{ xassert(dca == dca);
272.1075 + xassert(mode == mode);
272.1076 + xprintf("MySQL table driver not supported\n");
272.1077 + return NULL;
272.1078 +}
272.1079 +
272.1080 +int db_mysql_read(TABDCA *dca, void *link)
272.1081 +{ xassert(dca != dca);
272.1082 + xassert(link != link);
272.1083 + return 0;
272.1084 +}
272.1085 +
272.1086 +int db_mysql_write(TABDCA *dca, void *link)
272.1087 +{ xassert(dca != dca);
272.1088 + xassert(link != link);
272.1089 + return 0;
272.1090 +}
272.1091 +
272.1092 +int db_mysql_close(TABDCA *dca, void *link)
272.1093 +{ xassert(dca != dca);
272.1094 + xassert(link != link);
272.1095 + return 0;
272.1096 +}
272.1097 +
272.1098 +#else
272.1099 +
272.1100 +#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WOE__)
272.1101 +#include <windows.h>
272.1102 +#endif
272.1103 +
272.1104 +#ifdef __CYGWIN__
272.1105 +#define byte_defined 1
272.1106 +#endif
272.1107 +
272.1108 +#include <my_global.h>
272.1109 +#include <my_sys.h>
272.1110 +#include <mysql.h>
272.1111 +
272.1112 +struct db_mysql
272.1113 +{
272.1114 + int mode; /*'R' = Read, 'W' = Write*/
272.1115 + MYSQL *con; /*connection*/
272.1116 + MYSQL_RES *res; /*result*/
272.1117 + int nf;
272.1118 + /* number of fields in the csv file */
272.1119 + int ref[1+SQL_FIELD_MAX];
272.1120 + /* ref[k] = k', if k-th field of the csv file corresponds to
272.1121 + k'-th field in the table statement; if ref[k] = 0, k-th field
272.1122 + of the csv file is ignored */
272.1123 + char *query;
272.1124 + /* query generated by db_mysql_open */
272.1125 +};
272.1126 +
272.1127 +void STDCALL dl_mysql_close(MYSQL *sock)
272.1128 +{
272.1129 + typedef void STDCALL ep_mysql_close(MYSQL *sock);
272.1130 +
272.1131 + ep_mysql_close *fn;
272.1132 + fn = (ep_mysql_close *) xdlsym(h_mysql, "mysql_close");
272.1133 + xassert(fn != NULL);
272.1134 + return (*fn)(sock);
272.1135 +}
272.1136 +
272.1137 +const char * STDCALL dl_mysql_error(MYSQL *mysql)
272.1138 +{
272.1139 + typedef const char * STDCALL ep_mysql_error(MYSQL *mysql);
272.1140 +
272.1141 + ep_mysql_error *fn;
272.1142 + fn = (ep_mysql_error *) xdlsym(h_mysql, "mysql_error");
272.1143 + xassert(fn != NULL);
272.1144 + return (*fn)(mysql);
272.1145 +}
272.1146 +
272.1147 +MYSQL_FIELD * STDCALL dl_mysql_fetch_fields(MYSQL_RES *res)
272.1148 +{
272.1149 + typedef MYSQL_FIELD * STDCALL
272.1150 + ep_mysql_fetch_fields(MYSQL_RES *res);
272.1151 +
272.1152 + ep_mysql_fetch_fields *fn;
272.1153 + fn = (ep_mysql_fetch_fields *) xdlsym(h_mysql, "mysql_fetch_fields");
272.1154 + xassert(fn != NULL);
272.1155 + return (*fn)(res);
272.1156 +}
272.1157 +
272.1158 +unsigned long * STDCALL dl_mysql_fetch_lengths(MYSQL_RES *result)
272.1159 +{
272.1160 + typedef unsigned long * STDCALL
272.1161 + ep_mysql_fetch_lengths(MYSQL_RES *result);
272.1162 +
272.1163 + ep_mysql_fetch_lengths *fn;
272.1164 + fn = (ep_mysql_fetch_lengths *) xdlsym(h_mysql,
272.1165 + "mysql_fetch_lengths");
272.1166 + xassert(fn != NULL);
272.1167 + return (*fn)(result);
272.1168 +}
272.1169 +
272.1170 +MYSQL_ROW STDCALL dl_mysql_fetch_row(MYSQL_RES *result)
272.1171 +{
272.1172 + typedef MYSQL_ROW STDCALL ep_mysql_fetch_row(MYSQL_RES *result);
272.1173 +
272.1174 + ep_mysql_fetch_row *fn;
272.1175 + fn = (ep_mysql_fetch_row *) xdlsym(h_mysql, "mysql_fetch_row");
272.1176 + xassert(fn != NULL);
272.1177 + return (*fn)(result);
272.1178 +}
272.1179 +
272.1180 +unsigned int STDCALL dl_mysql_field_count(MYSQL *mysql)
272.1181 +{
272.1182 + typedef unsigned int STDCALL ep_mysql_field_count(MYSQL *mysql);
272.1183 +
272.1184 + ep_mysql_field_count *fn;
272.1185 + fn = (ep_mysql_field_count *) xdlsym(h_mysql, "mysql_field_count");
272.1186 + xassert(fn != NULL);
272.1187 + return (*fn)(mysql);
272.1188 +}
272.1189 +
272.1190 +MYSQL * STDCALL dl_mysql_init(MYSQL *mysql)
272.1191 +{
272.1192 + typedef MYSQL * STDCALL ep_mysql_init(MYSQL *mysql);
272.1193 +
272.1194 + ep_mysql_init *fn;
272.1195 + fn = (ep_mysql_init *) xdlsym(h_mysql, "mysql_init");
272.1196 + xassert(fn != NULL);
272.1197 + return (*fn)(mysql);
272.1198 +}
272.1199 +
272.1200 +unsigned int STDCALL dl_mysql_num_fields(MYSQL_RES *res)
272.1201 +{
272.1202 + typedef unsigned int STDCALL ep_mysql_num_fields(MYSQL_RES *res);
272.1203 +
272.1204 + ep_mysql_num_fields *fn;
272.1205 + fn = (ep_mysql_num_fields *) xdlsym(h_mysql, "mysql_num_fields");
272.1206 + xassert(fn != NULL);
272.1207 + return (*fn)(res);
272.1208 +}
272.1209 +
272.1210 +int STDCALL dl_mysql_query(MYSQL *mysql, const char *q)
272.1211 +{
272.1212 + typedef int STDCALL ep_mysql_query(MYSQL *mysql, const char *q);
272.1213 +
272.1214 + ep_mysql_query *fn;
272.1215 + fn = (ep_mysql_query *) xdlsym(h_mysql, "mysql_query");
272.1216 + xassert(fn != NULL);
272.1217 + return (*fn)(mysql, q);
272.1218 +}
272.1219 +
272.1220 +MYSQL * STDCALL dl_mysql_real_connect(MYSQL *mysql, const char *host,
272.1221 + const char *user,
272.1222 + const char *passwd,
272.1223 + const char *db,
272.1224 + unsigned int port,
272.1225 + const char *unix_socket,
272.1226 + unsigned long clientflag)
272.1227 +{
272.1228 + typedef MYSQL * STDCALL ep_mysql_real_connect(MYSQL *mysql,
272.1229 + const char *host,
272.1230 + const char *user,
272.1231 + const char *passwd,
272.1232 + const char *db,
272.1233 + unsigned int port,
272.1234 + const char *unix_socket,
272.1235 + unsigned long clientflag);
272.1236 +
272.1237 + ep_mysql_real_connect *fn;
272.1238 + fn = (ep_mysql_real_connect *) xdlsym(h_mysql,
272.1239 + "mysql_real_connect");
272.1240 + xassert(fn != NULL);
272.1241 + return (*fn)(mysql, host, user, passwd, db, port, unix_socket,
272.1242 + clientflag);
272.1243 +}
272.1244 +
272.1245 +MYSQL_RES * STDCALL dl_mysql_use_result(MYSQL *mysql)
272.1246 +{
272.1247 + typedef MYSQL_RES * STDCALL ep_mysql_use_result(MYSQL *mysql);
272.1248 + ep_mysql_use_result *fn;
272.1249 + fn = (ep_mysql_use_result *) xdlsym(h_mysql, "mysql_use_result");
272.1250 + xassert(fn != NULL);
272.1251 + return (*fn)(mysql);
272.1252 +}
272.1253 +
272.1254 +/***********************************************************************
272.1255 +* NAME
272.1256 +*
272.1257 +* db_mysql_open - open connection to ODBC data base
272.1258 +*
272.1259 +* SYNOPSIS
272.1260 +*
272.1261 +* #include "glpsql.h"
272.1262 +* void *db_mysql_open(TABDCA *dca, int mode);
272.1263 +*
272.1264 +* DESCRIPTION
272.1265 +*
272.1266 +* The routine db_mysql_open opens a connection to a MySQL data base.
272.1267 +* It then executes the sql statements passed.
272.1268 +*
272.1269 +* In the case of table read the SELECT statement is executed.
272.1270 +*
272.1271 +* In the case of table write the INSERT statement is prepared.
272.1272 +* RETURNS
272.1273 +*
272.1274 +* The routine returns a pointer to data storage area created. */
272.1275 +
272.1276 +void *db_mysql_open(TABDCA *dca, int mode)
272.1277 +{ void *ret;
272.1278 + char **sqllines;
272.1279 +
272.1280 + sqllines = args_concat(dca);
272.1281 + if (sqllines == NULL)
272.1282 + { xprintf("Missing arguments in table statement.\n"
272.1283 + "Please, supply table driver, dsn, and query.\n");
272.1284 + return NULL;
272.1285 + }
272.1286 + ret = db_mysql_open_int(dca, mode, (const char **) sqllines);
272.1287 + free_buffer(sqllines);
272.1288 + return ret;
272.1289 +}
272.1290 +
272.1291 +static void *db_mysql_open_int(TABDCA *dca, int mode, const char
272.1292 + **sqllines)
272.1293 +{
272.1294 + struct db_mysql *sql = NULL;
272.1295 + char *arg = NULL;
272.1296 + const char *field;
272.1297 + MYSQL_FIELD *fields;
272.1298 + char *keyword;
272.1299 + char *value;
272.1300 + char *query;
272.1301 + char *dsn;
272.1302 +/* "Server=[server_name];Database=[database_name];UID=[username];*/
272.1303 +/* PWD=[password];Port=[port]"*/
272.1304 + char *server = NULL; /* Server */
272.1305 + char *user = NULL; /* UID */
272.1306 + char *password = NULL; /* PWD */
272.1307 + char *database = NULL; /* Database */
272.1308 + unsigned int port = 0; /* Port */
272.1309 + int narg;
272.1310 + int i, j, total;
272.1311 +
272.1312 + if (libmysql == NULL)
272.1313 + {
272.1314 + xprintf("No loader for shared MySQL library available\n");
272.1315 + return NULL;
272.1316 + }
272.1317 +
272.1318 + if (h_mysql == NULL)
272.1319 + {
272.1320 + h_mysql = xdlopen(libmysql);
272.1321 + if (h_mysql == NULL)
272.1322 + { xprintf("unable to open library %s\n", libmysql);
272.1323 + xprintf("%s\n", xerrmsg());
272.1324 + return NULL;
272.1325 + }
272.1326 + }
272.1327 +
272.1328 + sql = (struct db_mysql *) xmalloc(sizeof(struct db_mysql));
272.1329 + if (sql == NULL)
272.1330 + return NULL;
272.1331 + sql->mode = mode;
272.1332 + sql->res = NULL;
272.1333 + sql->query = NULL;
272.1334 + sql->nf = mpl_tab_num_flds(dca);
272.1335 +
272.1336 + narg = mpl_tab_num_args(dca);
272.1337 + if (narg < 3 )
272.1338 + xprintf("MySQL driver: string list too short \n");
272.1339 +
272.1340 + /* get connection string*/
272.1341 + dsn = (char *) mpl_tab_get_arg(dca, 2);
272.1342 + /* copy connection string*/
272.1343 + i = strlen(dsn);
272.1344 + i++;
272.1345 + arg = xmalloc(i * sizeof(char));
272.1346 + strcpy(arg, dsn);
272.1347 + /*tokenize connection string*/
272.1348 + for (i = 1, keyword = strtok (arg, "="); (keyword != NULL);
272.1349 + keyword = strtok (NULL, "="), i++)
272.1350 + {
272.1351 + value = strtok (NULL, ";");
272.1352 + if (value==NULL)
272.1353 + {
272.1354 + xprintf("db_mysql_open: Missing value for keyword %s\n",
272.1355 + keyword);
272.1356 + xfree(arg);
272.1357 + xfree(sql);
272.1358 + return NULL;
272.1359 + }
272.1360 + if (0 == strcmp(keyword, "Server"))
272.1361 + server = value;
272.1362 + else if (0 == strcmp(keyword, "Database"))
272.1363 + database = value;
272.1364 + else if (0 == strcmp(keyword, "UID"))
272.1365 + user = value;
272.1366 + else if (0 == strcmp(keyword, "PWD"))
272.1367 + password = value;
272.1368 + else if (0 == strcmp(keyword, "Port"))
272.1369 + port = (unsigned int) atol(value);
272.1370 + }
272.1371 + /* Connect to database */
272.1372 + sql->con = dl_mysql_init(NULL);
272.1373 + if (!dl_mysql_real_connect(sql->con, server, user, password, database,
272.1374 + port, NULL, 0))
272.1375 + {
272.1376 + xprintf("db_mysql_open: Connect failed\n");
272.1377 + xprintf("%s\n", dl_mysql_error(sql->con));
272.1378 + xfree(arg);
272.1379 + xfree(sql);
272.1380 + return NULL;
272.1381 + }
272.1382 + xfree(arg);
272.1383 +
272.1384 + for(j = 0; sqllines[j+1] != NULL; j++)
272.1385 + { query = (char *) sqllines[j];
272.1386 + xprintf("%s\n", query);
272.1387 + if (dl_mysql_query(sql->con, query))
272.1388 + {
272.1389 + xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query);
272.1390 + xprintf("%s\n",dl_mysql_error(sql->con));
272.1391 + dl_mysql_close(sql->con);
272.1392 + xfree(sql);
272.1393 + return NULL;
272.1394 + }
272.1395 + }
272.1396 +
272.1397 + if ( sql->mode == 'R' )
272.1398 + { sql->nf = mpl_tab_num_flds(dca);
272.1399 + for(j = 0; sqllines[j] != NULL; j++)
272.1400 + arg = (char *) sqllines[j];
272.1401 + total = strlen(arg);
272.1402 + if (total > 7 && 0 == strncmp(arg, "SELECT ", 7))
272.1403 + {
272.1404 + total = strlen(arg);
272.1405 + query = xmalloc( (total+1) * sizeof(char));
272.1406 + strcpy (query, arg);
272.1407 + }
272.1408 + else
272.1409 + {
272.1410 + query = db_generate_select_stmt(dca);
272.1411 + }
272.1412 + xprintf("%s\n", query);
272.1413 + if (dl_mysql_query(sql->con, query))
272.1414 + {
272.1415 + xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query);
272.1416 + xprintf("%s\n",dl_mysql_error(sql->con));
272.1417 + dl_mysql_close(sql->con);
272.1418 + xfree(query);
272.1419 + xfree(sql);
272.1420 + return NULL;
272.1421 + }
272.1422 + xfree(query);
272.1423 + sql->res = dl_mysql_use_result(sql->con);
272.1424 + if (sql->res)
272.1425 + {
272.1426 + /* create references between query results and table fields*/
272.1427 + total = dl_mysql_num_fields(sql->res);
272.1428 + if (total > SQL_FIELD_MAX)
272.1429 + { xprintf("db_mysql_open: Too many fields (> %d) in query.\n"
272.1430 + "\"%s\"\n", SQL_FIELD_MAX, query);
272.1431 + xprintf("%s\n",dl_mysql_error(sql->con));
272.1432 + dl_mysql_close(sql->con);
272.1433 + xfree(query);
272.1434 + xfree(sql);
272.1435 + return NULL;
272.1436 + }
272.1437 + fields = dl_mysql_fetch_fields(sql->res);
272.1438 + for (i = 1; i <= total; i++)
272.1439 + {
272.1440 + for (j = sql->nf; j >= 1; j--)
272.1441 + {
272.1442 + if (strcmp(mpl_tab_get_name(dca, j), fields[i-1].name)
272.1443 + == 0)
272.1444 + break;
272.1445 + }
272.1446 + sql->ref[i] = j;
272.1447 + }
272.1448 + }
272.1449 + else
272.1450 + {
272.1451 + if(dl_mysql_field_count(sql->con) == 0)
272.1452 + {
272.1453 + xprintf("db_mysql_open: Query was not a SELECT\n\"%s\"\n",
272.1454 + query);
272.1455 + xprintf("%s\n",dl_mysql_error(sql->con));
272.1456 + xfree(query);
272.1457 + xfree(sql);
272.1458 + return NULL;
272.1459 + }
272.1460 + else
272.1461 + {
272.1462 + xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query);
272.1463 + xprintf("%s\n",dl_mysql_error(sql->con));
272.1464 + xfree(query);
272.1465 + xfree(sql);
272.1466 + return NULL;
272.1467 + }
272.1468 + }
272.1469 + }
272.1470 + else if ( sql->mode == 'W' )
272.1471 + { for(j = 0; sqllines[j] != NULL; j++)
272.1472 + arg = (char *) sqllines[j];
272.1473 + if ( NULL != strchr(arg, '?') )
272.1474 + {
272.1475 + total = strlen(arg);
272.1476 + query = xmalloc( (total+1) * sizeof(char));
272.1477 + strcpy (query, arg);
272.1478 + }
272.1479 + else
272.1480 + query = db_generate_insert_stmt(dca);
272.1481 + sql->query = query;
272.1482 + xprintf("%s\n", query);
272.1483 + }
272.1484 + return sql;
272.1485 +}
272.1486 +
272.1487 +int db_mysql_read(TABDCA *dca, void *link)
272.1488 +{ struct db_mysql *sql;
272.1489 + char buf[255+1];
272.1490 + char **row;
272.1491 + unsigned long *lengths;
272.1492 + MYSQL_FIELD *fields;
272.1493 + double num;
272.1494 + int len;
272.1495 + unsigned long num_fields;
272.1496 + int i;
272.1497 +
272.1498 + sql = (struct db_mysql *) link;
272.1499 +
272.1500 + xassert(sql != NULL);
272.1501 + xassert(sql->mode == 'R');
272.1502 + if (NULL == sql->res)
272.1503 + {
272.1504 + xprintf("db_mysql_read: no result set available");
272.1505 + return 1;
272.1506 + }
272.1507 + if (NULL==(row = (char **)dl_mysql_fetch_row(sql->res))) {
272.1508 + return -1; /*EOF*/
272.1509 + }
272.1510 + lengths = dl_mysql_fetch_lengths(sql->res);
272.1511 + fields = dl_mysql_fetch_fields(sql->res);
272.1512 + num_fields = dl_mysql_num_fields(sql->res);
272.1513 + for (i=1; i <= num_fields; i++)
272.1514 + {
272.1515 + if (row[i-1] != NULL)
272.1516 + { len = (size_t) lengths[i-1];
272.1517 + if (len > 255)
272.1518 + len = 255;
272.1519 + strncpy(buf, (const char *) row[i-1], len);
272.1520 + buf[len] = 0x00;
272.1521 + if (0 != (fields[i-1].flags & NUM_FLAG))
272.1522 + { strspx(buf); /* remove spaces*/
272.1523 + if (str2num(buf, &num) != 0)
272.1524 + { xprintf("'%s' cannot be converted to a number.\n", buf);
272.1525 + return 1;
272.1526 + }
272.1527 + if (sql->ref[i] > 0)
272.1528 + mpl_tab_set_num(dca, sql->ref[i], num);
272.1529 + }
272.1530 + else
272.1531 + { if (sql->ref[i] > 0)
272.1532 + mpl_tab_set_str(dca, sql->ref[i], strtrim(buf));
272.1533 + }
272.1534 + }
272.1535 + }
272.1536 + return 0;
272.1537 +}
272.1538 +
272.1539 +int db_mysql_write(TABDCA *dca, void *link)
272.1540 +{
272.1541 + struct db_mysql *sql;
272.1542 + char *part;
272.1543 + char *query;
272.1544 + char *template;
272.1545 + char num[50];
272.1546 + int k;
272.1547 + int len;
272.1548 + int nf;
272.1549 +
272.1550 + sql = (struct db_mysql *) link;
272.1551 + xassert(sql != NULL);
272.1552 + xassert(sql->mode == 'W');
272.1553 +
272.1554 + len = strlen(sql->query);
272.1555 + template = (char *) xmalloc( (len + 1) * sizeof(char) );
272.1556 + strcpy(template, sql->query);
272.1557 +
272.1558 + nf = mpl_tab_num_flds(dca);
272.1559 + for (k = 1; k <= nf; k++)
272.1560 + { switch (mpl_tab_get_type(dca, k))
272.1561 + { case 'N':
272.1562 + len += 20;
272.1563 + break;
272.1564 + case 'S':
272.1565 + len += db_escaped_string_length(mpl_tab_get_str(dca, k));
272.1566 + len += 2;
272.1567 + break;
272.1568 + default:
272.1569 + xassert(dca != dca);
272.1570 + }
272.1571 + }
272.1572 + query = xmalloc( (len + 1 ) * sizeof(char) );
272.1573 + query[0] = 0x00;
272.1574 + for (k = 1, part = strtok (template, "?"); (part != NULL);
272.1575 + part = strtok (NULL, "?"), k++)
272.1576 + {
272.1577 + if (k > nf) break;
272.1578 + strcat( query, part );
272.1579 + switch (mpl_tab_get_type(dca, k))
272.1580 + { case 'N':
272.1581 +#if 0 /* 02/XI-2010 by xypron */
272.1582 + sprintf(num, "%-18g",mpl_tab_get_num(dca, k));
272.1583 +#else
272.1584 + sprintf(num, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k));
272.1585 +#endif
272.1586 + strcat( query, num );
272.1587 + break;
272.1588 + case 'S':
272.1589 + strcat( query, "'");
272.1590 + db_escape_string( query + strlen(query),
272.1591 + mpl_tab_get_str(dca, k) );
272.1592 + strcat( query, "'");
272.1593 + break;
272.1594 + default:
272.1595 + xassert(dca != dca);
272.1596 + }
272.1597 + }
272.1598 + if (part != NULL)
272.1599 + strcat(query, part);
272.1600 + if (dl_mysql_query(sql->con, query))
272.1601 + {
272.1602 + xprintf("db_mysql_write: Query\n\"%s\"\nfailed.\n", query);
272.1603 + xprintf("%s\n",dl_mysql_error(sql->con));
272.1604 + xfree(query);
272.1605 + xfree(template);
272.1606 + return 1;
272.1607 + }
272.1608 +
272.1609 + xfree(query);
272.1610 + xfree(template);
272.1611 + return 0;
272.1612 + }
272.1613 +
272.1614 +int db_mysql_close(TABDCA *dca, void *link)
272.1615 +{
272.1616 + struct db_mysql *sql;
272.1617 +
272.1618 + sql = (struct db_mysql *) link;
272.1619 + xassert(sql != NULL);
272.1620 + dl_mysql_close(sql->con);
272.1621 + if ( sql->mode == 'W' )
272.1622 + xfree(sql->query);
272.1623 + xfree(sql);
272.1624 + dca->link = NULL;
272.1625 + return 0;
272.1626 +}
272.1627 +
272.1628 +#endif
272.1629 +
272.1630 +/* eof */
273.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
273.2 +++ b/src/glpsql.h Mon Dec 06 13:09:21 2010 +0100
273.3 @@ -0,0 +1,64 @@
273.4 +/* glpsql.h */
273.5 +
273.6 +/***********************************************************************
273.7 +* This code is part of GLPK (GNU Linear Programming Kit).
273.8 +*
273.9 +* Author: Heinrich Schuchardt <heinrich.schuchardt@gmx.de>.
273.10 +*
273.11 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
273.12 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
273.13 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
273.14 +* E-mail: <mao@gnu.org>.
273.15 +*
273.16 +* GLPK is free software: you can redistribute it and/or modify it
273.17 +* under the terms of the GNU General Public License as published by
273.18 +* the Free Software Foundation, either version 3 of the License, or
273.19 +* (at your option) any later version.
273.20 +*
273.21 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
273.22 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
273.23 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
273.24 +* License for more details.
273.25 +*
273.26 +* You should have received a copy of the GNU General Public License
273.27 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
273.28 +***********************************************************************/
273.29 +
273.30 +#ifndef GLPSQL_H
273.31 +#define GLPSQL_H
273.32 +
273.33 +#define db_iodbc_open _glp_db_iodbc_open
273.34 +void *db_iodbc_open(TABDCA *dca, int mode);
273.35 +/* open iODBC database connection */
273.36 +
273.37 +#define db_iodbc_read _glp_db_iodbc_read
273.38 +int db_iodbc_read(TABDCA *dca, void *link);
273.39 +/* read data from iODBC */
273.40 +
273.41 +#define db_iodbc_write _glp_db_iodbc_write
273.42 +int db_iodbc_write(TABDCA *dca, void *link);
273.43 +/* write data to iODBC */
273.44 +
273.45 +#define db_iodbc_close _glp_db_iodbc_close
273.46 +int db_iodbc_close(TABDCA *dca, void *link);
273.47 +/* close iODBC database connection */
273.48 +
273.49 +#define db_mysql_open _glp_db_mysql_open
273.50 +void *db_mysql_open(TABDCA *dca, int mode);
273.51 +/* open MySQL database connection */
273.52 +
273.53 +#define db_mysql_read _glp_db_mysql_read
273.54 +int db_mysql_read(TABDCA *dca, void *link);
273.55 +/* read data from MySQL */
273.56 +
273.57 +#define db_mysql_write _glp_db_mysql_write
273.58 +int db_mysql_write(TABDCA *dca, void *link);
273.59 +/* write data to MySQL */
273.60 +
273.61 +#define db_mysql_close _glp_db_mysql_close
273.62 +int db_mysql_close(TABDCA *dca, void *link);
273.63 +/* close MySQL database connection */
273.64 +
273.65 +#endif
273.66 +
273.67 +/* eof */
274.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
274.2 +++ b/src/glpssx.h Mon Dec 06 13:09:21 2010 +0100
274.3 @@ -0,0 +1,418 @@
274.4 +/* glpssx.h (simplex method, bignum arithmetic) */
274.5 +
274.6 +/***********************************************************************
274.7 +* This code is part of GLPK (GNU Linear Programming Kit).
274.8 +*
274.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
274.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
274.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
274.12 +* E-mail: <mao@gnu.org>.
274.13 +*
274.14 +* GLPK is free software: you can redistribute it and/or modify it
274.15 +* under the terms of the GNU General Public License as published by
274.16 +* the Free Software Foundation, either version 3 of the License, or
274.17 +* (at your option) any later version.
274.18 +*
274.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
274.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
274.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
274.22 +* License for more details.
274.23 +*
274.24 +* You should have received a copy of the GNU General Public License
274.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
274.26 +***********************************************************************/
274.27 +
274.28 +#ifndef GLPSSX_H
274.29 +#define GLPSSX_H
274.30 +
274.31 +#include "glpbfx.h"
274.32 +#include "glpenv.h"
274.33 +
274.34 +typedef struct SSX SSX;
274.35 +
274.36 +struct SSX
274.37 +{ /* simplex solver workspace */
274.38 +/*----------------------------------------------------------------------
274.39 +// LP PROBLEM DATA
274.40 +//
274.41 +// It is assumed that LP problem has the following statement:
274.42 +//
274.43 +// minimize (or maximize)
274.44 +//
274.45 +// z = c[1]*x[1] + ... + c[m+n]*x[m+n] + c[0] (1)
274.46 +//
274.47 +// subject to equality constraints
274.48 +//
274.49 +// x[1] - a[1,1]*x[m+1] - ... - a[1,n]*x[m+n] = 0
274.50 +//
274.51 +// . . . . . . . (2)
274.52 +//
274.53 +// x[m] - a[m,1]*x[m+1] + ... - a[m,n]*x[m+n] = 0
274.54 +//
274.55 +// and bounds of variables
274.56 +//
274.57 +// l[1] <= x[1] <= u[1]
274.58 +//
274.59 +// . . . . . . . (3)
274.60 +//
274.61 +// l[m+n] <= x[m+n] <= u[m+n]
274.62 +//
274.63 +// where:
274.64 +// x[1], ..., x[m] - auxiliary variables;
274.65 +// x[m+1], ..., x[m+n] - structural variables;
274.66 +// z - objective function;
274.67 +// c[1], ..., c[m+n] - coefficients of the objective function;
274.68 +// c[0] - constant term of the objective function;
274.69 +// a[1,1], ..., a[m,n] - constraint coefficients;
274.70 +// l[1], ..., l[m+n] - lower bounds of variables;
274.71 +// u[1], ..., u[m+n] - upper bounds of variables.
274.72 +//
274.73 +// Bounds of variables can be finite as well as inifinite. Besides,
274.74 +// lower and upper bounds can be equal to each other. So the following
274.75 +// five types of variables are possible:
274.76 +//
274.77 +// Bounds of variable Type of variable
274.78 +// -------------------------------------------------
274.79 +// -inf < x[k] < +inf Free (unbounded) variable
274.80 +// l[k] <= x[k] < +inf Variable with lower bound
274.81 +// -inf < x[k] <= u[k] Variable with upper bound
274.82 +// l[k] <= x[k] <= u[k] Double-bounded variable
274.83 +// l[k] = x[k] = u[k] Fixed variable
274.84 +//
274.85 +// Using vector-matrix notations the LP problem (1)-(3) can be written
274.86 +// as follows:
274.87 +//
274.88 +// minimize (or maximize)
274.89 +//
274.90 +// z = c * x + c[0] (4)
274.91 +//
274.92 +// subject to equality constraints
274.93 +//
274.94 +// xR - A * xS = 0 (5)
274.95 +//
274.96 +// and bounds of variables
274.97 +//
274.98 +// l <= x <= u (6)
274.99 +//
274.100 +// where:
274.101 +// xR - vector of auxiliary variables;
274.102 +// xS - vector of structural variables;
274.103 +// x = (xR, xS) - vector of all variables;
274.104 +// z - objective function;
274.105 +// c - vector of objective coefficients;
274.106 +// c[0] - constant term of the objective function;
274.107 +// A - matrix of constraint coefficients (has m rows
274.108 +// and n columns);
274.109 +// l - vector of lower bounds of variables;
274.110 +// u - vector of upper bounds of variables.
274.111 +//
274.112 +// The simplex method makes no difference between auxiliary and
274.113 +// structural variables, so it is convenient to think the system of
274.114 +// equality constraints (5) written in a homogeneous form:
274.115 +//
274.116 +// (I | -A) * x = 0, (7)
274.117 +//
274.118 +// where (I | -A) is an augmented (m+n)xm constraint matrix, I is mxm
274.119 +// unity matrix whose columns correspond to auxiliary variables, and A
274.120 +// is the original mxn constraint matrix whose columns correspond to
274.121 +// structural variables. Note that only the matrix A is stored.
274.122 +----------------------------------------------------------------------*/
274.123 + int m;
274.124 + /* number of rows (auxiliary variables), m > 0 */
274.125 + int n;
274.126 + /* number of columns (structural variables), n > 0 */
274.127 + int *type; /* int type[1+m+n]; */
274.128 + /* type[0] is not used;
274.129 + type[k], 1 <= k <= m+n, is the type of variable x[k]: */
274.130 +#define SSX_FR 0 /* free (unbounded) variable */
274.131 +#define SSX_LO 1 /* variable with lower bound */
274.132 +#define SSX_UP 2 /* variable with upper bound */
274.133 +#define SSX_DB 3 /* double-bounded variable */
274.134 +#define SSX_FX 4 /* fixed variable */
274.135 + mpq_t *lb; /* mpq_t lb[1+m+n]; alias: l */
274.136 + /* lb[0] is not used;
274.137 + lb[k], 1 <= k <= m+n, is an lower bound of variable x[k];
274.138 + if x[k] has no lower bound, lb[k] is zero */
274.139 + mpq_t *ub; /* mpq_t ub[1+m+n]; alias: u */
274.140 + /* ub[0] is not used;
274.141 + ub[k], 1 <= k <= m+n, is an upper bound of variable x[k];
274.142 + if x[k] has no upper bound, ub[k] is zero;
274.143 + if x[k] is of fixed type, ub[k] is equal to lb[k] */
274.144 + int dir;
274.145 + /* optimization direction (sense of the objective function): */
274.146 +#define SSX_MIN 0 /* minimization */
274.147 +#define SSX_MAX 1 /* maximization */
274.148 + mpq_t *coef; /* mpq_t coef[1+m+n]; alias: c */
274.149 + /* coef[0] is a constant term of the objective function;
274.150 + coef[k], 1 <= k <= m+n, is a coefficient of the objective
274.151 + function at variable x[k];
274.152 + note that auxiliary variables also may have non-zero objective
274.153 + coefficients */
274.154 + int *A_ptr; /* int A_ptr[1+n+1]; */
274.155 + int *A_ind; /* int A_ind[A_ptr[n+1]]; */
274.156 + mpq_t *A_val; /* mpq_t A_val[A_ptr[n+1]]; */
274.157 + /* constraint matrix A (see (5)) in storage-by-columns format */
274.158 +/*----------------------------------------------------------------------
274.159 +// LP BASIS AND CURRENT BASIC SOLUTION
274.160 +//
274.161 +// The LP basis is defined by the following partition of the augmented
274.162 +// constraint matrix (7):
274.163 +//
274.164 +// (B | N) = (I | -A) * Q, (8)
274.165 +//
274.166 +// where B is a mxm non-singular basis matrix whose columns correspond
274.167 +// to basic variables xB, N is a mxn matrix whose columns correspond to
274.168 +// non-basic variables xN, and Q is a permutation (m+n)x(m+n) matrix.
274.169 +//
274.170 +// From (7) and (8) it follows that
274.171 +//
274.172 +// (I | -A) * x = (I | -A) * Q * Q' * x = (B | N) * (xB, xN),
274.173 +//
274.174 +// therefore
274.175 +//
274.176 +// (xB, xN) = Q' * x, (9)
274.177 +//
274.178 +// where x is the vector of all variables in the original order, xB is
274.179 +// a vector of basic variables, xN is a vector of non-basic variables,
274.180 +// Q' = inv(Q) is a matrix transposed to Q.
274.181 +//
274.182 +// Current values of non-basic variables xN[j], j = 1, ..., n, are not
274.183 +// stored; they are defined implicitly by their statuses as follows:
274.184 +//
274.185 +// 0, if xN[j] is free variable
274.186 +// lN[j], if xN[j] is on its lower bound (10)
274.187 +// uN[j], if xN[j] is on its upper bound
274.188 +// lN[j] = uN[j], if xN[j] is fixed variable
274.189 +//
274.190 +// where lN[j] and uN[j] are lower and upper bounds of xN[j].
274.191 +//
274.192 +// Current values of basic variables xB[i], i = 1, ..., m, are computed
274.193 +// as follows:
274.194 +//
274.195 +// beta = - inv(B) * N * xN, (11)
274.196 +//
274.197 +// where current values of xN are defined by (10).
274.198 +//
274.199 +// Current values of simplex multipliers pi[i], i = 1, ..., m (which
274.200 +// are values of Lagrange multipliers for equality constraints (7) also
274.201 +// called shadow prices) are computed as follows:
274.202 +//
274.203 +// pi = inv(B') * cB, (12)
274.204 +//
274.205 +// where B' is a matrix transposed to B, cB is a vector of objective
274.206 +// coefficients at basic variables xB.
274.207 +//
274.208 +// Current values of reduced costs d[j], j = 1, ..., n, (which are
274.209 +// values of Langrange multipliers for active inequality constraints
274.210 +// corresponding to non-basic variables) are computed as follows:
274.211 +//
274.212 +// d = cN - N' * pi, (13)
274.213 +//
274.214 +// where N' is a matrix transposed to N, cN is a vector of objective
274.215 +// coefficients at non-basic variables xN.
274.216 +----------------------------------------------------------------------*/
274.217 + int *stat; /* int stat[1+m+n]; */
274.218 + /* stat[0] is not used;
274.219 + stat[k], 1 <= k <= m+n, is the status of variable x[k]: */
274.220 +#define SSX_BS 0 /* basic variable */
274.221 +#define SSX_NL 1 /* non-basic variable on lower bound */
274.222 +#define SSX_NU 2 /* non-basic variable on upper bound */
274.223 +#define SSX_NF 3 /* non-basic free variable */
274.224 +#define SSX_NS 4 /* non-basic fixed variable */
274.225 + int *Q_row; /* int Q_row[1+m+n]; */
274.226 + /* matrix Q in row-like format;
274.227 + Q_row[0] is not used;
274.228 + Q_row[i] = j means that q[i,j] = 1 */
274.229 + int *Q_col; /* int Q_col[1+m+n]; */
274.230 + /* matrix Q in column-like format;
274.231 + Q_col[0] is not used;
274.232 + Q_col[j] = i means that q[i,j] = 1 */
274.233 + /* if k-th column of the matrix (I | A) is k'-th column of the
274.234 + matrix (B | N), then Q_row[k] = k' and Q_col[k'] = k;
274.235 + if x[k] is xB[i], then Q_row[k] = i and Q_col[i] = k;
274.236 + if x[k] is xN[j], then Q_row[k] = m+j and Q_col[m+j] = k */
274.237 + BFX *binv;
274.238 + /* invertable form of the basis matrix B */
274.239 + mpq_t *bbar; /* mpq_t bbar[1+m]; alias: beta */
274.240 + /* bbar[0] is a value of the objective function;
274.241 + bbar[i], 1 <= i <= m, is a value of basic variable xB[i] */
274.242 + mpq_t *pi; /* mpq_t pi[1+m]; */
274.243 + /* pi[0] is not used;
274.244 + pi[i], 1 <= i <= m, is a simplex multiplier corresponding to
274.245 + i-th row (equality constraint) */
274.246 + mpq_t *cbar; /* mpq_t cbar[1+n]; alias: d */
274.247 + /* cbar[0] is not used;
274.248 + cbar[j], 1 <= j <= n, is a reduced cost of non-basic variable
274.249 + xN[j] */
274.250 +/*----------------------------------------------------------------------
274.251 +// SIMPLEX TABLE
274.252 +//
274.253 +// Due to (8) and (9) the system of equality constraints (7) for the
274.254 +// current basis can be written as follows:
274.255 +//
274.256 +// xB = A~ * xN, (14)
274.257 +//
274.258 +// where
274.259 +//
274.260 +// A~ = - inv(B) * N (15)
274.261 +//
274.262 +// is a mxn matrix called the simplex table.
274.263 +//
274.264 +// The revised simplex method uses only two components of A~, namely,
274.265 +// pivot column corresponding to non-basic variable xN[q] chosen to
274.266 +// enter the basis, and pivot row corresponding to basic variable xB[p]
274.267 +// chosen to leave the basis.
274.268 +//
274.269 +// Pivot column alfa_q is q-th column of A~, so
274.270 +//
274.271 +// alfa_q = A~ * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q], (16)
274.272 +//
274.273 +// where N[q] is q-th column of the matrix N.
274.274 +//
274.275 +// Pivot row alfa_p is p-th row of A~ or, equivalently, p-th column of
274.276 +// A~', a matrix transposed to A~, so
274.277 +//
274.278 +// alfa_p = A~' * e[p] = - N' * inv(B') * e[p] = - N' * rho_p, (17)
274.279 +//
274.280 +// where (*)' means transposition, and
274.281 +//
274.282 +// rho_p = inv(B') * e[p], (18)
274.283 +//
274.284 +// is p-th column of inv(B') or, that is the same, p-th row of inv(B).
274.285 +----------------------------------------------------------------------*/
274.286 + int p;
274.287 + /* number of basic variable xB[p], 1 <= p <= m, chosen to leave
274.288 + the basis */
274.289 + mpq_t *rho; /* mpq_t rho[1+m]; */
274.290 + /* p-th row of the inverse inv(B); see (18) */
274.291 + mpq_t *ap; /* mpq_t ap[1+n]; */
274.292 + /* p-th row of the simplex table; see (17) */
274.293 + int q;
274.294 + /* number of non-basic variable xN[q], 1 <= q <= n, chosen to
274.295 + enter the basis */
274.296 + mpq_t *aq; /* mpq_t aq[1+m]; */
274.297 + /* q-th column of the simplex table; see (16) */
274.298 +/*--------------------------------------------------------------------*/
274.299 + int q_dir;
274.300 + /* direction in which non-basic variable xN[q] should change on
274.301 + moving to the adjacent vertex of the polyhedron:
274.302 + +1 means that xN[q] increases
274.303 + -1 means that xN[q] decreases */
274.304 + int p_stat;
274.305 + /* non-basic status which should be assigned to basic variable
274.306 + xB[p] when it has left the basis and become xN[q] */
274.307 + mpq_t delta;
274.308 + /* actual change of xN[q] in the adjacent basis (it has the same
274.309 + sign as q_dir) */
274.310 +/*--------------------------------------------------------------------*/
274.311 + int it_lim;
274.312 + /* simplex iterations limit; if this value is positive, it is
274.313 + decreased by one each time when one simplex iteration has been
274.314 + performed, and reaching zero value signals the solver to stop
274.315 + the search; negative value means no iterations limit */
274.316 + int it_cnt;
274.317 + /* simplex iterations count; this count is increased by one each
274.318 + time when one simplex iteration has been performed */
274.319 + double tm_lim;
274.320 + /* searching time limit, in seconds; if this value is positive,
274.321 + it is decreased each time when one simplex iteration has been
274.322 + performed by the amount of time spent for the iteration, and
274.323 + reaching zero value signals the solver to stop the search;
274.324 + negative value means no time limit */
274.325 + double out_frq;
274.326 + /* output frequency, in seconds; this parameter specifies how
274.327 + frequently the solver sends information about the progress of
274.328 + the search to the standard output */
274.329 + glp_long tm_beg;
274.330 + /* starting time of the search, in seconds; the total time of the
274.331 + search is the difference between xtime() and tm_beg */
274.332 + glp_long tm_lag;
274.333 + /* the most recent time, in seconds, at which the progress of the
274.334 + the search was displayed */
274.335 +};
274.336 +
274.337 +#define ssx_create _glp_ssx_create
274.338 +#define ssx_factorize _glp_ssx_factorize
274.339 +#define ssx_get_xNj _glp_ssx_get_xNj
274.340 +#define ssx_eval_bbar _glp_ssx_eval_bbar
274.341 +#define ssx_eval_pi _glp_ssx_eval_pi
274.342 +#define ssx_eval_dj _glp_ssx_eval_dj
274.343 +#define ssx_eval_cbar _glp_ssx_eval_cbar
274.344 +#define ssx_eval_rho _glp_ssx_eval_rho
274.345 +#define ssx_eval_row _glp_ssx_eval_row
274.346 +#define ssx_eval_col _glp_ssx_eval_col
274.347 +#define ssx_chuzc _glp_ssx_chuzc
274.348 +#define ssx_chuzr _glp_ssx_chuzr
274.349 +#define ssx_update_bbar _glp_ssx_update_bbar
274.350 +#define ssx_update_pi _glp_ssx_update_pi
274.351 +#define ssx_update_cbar _glp_ssx_update_cbar
274.352 +#define ssx_change_basis _glp_ssx_change_basis
274.353 +#define ssx_delete _glp_ssx_delete
274.354 +
274.355 +#define ssx_phase_I _glp_ssx_phase_I
274.356 +#define ssx_phase_II _glp_ssx_phase_II
274.357 +#define ssx_driver _glp_ssx_driver
274.358 +
274.359 +SSX *ssx_create(int m, int n, int nnz);
274.360 +/* create simplex solver workspace */
274.361 +
274.362 +int ssx_factorize(SSX *ssx);
274.363 +/* factorize the current basis matrix */
274.364 +
274.365 +void ssx_get_xNj(SSX *ssx, int j, mpq_t x);
274.366 +/* determine value of non-basic variable */
274.367 +
274.368 +void ssx_eval_bbar(SSX *ssx);
274.369 +/* compute values of basic variables */
274.370 +
274.371 +void ssx_eval_pi(SSX *ssx);
274.372 +/* compute values of simplex multipliers */
274.373 +
274.374 +void ssx_eval_dj(SSX *ssx, int j, mpq_t dj);
274.375 +/* compute reduced cost of non-basic variable */
274.376 +
274.377 +void ssx_eval_cbar(SSX *ssx);
274.378 +/* compute reduced costs of all non-basic variables */
274.379 +
274.380 +void ssx_eval_rho(SSX *ssx);
274.381 +/* compute p-th row of the inverse */
274.382 +
274.383 +void ssx_eval_row(SSX *ssx);
274.384 +/* compute pivot row of the simplex table */
274.385 +
274.386 +void ssx_eval_col(SSX *ssx);
274.387 +/* compute pivot column of the simplex table */
274.388 +
274.389 +void ssx_chuzc(SSX *ssx);
274.390 +/* choose pivot column */
274.391 +
274.392 +void ssx_chuzr(SSX *ssx);
274.393 +/* choose pivot row */
274.394 +
274.395 +void ssx_update_bbar(SSX *ssx);
274.396 +/* update values of basic variables */
274.397 +
274.398 +void ssx_update_pi(SSX *ssx);
274.399 +/* update simplex multipliers */
274.400 +
274.401 +void ssx_update_cbar(SSX *ssx);
274.402 +/* update reduced costs of non-basic variables */
274.403 +
274.404 +void ssx_change_basis(SSX *ssx);
274.405 +/* change current basis to adjacent one */
274.406 +
274.407 +void ssx_delete(SSX *ssx);
274.408 +/* delete simplex solver workspace */
274.409 +
274.410 +int ssx_phase_I(SSX *ssx);
274.411 +/* find primal feasible solution */
274.412 +
274.413 +int ssx_phase_II(SSX *ssx);
274.414 +/* find optimal solution */
274.415 +
274.416 +int ssx_driver(SSX *ssx);
274.417 +/* base driver to exact simplex method */
274.418 +
274.419 +#endif
274.420 +
274.421 +/* eof */
275.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
275.2 +++ b/src/glpssx01.c Mon Dec 06 13:09:21 2010 +0100
275.3 @@ -0,0 +1,839 @@
275.4 +/* glpssx01.c */
275.5 +
275.6 +/***********************************************************************
275.7 +* This code is part of GLPK (GNU Linear Programming Kit).
275.8 +*
275.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
275.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
275.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
275.12 +* E-mail: <mao@gnu.org>.
275.13 +*
275.14 +* GLPK is free software: you can redistribute it and/or modify it
275.15 +* under the terms of the GNU General Public License as published by
275.16 +* the Free Software Foundation, either version 3 of the License, or
275.17 +* (at your option) any later version.
275.18 +*
275.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
275.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
275.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
275.22 +* License for more details.
275.23 +*
275.24 +* You should have received a copy of the GNU General Public License
275.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
275.26 +***********************************************************************/
275.27 +
275.28 +#include "glpenv.h"
275.29 +#include "glpssx.h"
275.30 +#define xfault xerror
275.31 +
275.32 +/*----------------------------------------------------------------------
275.33 +// ssx_create - create simplex solver workspace.
275.34 +//
275.35 +// This routine creates the workspace used by simplex solver routines,
275.36 +// and returns a pointer to it.
275.37 +//
275.38 +// Parameters m, n, and nnz specify, respectively, the number of rows,
275.39 +// columns, and non-zero constraint coefficients.
275.40 +//
275.41 +// This routine only allocates the memory for the workspace components,
275.42 +// so the workspace needs to be saturated by data. */
275.43 +
275.44 +SSX *ssx_create(int m, int n, int nnz)
275.45 +{ SSX *ssx;
275.46 + int i, j, k;
275.47 + if (m < 1)
275.48 + xfault("ssx_create: m = %d; invalid number of rows\n", m);
275.49 + if (n < 1)
275.50 + xfault("ssx_create: n = %d; invalid number of columns\n", n);
275.51 + if (nnz < 0)
275.52 + xfault("ssx_create: nnz = %d; invalid number of non-zero const"
275.53 + "raint coefficients\n", nnz);
275.54 + ssx = xmalloc(sizeof(SSX));
275.55 + ssx->m = m;
275.56 + ssx->n = n;
275.57 + ssx->type = xcalloc(1+m+n, sizeof(int));
275.58 + ssx->lb = xcalloc(1+m+n, sizeof(mpq_t));
275.59 + for (k = 1; k <= m+n; k++) mpq_init(ssx->lb[k]);
275.60 + ssx->ub = xcalloc(1+m+n, sizeof(mpq_t));
275.61 + for (k = 1; k <= m+n; k++) mpq_init(ssx->ub[k]);
275.62 + ssx->coef = xcalloc(1+m+n, sizeof(mpq_t));
275.63 + for (k = 0; k <= m+n; k++) mpq_init(ssx->coef[k]);
275.64 + ssx->A_ptr = xcalloc(1+n+1, sizeof(int));
275.65 + ssx->A_ptr[n+1] = nnz+1;
275.66 + ssx->A_ind = xcalloc(1+nnz, sizeof(int));
275.67 + ssx->A_val = xcalloc(1+nnz, sizeof(mpq_t));
275.68 + for (k = 1; k <= nnz; k++) mpq_init(ssx->A_val[k]);
275.69 + ssx->stat = xcalloc(1+m+n, sizeof(int));
275.70 + ssx->Q_row = xcalloc(1+m+n, sizeof(int));
275.71 + ssx->Q_col = xcalloc(1+m+n, sizeof(int));
275.72 + ssx->binv = bfx_create_binv();
275.73 + ssx->bbar = xcalloc(1+m, sizeof(mpq_t));
275.74 + for (i = 0; i <= m; i++) mpq_init(ssx->bbar[i]);
275.75 + ssx->pi = xcalloc(1+m, sizeof(mpq_t));
275.76 + for (i = 1; i <= m; i++) mpq_init(ssx->pi[i]);
275.77 + ssx->cbar = xcalloc(1+n, sizeof(mpq_t));
275.78 + for (j = 1; j <= n; j++) mpq_init(ssx->cbar[j]);
275.79 + ssx->rho = xcalloc(1+m, sizeof(mpq_t));
275.80 + for (i = 1; i <= m; i++) mpq_init(ssx->rho[i]);
275.81 + ssx->ap = xcalloc(1+n, sizeof(mpq_t));
275.82 + for (j = 1; j <= n; j++) mpq_init(ssx->ap[j]);
275.83 + ssx->aq = xcalloc(1+m, sizeof(mpq_t));
275.84 + for (i = 1; i <= m; i++) mpq_init(ssx->aq[i]);
275.85 + mpq_init(ssx->delta);
275.86 + return ssx;
275.87 +}
275.88 +
275.89 +/*----------------------------------------------------------------------
275.90 +// ssx_factorize - factorize the current basis matrix.
275.91 +//
275.92 +// This routine computes factorization of the current basis matrix B
275.93 +// and returns the singularity flag. If the matrix B is non-singular,
275.94 +// the flag is zero, otherwise non-zero. */
275.95 +
275.96 +static int basis_col(void *info, int j, int ind[], mpq_t val[])
275.97 +{ /* this auxiliary routine provides row indices and numeric values
275.98 + of non-zero elements in j-th column of the matrix B */
275.99 + SSX *ssx = info;
275.100 + int m = ssx->m;
275.101 + int n = ssx->n;
275.102 + int *A_ptr = ssx->A_ptr;
275.103 + int *A_ind = ssx->A_ind;
275.104 + mpq_t *A_val = ssx->A_val;
275.105 + int *Q_col = ssx->Q_col;
275.106 + int k, len, ptr;
275.107 + xassert(1 <= j && j <= m);
275.108 + k = Q_col[j]; /* x[k] = xB[j] */
275.109 + xassert(1 <= k && k <= m+n);
275.110 + /* j-th column of the matrix B is k-th column of the augmented
275.111 + constraint matrix (I | -A) */
275.112 + if (k <= m)
275.113 + { /* it is a column of the unity matrix I */
275.114 + len = 1, ind[1] = k, mpq_set_si(val[1], 1, 1);
275.115 + }
275.116 + else
275.117 + { /* it is a column of the original constraint matrix -A */
275.118 + len = 0;
275.119 + for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
275.120 + { len++;
275.121 + ind[len] = A_ind[ptr];
275.122 + mpq_neg(val[len], A_val[ptr]);
275.123 + }
275.124 + }
275.125 + return len;
275.126 +}
275.127 +
275.128 +int ssx_factorize(SSX *ssx)
275.129 +{ int ret;
275.130 + ret = bfx_factorize(ssx->binv, ssx->m, basis_col, ssx);
275.131 + return ret;
275.132 +}
275.133 +
275.134 +/*----------------------------------------------------------------------
275.135 +// ssx_get_xNj - determine value of non-basic variable.
275.136 +//
275.137 +// This routine determines the value of non-basic variable xN[j] in the
275.138 +// current basic solution defined as follows:
275.139 +//
275.140 +// 0, if xN[j] is free variable
275.141 +// lN[j], if xN[j] is on its lower bound
275.142 +// uN[j], if xN[j] is on its upper bound
275.143 +// lN[j] = uN[j], if xN[j] is fixed variable
275.144 +//
275.145 +// where lN[j] and uN[j] are lower and upper bounds of xN[j]. */
275.146 +
275.147 +void ssx_get_xNj(SSX *ssx, int j, mpq_t x)
275.148 +{ int m = ssx->m;
275.149 + int n = ssx->n;
275.150 + mpq_t *lb = ssx->lb;
275.151 + mpq_t *ub = ssx->ub;
275.152 + int *stat = ssx->stat;
275.153 + int *Q_col = ssx->Q_col;
275.154 + int k;
275.155 + xassert(1 <= j && j <= n);
275.156 + k = Q_col[m+j]; /* x[k] = xN[j] */
275.157 + xassert(1 <= k && k <= m+n);
275.158 + switch (stat[k])
275.159 + { case SSX_NL:
275.160 + /* xN[j] is on its lower bound */
275.161 + mpq_set(x, lb[k]); break;
275.162 + case SSX_NU:
275.163 + /* xN[j] is on its upper bound */
275.164 + mpq_set(x, ub[k]); break;
275.165 + case SSX_NF:
275.166 + /* xN[j] is free variable */
275.167 + mpq_set_si(x, 0, 1); break;
275.168 + case SSX_NS:
275.169 + /* xN[j] is fixed variable */
275.170 + mpq_set(x, lb[k]); break;
275.171 + default:
275.172 + xassert(stat != stat);
275.173 + }
275.174 + return;
275.175 +}
275.176 +
275.177 +/*----------------------------------------------------------------------
275.178 +// ssx_eval_bbar - compute values of basic variables.
275.179 +//
275.180 +// This routine computes values of basic variables xB in the current
275.181 +// basic solution as follows:
275.182 +//
275.183 +// beta = - inv(B) * N * xN,
275.184 +//
275.185 +// where B is the basis matrix, N is the matrix of non-basic columns,
275.186 +// xN is a vector of current values of non-basic variables. */
275.187 +
275.188 +void ssx_eval_bbar(SSX *ssx)
275.189 +{ int m = ssx->m;
275.190 + int n = ssx->n;
275.191 + mpq_t *coef = ssx->coef;
275.192 + int *A_ptr = ssx->A_ptr;
275.193 + int *A_ind = ssx->A_ind;
275.194 + mpq_t *A_val = ssx->A_val;
275.195 + int *Q_col = ssx->Q_col;
275.196 + mpq_t *bbar = ssx->bbar;
275.197 + int i, j, k, ptr;
275.198 + mpq_t x, temp;
275.199 + mpq_init(x);
275.200 + mpq_init(temp);
275.201 + /* bbar := 0 */
275.202 + for (i = 1; i <= m; i++)
275.203 + mpq_set_si(bbar[i], 0, 1);
275.204 + /* bbar := - N * xN = - N[1] * xN[1] - ... - N[n] * xN[n] */
275.205 + for (j = 1; j <= n; j++)
275.206 + { ssx_get_xNj(ssx, j, x);
275.207 + if (mpq_sgn(x) == 0) continue;
275.208 + k = Q_col[m+j]; /* x[k] = xN[j] */
275.209 + if (k <= m)
275.210 + { /* N[j] is a column of the unity matrix I */
275.211 + mpq_sub(bbar[k], bbar[k], x);
275.212 + }
275.213 + else
275.214 + { /* N[j] is a column of the original constraint matrix -A */
275.215 + for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
275.216 + { mpq_mul(temp, A_val[ptr], x);
275.217 + mpq_add(bbar[A_ind[ptr]], bbar[A_ind[ptr]], temp);
275.218 + }
275.219 + }
275.220 + }
275.221 + /* bbar := inv(B) * bbar */
275.222 + bfx_ftran(ssx->binv, bbar, 0);
275.223 +#if 1
275.224 + /* compute value of the objective function */
275.225 + /* bbar[0] := c[0] */
275.226 + mpq_set(bbar[0], coef[0]);
275.227 + /* bbar[0] := bbar[0] + sum{i in B} cB[i] * xB[i] */
275.228 + for (i = 1; i <= m; i++)
275.229 + { k = Q_col[i]; /* x[k] = xB[i] */
275.230 + if (mpq_sgn(coef[k]) == 0) continue;
275.231 + mpq_mul(temp, coef[k], bbar[i]);
275.232 + mpq_add(bbar[0], bbar[0], temp);
275.233 + }
275.234 + /* bbar[0] := bbar[0] + sum{j in N} cN[j] * xN[j] */
275.235 + for (j = 1; j <= n; j++)
275.236 + { k = Q_col[m+j]; /* x[k] = xN[j] */
275.237 + if (mpq_sgn(coef[k]) == 0) continue;
275.238 + ssx_get_xNj(ssx, j, x);
275.239 + mpq_mul(temp, coef[k], x);
275.240 + mpq_add(bbar[0], bbar[0], temp);
275.241 + }
275.242 +#endif
275.243 + mpq_clear(x);
275.244 + mpq_clear(temp);
275.245 + return;
275.246 +}
275.247 +
275.248 +/*----------------------------------------------------------------------
275.249 +// ssx_eval_pi - compute values of simplex multipliers.
275.250 +//
275.251 +// This routine computes values of simplex multipliers (shadow prices)
275.252 +// pi in the current basic solution as follows:
275.253 +//
275.254 +// pi = inv(B') * cB,
275.255 +//
275.256 +// where B' is a matrix transposed to the basis matrix B, cB is a vector
275.257 +// of objective coefficients at basic variables xB. */
275.258 +
275.259 +void ssx_eval_pi(SSX *ssx)
275.260 +{ int m = ssx->m;
275.261 + mpq_t *coef = ssx->coef;
275.262 + int *Q_col = ssx->Q_col;
275.263 + mpq_t *pi = ssx->pi;
275.264 + int i;
275.265 + /* pi := cB */
275.266 + for (i = 1; i <= m; i++) mpq_set(pi[i], coef[Q_col[i]]);
275.267 + /* pi := inv(B') * cB */
275.268 + bfx_btran(ssx->binv, pi);
275.269 + return;
275.270 +}
275.271 +
275.272 +/*----------------------------------------------------------------------
275.273 +// ssx_eval_dj - compute reduced cost of non-basic variable.
275.274 +//
275.275 +// This routine computes reduced cost d[j] of non-basic variable xN[j]
275.276 +// in the current basic solution as follows:
275.277 +//
275.278 +// d[j] = cN[j] - N[j] * pi,
275.279 +//
275.280 +// where cN[j] is an objective coefficient at xN[j], N[j] is a column
275.281 +// of the augmented constraint matrix (I | -A) corresponding to xN[j],
275.282 +// pi is the vector of simplex multipliers (shadow prices). */
275.283 +
275.284 +void ssx_eval_dj(SSX *ssx, int j, mpq_t dj)
275.285 +{ int m = ssx->m;
275.286 + int n = ssx->n;
275.287 + mpq_t *coef = ssx->coef;
275.288 + int *A_ptr = ssx->A_ptr;
275.289 + int *A_ind = ssx->A_ind;
275.290 + mpq_t *A_val = ssx->A_val;
275.291 + int *Q_col = ssx->Q_col;
275.292 + mpq_t *pi = ssx->pi;
275.293 + int k, ptr, end;
275.294 + mpq_t temp;
275.295 + mpq_init(temp);
275.296 + xassert(1 <= j && j <= n);
275.297 + k = Q_col[m+j]; /* x[k] = xN[j] */
275.298 + xassert(1 <= k && k <= m+n);
275.299 + /* j-th column of the matrix N is k-th column of the augmented
275.300 + constraint matrix (I | -A) */
275.301 + if (k <= m)
275.302 + { /* it is a column of the unity matrix I */
275.303 + mpq_sub(dj, coef[k], pi[k]);
275.304 + }
275.305 + else
275.306 + { /* it is a column of the original constraint matrix -A */
275.307 + mpq_set(dj, coef[k]);
275.308 + for (ptr = A_ptr[k-m], end = A_ptr[k-m+1]; ptr < end; ptr++)
275.309 + { mpq_mul(temp, A_val[ptr], pi[A_ind[ptr]]);
275.310 + mpq_add(dj, dj, temp);
275.311 + }
275.312 + }
275.313 + mpq_clear(temp);
275.314 + return;
275.315 +}
275.316 +
275.317 +/*----------------------------------------------------------------------
275.318 +// ssx_eval_cbar - compute reduced costs of all non-basic variables.
275.319 +//
275.320 +// This routine computes the vector of reduced costs pi in the current
275.321 +// basic solution for all non-basic variables, including fixed ones. */
275.322 +
275.323 +void ssx_eval_cbar(SSX *ssx)
275.324 +{ int n = ssx->n;
275.325 + mpq_t *cbar = ssx->cbar;
275.326 + int j;
275.327 + for (j = 1; j <= n; j++)
275.328 + ssx_eval_dj(ssx, j, cbar[j]);
275.329 + return;
275.330 +}
275.331 +
275.332 +/*----------------------------------------------------------------------
275.333 +// ssx_eval_rho - compute p-th row of the inverse.
275.334 +//
275.335 +// This routine computes p-th row of the matrix inv(B), where B is the
275.336 +// current basis matrix.
275.337 +//
275.338 +// p-th row of the inverse is computed using the following formula:
275.339 +//
275.340 +// rho = inv(B') * e[p],
275.341 +//
275.342 +// where B' is a matrix transposed to B, e[p] is a unity vector, which
275.343 +// contains one in p-th position. */
275.344 +
275.345 +void ssx_eval_rho(SSX *ssx)
275.346 +{ int m = ssx->m;
275.347 + int p = ssx->p;
275.348 + mpq_t *rho = ssx->rho;
275.349 + int i;
275.350 + xassert(1 <= p && p <= m);
275.351 + /* rho := 0 */
275.352 + for (i = 1; i <= m; i++) mpq_set_si(rho[i], 0, 1);
275.353 + /* rho := e[p] */
275.354 + mpq_set_si(rho[p], 1, 1);
275.355 + /* rho := inv(B') * rho */
275.356 + bfx_btran(ssx->binv, rho);
275.357 + return;
275.358 +}
275.359 +
275.360 +/*----------------------------------------------------------------------
275.361 +// ssx_eval_row - compute pivot row of the simplex table.
275.362 +//
275.363 +// This routine computes p-th (pivot) row of the current simplex table
275.364 +// A~ = - inv(B) * N using the following formula:
275.365 +//
275.366 +// A~[p] = - N' * inv(B') * e[p] = - N' * rho[p],
275.367 +//
275.368 +// where N' is a matrix transposed to the matrix N, rho[p] is p-th row
275.369 +// of the inverse inv(B). */
275.370 +
275.371 +void ssx_eval_row(SSX *ssx)
275.372 +{ int m = ssx->m;
275.373 + int n = ssx->n;
275.374 + int *A_ptr = ssx->A_ptr;
275.375 + int *A_ind = ssx->A_ind;
275.376 + mpq_t *A_val = ssx->A_val;
275.377 + int *Q_col = ssx->Q_col;
275.378 + mpq_t *rho = ssx->rho;
275.379 + mpq_t *ap = ssx->ap;
275.380 + int j, k, ptr;
275.381 + mpq_t temp;
275.382 + mpq_init(temp);
275.383 + for (j = 1; j <= n; j++)
275.384 + { /* ap[j] := - N'[j] * rho (inner product) */
275.385 + k = Q_col[m+j]; /* x[k] = xN[j] */
275.386 + if (k <= m)
275.387 + mpq_neg(ap[j], rho[k]);
275.388 + else
275.389 + { mpq_set_si(ap[j], 0, 1);
275.390 + for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
275.391 + { mpq_mul(temp, A_val[ptr], rho[A_ind[ptr]]);
275.392 + mpq_add(ap[j], ap[j], temp);
275.393 + }
275.394 + }
275.395 + }
275.396 + mpq_clear(temp);
275.397 + return;
275.398 +}
275.399 +
275.400 +/*----------------------------------------------------------------------
275.401 +// ssx_eval_col - compute pivot column of the simplex table.
275.402 +//
275.403 +// This routine computes q-th (pivot) column of the current simplex
275.404 +// table A~ = - inv(B) * N using the following formula:
275.405 +//
275.406 +// A~[q] = - inv(B) * N[q],
275.407 +//
275.408 +// where N[q] is q-th column of the matrix N corresponding to chosen
275.409 +// non-basic variable xN[q]. */
275.410 +
275.411 +void ssx_eval_col(SSX *ssx)
275.412 +{ int m = ssx->m;
275.413 + int n = ssx->n;
275.414 + int *A_ptr = ssx->A_ptr;
275.415 + int *A_ind = ssx->A_ind;
275.416 + mpq_t *A_val = ssx->A_val;
275.417 + int *Q_col = ssx->Q_col;
275.418 + int q = ssx->q;
275.419 + mpq_t *aq = ssx->aq;
275.420 + int i, k, ptr;
275.421 + xassert(1 <= q && q <= n);
275.422 + /* aq := 0 */
275.423 + for (i = 1; i <= m; i++) mpq_set_si(aq[i], 0, 1);
275.424 + /* aq := N[q] */
275.425 + k = Q_col[m+q]; /* x[k] = xN[q] */
275.426 + if (k <= m)
275.427 + { /* N[q] is a column of the unity matrix I */
275.428 + mpq_set_si(aq[k], 1, 1);
275.429 + }
275.430 + else
275.431 + { /* N[q] is a column of the original constraint matrix -A */
275.432 + for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
275.433 + mpq_neg(aq[A_ind[ptr]], A_val[ptr]);
275.434 + }
275.435 + /* aq := inv(B) * aq */
275.436 + bfx_ftran(ssx->binv, aq, 1);
275.437 + /* aq := - aq */
275.438 + for (i = 1; i <= m; i++) mpq_neg(aq[i], aq[i]);
275.439 + return;
275.440 +}
275.441 +
275.442 +/*----------------------------------------------------------------------
275.443 +// ssx_chuzc - choose pivot column.
275.444 +//
275.445 +// This routine chooses non-basic variable xN[q] whose reduced cost
275.446 +// indicates possible improving of the objective function to enter it
275.447 +// in the basis.
275.448 +//
275.449 +// Currently the standard (textbook) pricing is used, i.e. that
275.450 +// non-basic variable is preferred which has greatest reduced cost (in
275.451 +// magnitude).
275.452 +//
275.453 +// If xN[q] has been chosen, the routine stores its number q and also
275.454 +// sets the flag q_dir that indicates direction in which xN[q] has to
275.455 +// change (+1 means increasing, -1 means decreasing).
275.456 +//
275.457 +// If the choice cannot be made, because the current basic solution is
275.458 +// dual feasible, the routine sets the number q to 0. */
275.459 +
275.460 +void ssx_chuzc(SSX *ssx)
275.461 +{ int m = ssx->m;
275.462 + int n = ssx->n;
275.463 + int dir = (ssx->dir == SSX_MIN ? +1 : -1);
275.464 + int *Q_col = ssx->Q_col;
275.465 + int *stat = ssx->stat;
275.466 + mpq_t *cbar = ssx->cbar;
275.467 + int j, k, s, q, q_dir;
275.468 + double best, temp;
275.469 + /* nothing is chosen so far */
275.470 + q = 0, q_dir = 0, best = 0.0;
275.471 + /* look through the list of non-basic variables */
275.472 + for (j = 1; j <= n; j++)
275.473 + { k = Q_col[m+j]; /* x[k] = xN[j] */
275.474 + s = dir * mpq_sgn(cbar[j]);
275.475 + if ((stat[k] == SSX_NF || stat[k] == SSX_NL) && s < 0 ||
275.476 + (stat[k] == SSX_NF || stat[k] == SSX_NU) && s > 0)
275.477 + { /* reduced cost of xN[j] indicates possible improving of
275.478 + the objective function */
275.479 + temp = fabs(mpq_get_d(cbar[j]));
275.480 + xassert(temp != 0.0);
275.481 + if (q == 0 || best < temp)
275.482 + q = j, q_dir = - s, best = temp;
275.483 + }
275.484 + }
275.485 + ssx->q = q, ssx->q_dir = q_dir;
275.486 + return;
275.487 +}
275.488 +
275.489 +/*----------------------------------------------------------------------
275.490 +// ssx_chuzr - choose pivot row.
275.491 +//
275.492 +// This routine looks through elements of q-th column of the simplex
275.493 +// table and chooses basic variable xB[p] which should leave the basis.
275.494 +//
275.495 +// The choice is based on the standard (textbook) ratio test.
275.496 +//
275.497 +// If xB[p] has been chosen, the routine stores its number p and also
275.498 +// sets its non-basic status p_stat which should be assigned to xB[p]
275.499 +// when it has left the basis and become xN[q].
275.500 +//
275.501 +// Special case p < 0 means that xN[q] is double-bounded variable and
275.502 +// it reaches its opposite bound before any basic variable does that,
275.503 +// so the current basis remains unchanged.
275.504 +//
275.505 +// If the choice cannot be made, because xN[q] can infinitely change in
275.506 +// the feasible direction, the routine sets the number p to 0. */
275.507 +
275.508 +void ssx_chuzr(SSX *ssx)
275.509 +{ int m = ssx->m;
275.510 + int n = ssx->n;
275.511 + int *type = ssx->type;
275.512 + mpq_t *lb = ssx->lb;
275.513 + mpq_t *ub = ssx->ub;
275.514 + int *Q_col = ssx->Q_col;
275.515 + mpq_t *bbar = ssx->bbar;
275.516 + int q = ssx->q;
275.517 + mpq_t *aq = ssx->aq;
275.518 + int q_dir = ssx->q_dir;
275.519 + int i, k, s, t, p, p_stat;
275.520 + mpq_t teta, temp;
275.521 + mpq_init(teta);
275.522 + mpq_init(temp);
275.523 + xassert(1 <= q && q <= n);
275.524 + xassert(q_dir == +1 || q_dir == -1);
275.525 + /* nothing is chosen so far */
275.526 + p = 0, p_stat = 0;
275.527 + /* look through the list of basic variables */
275.528 + for (i = 1; i <= m; i++)
275.529 + { s = q_dir * mpq_sgn(aq[i]);
275.530 + if (s < 0)
275.531 + { /* xB[i] decreases */
275.532 + k = Q_col[i]; /* x[k] = xB[i] */
275.533 + t = type[k];
275.534 + if (t == SSX_LO || t == SSX_DB || t == SSX_FX)
275.535 + { /* xB[i] has finite lower bound */
275.536 + mpq_sub(temp, bbar[i], lb[k]);
275.537 + mpq_div(temp, temp, aq[i]);
275.538 + mpq_abs(temp, temp);
275.539 + if (p == 0 || mpq_cmp(teta, temp) > 0)
275.540 + { p = i;
275.541 + p_stat = (t == SSX_FX ? SSX_NS : SSX_NL);
275.542 + mpq_set(teta, temp);
275.543 + }
275.544 + }
275.545 + }
275.546 + else if (s > 0)
275.547 + { /* xB[i] increases */
275.548 + k = Q_col[i]; /* x[k] = xB[i] */
275.549 + t = type[k];
275.550 + if (t == SSX_UP || t == SSX_DB || t == SSX_FX)
275.551 + { /* xB[i] has finite upper bound */
275.552 + mpq_sub(temp, bbar[i], ub[k]);
275.553 + mpq_div(temp, temp, aq[i]);
275.554 + mpq_abs(temp, temp);
275.555 + if (p == 0 || mpq_cmp(teta, temp) > 0)
275.556 + { p = i;
275.557 + p_stat = (t == SSX_FX ? SSX_NS : SSX_NU);
275.558 + mpq_set(teta, temp);
275.559 + }
275.560 + }
275.561 + }
275.562 + /* if something has been chosen and the ratio test indicates
275.563 + exact degeneracy, the search can be finished */
275.564 + if (p != 0 && mpq_sgn(teta) == 0) break;
275.565 + }
275.566 + /* if xN[q] is double-bounded, check if it can reach its opposite
275.567 + bound before any basic variable */
275.568 + k = Q_col[m+q]; /* x[k] = xN[q] */
275.569 + if (type[k] == SSX_DB)
275.570 + { mpq_sub(temp, ub[k], lb[k]);
275.571 + if (p == 0 || mpq_cmp(teta, temp) > 0)
275.572 + { p = -1;
275.573 + p_stat = -1;
275.574 + mpq_set(teta, temp);
275.575 + }
275.576 + }
275.577 + ssx->p = p;
275.578 + ssx->p_stat = p_stat;
275.579 + /* if xB[p] has been chosen, determine its actual change in the
275.580 + adjacent basis (it has the same sign as q_dir) */
275.581 + if (p != 0)
275.582 + { xassert(mpq_sgn(teta) >= 0);
275.583 + if (q_dir > 0)
275.584 + mpq_set(ssx->delta, teta);
275.585 + else
275.586 + mpq_neg(ssx->delta, teta);
275.587 + }
275.588 + mpq_clear(teta);
275.589 + mpq_clear(temp);
275.590 + return;
275.591 +}
275.592 +
275.593 +/*----------------------------------------------------------------------
275.594 +// ssx_update_bbar - update values of basic variables.
275.595 +//
275.596 +// This routine recomputes the current values of basic variables for
275.597 +// the adjacent basis.
275.598 +//
275.599 +// The simplex table for the current basis is the following:
275.600 +//
275.601 +// xB[i] = sum{j in 1..n} alfa[i,j] * xN[q], i = 1,...,m
275.602 +//
275.603 +// therefore
275.604 +//
275.605 +// delta xB[i] = alfa[i,q] * delta xN[q], i = 1,...,m
275.606 +//
275.607 +// where delta xN[q] = xN.new[q] - xN[q] is the change of xN[q] in the
275.608 +// adjacent basis, and delta xB[i] = xB.new[i] - xB[i] is the change of
275.609 +// xB[i]. This gives formulae for recomputing values of xB[i]:
275.610 +//
275.611 +// xB.new[p] = xN[q] + delta xN[q]
275.612 +//
275.613 +// (because xN[q] becomes xB[p] in the adjacent basis), and
275.614 +//
275.615 +// xB.new[i] = xB[i] + alfa[i,q] * delta xN[q], i != p
275.616 +//
275.617 +// for other basic variables. */
275.618 +
275.619 +void ssx_update_bbar(SSX *ssx)
275.620 +{ int m = ssx->m;
275.621 + int n = ssx->n;
275.622 + mpq_t *bbar = ssx->bbar;
275.623 + mpq_t *cbar = ssx->cbar;
275.624 + int p = ssx->p;
275.625 + int q = ssx->q;
275.626 + mpq_t *aq = ssx->aq;
275.627 + int i;
275.628 + mpq_t temp;
275.629 + mpq_init(temp);
275.630 + xassert(1 <= q && q <= n);
275.631 + if (p < 0)
275.632 + { /* xN[q] is double-bounded and goes to its opposite bound */
275.633 + /* nop */;
275.634 + }
275.635 + else
275.636 + { /* xN[q] becomes xB[p] in the adjacent basis */
275.637 + /* xB.new[p] = xN[q] + delta xN[q] */
275.638 + xassert(1 <= p && p <= m);
275.639 + ssx_get_xNj(ssx, q, temp);
275.640 + mpq_add(bbar[p], temp, ssx->delta);
275.641 + }
275.642 + /* update values of other basic variables depending on xN[q] */
275.643 + for (i = 1; i <= m; i++)
275.644 + { if (i == p) continue;
275.645 + /* xB.new[i] = xB[i] + alfa[i,q] * delta xN[q] */
275.646 + if (mpq_sgn(aq[i]) == 0) continue;
275.647 + mpq_mul(temp, aq[i], ssx->delta);
275.648 + mpq_add(bbar[i], bbar[i], temp);
275.649 + }
275.650 +#if 1
275.651 + /* update value of the objective function */
275.652 + /* z.new = z + d[q] * delta xN[q] */
275.653 + mpq_mul(temp, cbar[q], ssx->delta);
275.654 + mpq_add(bbar[0], bbar[0], temp);
275.655 +#endif
275.656 + mpq_clear(temp);
275.657 + return;
275.658 +}
275.659 +
275.660 +/*----------------------------------------------------------------------
275.661 +-- ssx_update_pi - update simplex multipliers.
275.662 +--
275.663 +-- This routine recomputes the vector of simplex multipliers for the
275.664 +-- adjacent basis. */
275.665 +
275.666 +void ssx_update_pi(SSX *ssx)
275.667 +{ int m = ssx->m;
275.668 + int n = ssx->n;
275.669 + mpq_t *pi = ssx->pi;
275.670 + mpq_t *cbar = ssx->cbar;
275.671 + int p = ssx->p;
275.672 + int q = ssx->q;
275.673 + mpq_t *aq = ssx->aq;
275.674 + mpq_t *rho = ssx->rho;
275.675 + int i;
275.676 + mpq_t new_dq, temp;
275.677 + mpq_init(new_dq);
275.678 + mpq_init(temp);
275.679 + xassert(1 <= p && p <= m);
275.680 + xassert(1 <= q && q <= n);
275.681 + /* compute d[q] in the adjacent basis */
275.682 + mpq_div(new_dq, cbar[q], aq[p]);
275.683 + /* update the vector of simplex multipliers */
275.684 + for (i = 1; i <= m; i++)
275.685 + { if (mpq_sgn(rho[i]) == 0) continue;
275.686 + mpq_mul(temp, new_dq, rho[i]);
275.687 + mpq_sub(pi[i], pi[i], temp);
275.688 + }
275.689 + mpq_clear(new_dq);
275.690 + mpq_clear(temp);
275.691 + return;
275.692 +}
275.693 +
275.694 +/*----------------------------------------------------------------------
275.695 +// ssx_update_cbar - update reduced costs of non-basic variables.
275.696 +//
275.697 +// This routine recomputes the vector of reduced costs of non-basic
275.698 +// variables for the adjacent basis. */
275.699 +
275.700 +void ssx_update_cbar(SSX *ssx)
275.701 +{ int m = ssx->m;
275.702 + int n = ssx->n;
275.703 + mpq_t *cbar = ssx->cbar;
275.704 + int p = ssx->p;
275.705 + int q = ssx->q;
275.706 + mpq_t *ap = ssx->ap;
275.707 + int j;
275.708 + mpq_t temp;
275.709 + mpq_init(temp);
275.710 + xassert(1 <= p && p <= m);
275.711 + xassert(1 <= q && q <= n);
275.712 + /* compute d[q] in the adjacent basis */
275.713 + /* d.new[q] = d[q] / alfa[p,q] */
275.714 + mpq_div(cbar[q], cbar[q], ap[q]);
275.715 + /* update reduced costs of other non-basic variables */
275.716 + for (j = 1; j <= n; j++)
275.717 + { if (j == q) continue;
275.718 + /* d.new[j] = d[j] - (alfa[p,j] / alfa[p,q]) * d[q] */
275.719 + if (mpq_sgn(ap[j]) == 0) continue;
275.720 + mpq_mul(temp, ap[j], cbar[q]);
275.721 + mpq_sub(cbar[j], cbar[j], temp);
275.722 + }
275.723 + mpq_clear(temp);
275.724 + return;
275.725 +}
275.726 +
275.727 +/*----------------------------------------------------------------------
275.728 +// ssx_change_basis - change current basis to adjacent one.
275.729 +//
275.730 +// This routine changes the current basis to the adjacent one swapping
275.731 +// basic variable xB[p] and non-basic variable xN[q]. */
275.732 +
275.733 +void ssx_change_basis(SSX *ssx)
275.734 +{ int m = ssx->m;
275.735 + int n = ssx->n;
275.736 + int *type = ssx->type;
275.737 + int *stat = ssx->stat;
275.738 + int *Q_row = ssx->Q_row;
275.739 + int *Q_col = ssx->Q_col;
275.740 + int p = ssx->p;
275.741 + int q = ssx->q;
275.742 + int p_stat = ssx->p_stat;
275.743 + int k, kp, kq;
275.744 + if (p < 0)
275.745 + { /* special case: xN[q] goes to its opposite bound */
275.746 + xassert(1 <= q && q <= n);
275.747 + k = Q_col[m+q]; /* x[k] = xN[q] */
275.748 + xassert(type[k] == SSX_DB);
275.749 + switch (stat[k])
275.750 + { case SSX_NL:
275.751 + stat[k] = SSX_NU;
275.752 + break;
275.753 + case SSX_NU:
275.754 + stat[k] = SSX_NL;
275.755 + break;
275.756 + default:
275.757 + xassert(stat != stat);
275.758 + }
275.759 + }
275.760 + else
275.761 + { /* xB[p] leaves the basis, xN[q] enters the basis */
275.762 + xassert(1 <= p && p <= m);
275.763 + xassert(1 <= q && q <= n);
275.764 + kp = Q_col[p]; /* x[kp] = xB[p] */
275.765 + kq = Q_col[m+q]; /* x[kq] = xN[q] */
275.766 + /* check non-basic status of xB[p] which becomes xN[q] */
275.767 + switch (type[kp])
275.768 + { case SSX_FR:
275.769 + xassert(p_stat == SSX_NF);
275.770 + break;
275.771 + case SSX_LO:
275.772 + xassert(p_stat == SSX_NL);
275.773 + break;
275.774 + case SSX_UP:
275.775 + xassert(p_stat == SSX_NU);
275.776 + break;
275.777 + case SSX_DB:
275.778 + xassert(p_stat == SSX_NL || p_stat == SSX_NU);
275.779 + break;
275.780 + case SSX_FX:
275.781 + xassert(p_stat == SSX_NS);
275.782 + break;
275.783 + default:
275.784 + xassert(type != type);
275.785 + }
275.786 + /* swap xB[p] and xN[q] */
275.787 + stat[kp] = (char)p_stat, stat[kq] = SSX_BS;
275.788 + Q_row[kp] = m+q, Q_row[kq] = p;
275.789 + Q_col[p] = kq, Q_col[m+q] = kp;
275.790 + /* update factorization of the basis matrix */
275.791 + if (bfx_update(ssx->binv, p))
275.792 + { if (ssx_factorize(ssx))
275.793 + xassert(("Internal error: basis matrix is singular", 0));
275.794 + }
275.795 + }
275.796 + return;
275.797 +}
275.798 +
275.799 +/*----------------------------------------------------------------------
275.800 +// ssx_delete - delete simplex solver workspace.
275.801 +//
275.802 +// This routine deletes the simplex solver workspace freeing all the
275.803 +// memory allocated to this object. */
275.804 +
275.805 +void ssx_delete(SSX *ssx)
275.806 +{ int m = ssx->m;
275.807 + int n = ssx->n;
275.808 + int nnz = ssx->A_ptr[n+1]-1;
275.809 + int i, j, k;
275.810 + xfree(ssx->type);
275.811 + for (k = 1; k <= m+n; k++) mpq_clear(ssx->lb[k]);
275.812 + xfree(ssx->lb);
275.813 + for (k = 1; k <= m+n; k++) mpq_clear(ssx->ub[k]);
275.814 + xfree(ssx->ub);
275.815 + for (k = 0; k <= m+n; k++) mpq_clear(ssx->coef[k]);
275.816 + xfree(ssx->coef);
275.817 + xfree(ssx->A_ptr);
275.818 + xfree(ssx->A_ind);
275.819 + for (k = 1; k <= nnz; k++) mpq_clear(ssx->A_val[k]);
275.820 + xfree(ssx->A_val);
275.821 + xfree(ssx->stat);
275.822 + xfree(ssx->Q_row);
275.823 + xfree(ssx->Q_col);
275.824 + bfx_delete_binv(ssx->binv);
275.825 + for (i = 0; i <= m; i++) mpq_clear(ssx->bbar[i]);
275.826 + xfree(ssx->bbar);
275.827 + for (i = 1; i <= m; i++) mpq_clear(ssx->pi[i]);
275.828 + xfree(ssx->pi);
275.829 + for (j = 1; j <= n; j++) mpq_clear(ssx->cbar[j]);
275.830 + xfree(ssx->cbar);
275.831 + for (i = 1; i <= m; i++) mpq_clear(ssx->rho[i]);
275.832 + xfree(ssx->rho);
275.833 + for (j = 1; j <= n; j++) mpq_clear(ssx->ap[j]);
275.834 + xfree(ssx->ap);
275.835 + for (i = 1; i <= m; i++) mpq_clear(ssx->aq[i]);
275.836 + xfree(ssx->aq);
275.837 + mpq_clear(ssx->delta);
275.838 + xfree(ssx);
275.839 + return;
275.840 +}
275.841 +
275.842 +/* eof */
276.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
276.2 +++ b/src/glpssx02.c Mon Dec 06 13:09:21 2010 +0100
276.3 @@ -0,0 +1,479 @@
276.4 +/* glpssx02.c */
276.5 +
276.6 +/***********************************************************************
276.7 +* This code is part of GLPK (GNU Linear Programming Kit).
276.8 +*
276.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
276.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
276.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
276.12 +* E-mail: <mao@gnu.org>.
276.13 +*
276.14 +* GLPK is free software: you can redistribute it and/or modify it
276.15 +* under the terms of the GNU General Public License as published by
276.16 +* the Free Software Foundation, either version 3 of the License, or
276.17 +* (at your option) any later version.
276.18 +*
276.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
276.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
276.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
276.22 +* License for more details.
276.23 +*
276.24 +* You should have received a copy of the GNU General Public License
276.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
276.26 +***********************************************************************/
276.27 +
276.28 +#include "glpenv.h"
276.29 +#include "glpssx.h"
276.30 +
276.31 +static void show_progress(SSX *ssx, int phase)
276.32 +{ /* this auxiliary routine displays information about progress of
276.33 + the search */
276.34 + int i, def = 0;
276.35 + for (i = 1; i <= ssx->m; i++)
276.36 + if (ssx->type[ssx->Q_col[i]] == SSX_FX) def++;
276.37 + xprintf("%s%6d: %s = %22.15g (%d)\n", phase == 1 ? " " : "*",
276.38 + ssx->it_cnt, phase == 1 ? "infsum" : "objval",
276.39 + mpq_get_d(ssx->bbar[0]), def);
276.40 +#if 0
276.41 + ssx->tm_lag = utime();
276.42 +#else
276.43 + ssx->tm_lag = xtime();
276.44 +#endif
276.45 + return;
276.46 +}
276.47 +
276.48 +/*----------------------------------------------------------------------
276.49 +// ssx_phase_I - find primal feasible solution.
276.50 +//
276.51 +// This routine implements phase I of the primal simplex method.
276.52 +//
276.53 +// On exit the routine returns one of the following codes:
276.54 +//
276.55 +// 0 - feasible solution found;
276.56 +// 1 - problem has no feasible solution;
276.57 +// 2 - iterations limit exceeded;
276.58 +// 3 - time limit exceeded.
276.59 +----------------------------------------------------------------------*/
276.60 +
276.61 +int ssx_phase_I(SSX *ssx)
276.62 +{ int m = ssx->m;
276.63 + int n = ssx->n;
276.64 + int *type = ssx->type;
276.65 + mpq_t *lb = ssx->lb;
276.66 + mpq_t *ub = ssx->ub;
276.67 + mpq_t *coef = ssx->coef;
276.68 + int *A_ptr = ssx->A_ptr;
276.69 + int *A_ind = ssx->A_ind;
276.70 + mpq_t *A_val = ssx->A_val;
276.71 + int *Q_col = ssx->Q_col;
276.72 + mpq_t *bbar = ssx->bbar;
276.73 + mpq_t *pi = ssx->pi;
276.74 + mpq_t *cbar = ssx->cbar;
276.75 + int *orig_type, orig_dir;
276.76 + mpq_t *orig_lb, *orig_ub, *orig_coef;
276.77 + int i, k, ret;
276.78 + /* save components of the original LP problem, which are changed
276.79 + by the routine */
276.80 + orig_type = xcalloc(1+m+n, sizeof(int));
276.81 + orig_lb = xcalloc(1+m+n, sizeof(mpq_t));
276.82 + orig_ub = xcalloc(1+m+n, sizeof(mpq_t));
276.83 + orig_coef = xcalloc(1+m+n, sizeof(mpq_t));
276.84 + for (k = 1; k <= m+n; k++)
276.85 + { orig_type[k] = type[k];
276.86 + mpq_init(orig_lb[k]);
276.87 + mpq_set(orig_lb[k], lb[k]);
276.88 + mpq_init(orig_ub[k]);
276.89 + mpq_set(orig_ub[k], ub[k]);
276.90 + }
276.91 + orig_dir = ssx->dir;
276.92 + for (k = 0; k <= m+n; k++)
276.93 + { mpq_init(orig_coef[k]);
276.94 + mpq_set(orig_coef[k], coef[k]);
276.95 + }
276.96 + /* build an artificial basic solution, which is primal feasible,
276.97 + and also build an auxiliary objective function to minimize the
276.98 + sum of infeasibilities for the original problem */
276.99 + ssx->dir = SSX_MIN;
276.100 + for (k = 0; k <= m+n; k++) mpq_set_si(coef[k], 0, 1);
276.101 + mpq_set_si(bbar[0], 0, 1);
276.102 + for (i = 1; i <= m; i++)
276.103 + { int t;
276.104 + k = Q_col[i]; /* x[k] = xB[i] */
276.105 + t = type[k];
276.106 + if (t == SSX_LO || t == SSX_DB || t == SSX_FX)
276.107 + { /* in the original problem x[k] has lower bound */
276.108 + if (mpq_cmp(bbar[i], lb[k]) < 0)
276.109 + { /* which is violated */
276.110 + type[k] = SSX_UP;
276.111 + mpq_set(ub[k], lb[k]);
276.112 + mpq_set_si(lb[k], 0, 1);
276.113 + mpq_set_si(coef[k], -1, 1);
276.114 + mpq_add(bbar[0], bbar[0], ub[k]);
276.115 + mpq_sub(bbar[0], bbar[0], bbar[i]);
276.116 + }
276.117 + }
276.118 + if (t == SSX_UP || t == SSX_DB || t == SSX_FX)
276.119 + { /* in the original problem x[k] has upper bound */
276.120 + if (mpq_cmp(bbar[i], ub[k]) > 0)
276.121 + { /* which is violated */
276.122 + type[k] = SSX_LO;
276.123 + mpq_set(lb[k], ub[k]);
276.124 + mpq_set_si(ub[k], 0, 1);
276.125 + mpq_set_si(coef[k], +1, 1);
276.126 + mpq_add(bbar[0], bbar[0], bbar[i]);
276.127 + mpq_sub(bbar[0], bbar[0], lb[k]);
276.128 + }
276.129 + }
276.130 + }
276.131 + /* now the initial basic solution should be primal feasible due
276.132 + to changes of bounds of some basic variables, which turned to
276.133 + implicit artifical variables */
276.134 + /* compute simplex multipliers and reduced costs */
276.135 + ssx_eval_pi(ssx);
276.136 + ssx_eval_cbar(ssx);
276.137 + /* display initial progress of the search */
276.138 + show_progress(ssx, 1);
276.139 + /* main loop starts here */
276.140 + for (;;)
276.141 + { /* display current progress of the search */
276.142 +#if 0
276.143 + if (utime() - ssx->tm_lag >= ssx->out_frq - 0.001)
276.144 +#else
276.145 + if (xdifftime(xtime(), ssx->tm_lag) >= ssx->out_frq - 0.001)
276.146 +#endif
276.147 + show_progress(ssx, 1);
276.148 + /* we do not need to wait until all artificial variables have
276.149 + left the basis */
276.150 + if (mpq_sgn(bbar[0]) == 0)
276.151 + { /* the sum of infeasibilities is zero, therefore the current
276.152 + solution is primal feasible for the original problem */
276.153 + ret = 0;
276.154 + break;
276.155 + }
276.156 + /* check if the iterations limit has been exhausted */
276.157 + if (ssx->it_lim == 0)
276.158 + { ret = 2;
276.159 + break;
276.160 + }
276.161 + /* check if the time limit has been exhausted */
276.162 +#if 0
276.163 + if (ssx->tm_lim >= 0.0 && ssx->tm_lim <= utime() - ssx->tm_beg)
276.164 +#else
276.165 + if (ssx->tm_lim >= 0.0 &&
276.166 + ssx->tm_lim <= xdifftime(xtime(), ssx->tm_beg))
276.167 +#endif
276.168 + { ret = 3;
276.169 + break;
276.170 + }
276.171 + /* choose non-basic variable xN[q] */
276.172 + ssx_chuzc(ssx);
276.173 + /* if xN[q] cannot be chosen, the sum of infeasibilities is
276.174 + minimal but non-zero; therefore the original problem has no
276.175 + primal feasible solution */
276.176 + if (ssx->q == 0)
276.177 + { ret = 1;
276.178 + break;
276.179 + }
276.180 + /* compute q-th column of the simplex table */
276.181 + ssx_eval_col(ssx);
276.182 + /* choose basic variable xB[p] */
276.183 + ssx_chuzr(ssx);
276.184 + /* the sum of infeasibilities cannot be negative, therefore
276.185 + the auxiliary lp problem cannot have unbounded solution */
276.186 + xassert(ssx->p != 0);
276.187 + /* update values of basic variables */
276.188 + ssx_update_bbar(ssx);
276.189 + if (ssx->p > 0)
276.190 + { /* compute p-th row of the inverse inv(B) */
276.191 + ssx_eval_rho(ssx);
276.192 + /* compute p-th row of the simplex table */
276.193 + ssx_eval_row(ssx);
276.194 + xassert(mpq_cmp(ssx->aq[ssx->p], ssx->ap[ssx->q]) == 0);
276.195 + /* update simplex multipliers */
276.196 + ssx_update_pi(ssx);
276.197 + /* update reduced costs of non-basic variables */
276.198 + ssx_update_cbar(ssx);
276.199 + }
276.200 + /* xB[p] is leaving the basis; if it is implicit artificial
276.201 + variable, the corresponding residual vanishes; therefore
276.202 + bounds of this variable should be restored to the original
276.203 + values */
276.204 + if (ssx->p > 0)
276.205 + { k = Q_col[ssx->p]; /* x[k] = xB[p] */
276.206 + if (type[k] != orig_type[k])
276.207 + { /* x[k] is implicit artificial variable */
276.208 + type[k] = orig_type[k];
276.209 + mpq_set(lb[k], orig_lb[k]);
276.210 + mpq_set(ub[k], orig_ub[k]);
276.211 + xassert(ssx->p_stat == SSX_NL || ssx->p_stat == SSX_NU);
276.212 + ssx->p_stat = (ssx->p_stat == SSX_NL ? SSX_NU : SSX_NL);
276.213 + if (type[k] == SSX_FX) ssx->p_stat = SSX_NS;
276.214 + /* nullify the objective coefficient at x[k] */
276.215 + mpq_set_si(coef[k], 0, 1);
276.216 + /* since coef[k] has been changed, we need to compute
276.217 + new reduced cost of x[k], which it will have in the
276.218 + adjacent basis */
276.219 + /* the formula d[j] = cN[j] - pi' * N[j] is used (note
276.220 + that the vector pi is not changed, because it depends
276.221 + on objective coefficients at basic variables, but in
276.222 + the adjacent basis, for which the vector pi has been
276.223 + just recomputed, x[k] is non-basic) */
276.224 + if (k <= m)
276.225 + { /* x[k] is auxiliary variable */
276.226 + mpq_neg(cbar[ssx->q], pi[k]);
276.227 + }
276.228 + else
276.229 + { /* x[k] is structural variable */
276.230 + int ptr;
276.231 + mpq_t temp;
276.232 + mpq_init(temp);
276.233 + mpq_set_si(cbar[ssx->q], 0, 1);
276.234 + for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
276.235 + { mpq_mul(temp, pi[A_ind[ptr]], A_val[ptr]);
276.236 + mpq_add(cbar[ssx->q], cbar[ssx->q], temp);
276.237 + }
276.238 + mpq_clear(temp);
276.239 + }
276.240 + }
276.241 + }
276.242 + /* jump to the adjacent vertex of the polyhedron */
276.243 + ssx_change_basis(ssx);
276.244 + /* one simplex iteration has been performed */
276.245 + if (ssx->it_lim > 0) ssx->it_lim--;
276.246 + ssx->it_cnt++;
276.247 + }
276.248 + /* display final progress of the search */
276.249 + show_progress(ssx, 1);
276.250 + /* restore components of the original problem, which were changed
276.251 + by the routine */
276.252 + for (k = 1; k <= m+n; k++)
276.253 + { type[k] = orig_type[k];
276.254 + mpq_set(lb[k], orig_lb[k]);
276.255 + mpq_clear(orig_lb[k]);
276.256 + mpq_set(ub[k], orig_ub[k]);
276.257 + mpq_clear(orig_ub[k]);
276.258 + }
276.259 + ssx->dir = orig_dir;
276.260 + for (k = 0; k <= m+n; k++)
276.261 + { mpq_set(coef[k], orig_coef[k]);
276.262 + mpq_clear(orig_coef[k]);
276.263 + }
276.264 + xfree(orig_type);
276.265 + xfree(orig_lb);
276.266 + xfree(orig_ub);
276.267 + xfree(orig_coef);
276.268 + /* return to the calling program */
276.269 + return ret;
276.270 +}
276.271 +
276.272 +/*----------------------------------------------------------------------
276.273 +// ssx_phase_II - find optimal solution.
276.274 +//
276.275 +// This routine implements phase II of the primal simplex method.
276.276 +//
276.277 +// On exit the routine returns one of the following codes:
276.278 +//
276.279 +// 0 - optimal solution found;
276.280 +// 1 - problem has unbounded solution;
276.281 +// 2 - iterations limit exceeded;
276.282 +// 3 - time limit exceeded.
276.283 +----------------------------------------------------------------------*/
276.284 +
276.285 +int ssx_phase_II(SSX *ssx)
276.286 +{ int ret;
276.287 + /* display initial progress of the search */
276.288 + show_progress(ssx, 2);
276.289 + /* main loop starts here */
276.290 + for (;;)
276.291 + { /* display current progress of the search */
276.292 +#if 0
276.293 + if (utime() - ssx->tm_lag >= ssx->out_frq - 0.001)
276.294 +#else
276.295 + if (xdifftime(xtime(), ssx->tm_lag) >= ssx->out_frq - 0.001)
276.296 +#endif
276.297 + show_progress(ssx, 2);
276.298 + /* check if the iterations limit has been exhausted */
276.299 + if (ssx->it_lim == 0)
276.300 + { ret = 2;
276.301 + break;
276.302 + }
276.303 + /* check if the time limit has been exhausted */
276.304 +#if 0
276.305 + if (ssx->tm_lim >= 0.0 && ssx->tm_lim <= utime() - ssx->tm_beg)
276.306 +#else
276.307 + if (ssx->tm_lim >= 0.0 &&
276.308 + ssx->tm_lim <= xdifftime(xtime(), ssx->tm_beg))
276.309 +#endif
276.310 + { ret = 3;
276.311 + break;
276.312 + }
276.313 + /* choose non-basic variable xN[q] */
276.314 + ssx_chuzc(ssx);
276.315 + /* if xN[q] cannot be chosen, the current basic solution is
276.316 + dual feasible and therefore optimal */
276.317 + if (ssx->q == 0)
276.318 + { ret = 0;
276.319 + break;
276.320 + }
276.321 + /* compute q-th column of the simplex table */
276.322 + ssx_eval_col(ssx);
276.323 + /* choose basic variable xB[p] */
276.324 + ssx_chuzr(ssx);
276.325 + /* if xB[p] cannot be chosen, the problem has no dual feasible
276.326 + solution (i.e. unbounded) */
276.327 + if (ssx->p == 0)
276.328 + { ret = 1;
276.329 + break;
276.330 + }
276.331 + /* update values of basic variables */
276.332 + ssx_update_bbar(ssx);
276.333 + if (ssx->p > 0)
276.334 + { /* compute p-th row of the inverse inv(B) */
276.335 + ssx_eval_rho(ssx);
276.336 + /* compute p-th row of the simplex table */
276.337 + ssx_eval_row(ssx);
276.338 + xassert(mpq_cmp(ssx->aq[ssx->p], ssx->ap[ssx->q]) == 0);
276.339 +#if 0
276.340 + /* update simplex multipliers */
276.341 + ssx_update_pi(ssx);
276.342 +#endif
276.343 + /* update reduced costs of non-basic variables */
276.344 + ssx_update_cbar(ssx);
276.345 + }
276.346 + /* jump to the adjacent vertex of the polyhedron */
276.347 + ssx_change_basis(ssx);
276.348 + /* one simplex iteration has been performed */
276.349 + if (ssx->it_lim > 0) ssx->it_lim--;
276.350 + ssx->it_cnt++;
276.351 + }
276.352 + /* display final progress of the search */
276.353 + show_progress(ssx, 2);
276.354 + /* return to the calling program */
276.355 + return ret;
276.356 +}
276.357 +
276.358 +/*----------------------------------------------------------------------
276.359 +// ssx_driver - base driver to exact simplex method.
276.360 +//
276.361 +// This routine is a base driver to a version of the primal simplex
276.362 +// method using exact (bignum) arithmetic.
276.363 +//
276.364 +// On exit the routine returns one of the following codes:
276.365 +//
276.366 +// 0 - optimal solution found;
276.367 +// 1 - problem has no feasible solution;
276.368 +// 2 - problem has unbounded solution;
276.369 +// 3 - iterations limit exceeded (phase I);
276.370 +// 4 - iterations limit exceeded (phase II);
276.371 +// 5 - time limit exceeded (phase I);
276.372 +// 6 - time limit exceeded (phase II);
276.373 +// 7 - initial basis matrix is exactly singular.
276.374 +----------------------------------------------------------------------*/
276.375 +
276.376 +int ssx_driver(SSX *ssx)
276.377 +{ int m = ssx->m;
276.378 + int *type = ssx->type;
276.379 + mpq_t *lb = ssx->lb;
276.380 + mpq_t *ub = ssx->ub;
276.381 + int *Q_col = ssx->Q_col;
276.382 + mpq_t *bbar = ssx->bbar;
276.383 + int i, k, ret;
276.384 + ssx->tm_beg = xtime();
276.385 + /* factorize the initial basis matrix */
276.386 + if (ssx_factorize(ssx))
276.387 + { xprintf("Initial basis matrix is singular\n");
276.388 + ret = 7;
276.389 + goto done;
276.390 + }
276.391 + /* compute values of basic variables */
276.392 + ssx_eval_bbar(ssx);
276.393 + /* check if the initial basic solution is primal feasible */
276.394 + for (i = 1; i <= m; i++)
276.395 + { int t;
276.396 + k = Q_col[i]; /* x[k] = xB[i] */
276.397 + t = type[k];
276.398 + if (t == SSX_LO || t == SSX_DB || t == SSX_FX)
276.399 + { /* x[k] has lower bound */
276.400 + if (mpq_cmp(bbar[i], lb[k]) < 0)
276.401 + { /* which is violated */
276.402 + break;
276.403 + }
276.404 + }
276.405 + if (t == SSX_UP || t == SSX_DB || t == SSX_FX)
276.406 + { /* x[k] has upper bound */
276.407 + if (mpq_cmp(bbar[i], ub[k]) > 0)
276.408 + { /* which is violated */
276.409 + break;
276.410 + }
276.411 + }
276.412 + }
276.413 + if (i > m)
276.414 + { /* no basic variable violates its bounds */
276.415 + ret = 0;
276.416 + goto skip;
276.417 + }
276.418 + /* phase I: find primal feasible solution */
276.419 + ret = ssx_phase_I(ssx);
276.420 + switch (ret)
276.421 + { case 0:
276.422 + ret = 0;
276.423 + break;
276.424 + case 1:
276.425 + xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n");
276.426 + ret = 1;
276.427 + break;
276.428 + case 2:
276.429 + xprintf("ITERATIONS LIMIT EXCEEDED; SEARCH TERMINATED\n");
276.430 + ret = 3;
276.431 + break;
276.432 + case 3:
276.433 + xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
276.434 + ret = 5;
276.435 + break;
276.436 + default:
276.437 + xassert(ret != ret);
276.438 + }
276.439 + /* compute values of basic variables (actually only the objective
276.440 + value needs to be computed) */
276.441 + ssx_eval_bbar(ssx);
276.442 +skip: /* compute simplex multipliers */
276.443 + ssx_eval_pi(ssx);
276.444 + /* compute reduced costs of non-basic variables */
276.445 + ssx_eval_cbar(ssx);
276.446 + /* if phase I failed, do not start phase II */
276.447 + if (ret != 0) goto done;
276.448 + /* phase II: find optimal solution */
276.449 + ret = ssx_phase_II(ssx);
276.450 + switch (ret)
276.451 + { case 0:
276.452 + xprintf("OPTIMAL SOLUTION FOUND\n");
276.453 + ret = 0;
276.454 + break;
276.455 + case 1:
276.456 + xprintf("PROBLEM HAS UNBOUNDED SOLUTION\n");
276.457 + ret = 2;
276.458 + break;
276.459 + case 2:
276.460 + xprintf("ITERATIONS LIMIT EXCEEDED; SEARCH TERMINATED\n");
276.461 + ret = 4;
276.462 + break;
276.463 + case 3:
276.464 + xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
276.465 + ret = 6;
276.466 + break;
276.467 + default:
276.468 + xassert(ret != ret);
276.469 + }
276.470 +done: /* decrease the time limit by the spent amount of time */
276.471 + if (ssx->tm_lim >= 0.0)
276.472 +#if 0
276.473 + { ssx->tm_lim -= utime() - ssx->tm_beg;
276.474 +#else
276.475 + { ssx->tm_lim -= xdifftime(xtime(), ssx->tm_beg);
276.476 +#endif
276.477 + if (ssx->tm_lim < 0.0) ssx->tm_lim = 0.0;
276.478 + }
276.479 + return ret;
276.480 +}
276.481 +
276.482 +/* eof */
277.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
277.2 +++ b/src/glpstd.h Mon Dec 06 13:09:21 2010 +0100
277.3 @@ -0,0 +1,43 @@
277.4 +/* glpstd.h (standard C headers) */
277.5 +
277.6 +/***********************************************************************
277.7 +* This code is part of GLPK (GNU Linear Programming Kit).
277.8 +*
277.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
277.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
277.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
277.12 +* E-mail: <mao@gnu.org>.
277.13 +*
277.14 +* GLPK is free software: you can redistribute it and/or modify it
277.15 +* under the terms of the GNU General Public License as published by
277.16 +* the Free Software Foundation, either version 3 of the License, or
277.17 +* (at your option) any later version.
277.18 +*
277.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
277.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
277.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
277.22 +* License for more details.
277.23 +*
277.24 +* You should have received a copy of the GNU General Public License
277.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
277.26 +***********************************************************************/
277.27 +
277.28 +#ifndef GLPSTD_H
277.29 +#define GLPSTD_H
277.30 +
277.31 +#include <ctype.h>
277.32 +#include <errno.h>
277.33 +#include <float.h>
277.34 +#include <limits.h>
277.35 +#include <math.h>
277.36 +#include <setjmp.h>
277.37 +#include <stdarg.h>
277.38 +#include <stddef.h>
277.39 +#include <stdio.h>
277.40 +#include <stdlib.h>
277.41 +#include <string.h>
277.42 +#include <time.h>
277.43 +
277.44 +#endif
277.45 +
277.46 +/* eof */
278.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
278.2 +++ b/src/glptsp.c Mon Dec 06 13:09:21 2010 +0100
278.3 @@ -0,0 +1,667 @@
278.4 +/* glptsp.c */
278.5 +
278.6 +/***********************************************************************
278.7 +* This code is part of GLPK (GNU Linear Programming Kit).
278.8 +*
278.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
278.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
278.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
278.12 +* E-mail: <mao@gnu.org>.
278.13 +*
278.14 +* GLPK is free software: you can redistribute it and/or modify it
278.15 +* under the terms of the GNU General Public License as published by
278.16 +* the Free Software Foundation, either version 3 of the License, or
278.17 +* (at your option) any later version.
278.18 +*
278.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
278.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
278.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
278.22 +* License for more details.
278.23 +*
278.24 +* You should have received a copy of the GNU General Public License
278.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
278.26 +***********************************************************************/
278.27 +
278.28 +#define _GLPSTD_ERRNO
278.29 +#define _GLPSTD_STDIO
278.30 +#include "glpenv.h"
278.31 +#include "glptsp.h"
278.32 +#define xfault xerror
278.33 +
278.34 +/*----------------------------------------------------------------------
278.35 +-- tsp_read_data - read TSP instance data.
278.36 +--
278.37 +-- *Synopsis*
278.38 +--
278.39 +-- #include "glptsp.h"
278.40 +-- TSP *tsp_read_data(char *fname);
278.41 +--
278.42 +-- *Description*
278.43 +--
278.44 +-- The routine tsp_read_data reads a TSP (or related problem) instance
278.45 +-- data from the text file, whose name is the character string fname.
278.46 +--
278.47 +-- For detailed description of the format recognized by the routine see
278.48 +-- the report: G.Reinelt, TSPLIB 95.
278.49 +--
278.50 +-- *Returns*
278.51 +--
278.52 +-- If no error occurred, the routine tsp_read_data returns a pointer to
278.53 +-- the TSP instance data block, which contains loaded data. In the case
278.54 +-- of error the routine prints an error message and returns NULL. */
278.55 +
278.56 +struct dsa
278.57 +{ /* dynamic storage area used by the routine tsp_read_data */
278.58 + char *fname;
278.59 + /* name of the input text file */
278.60 + FILE *fp;
278.61 + /* stream assigned to the input text file */
278.62 + int seqn;
278.63 + /* line sequential number */
278.64 + int c;
278.65 + /* current character */
278.66 + char token[255+1];
278.67 + /* current token */
278.68 +};
278.69 +
278.70 +static int get_char(struct dsa *dsa)
278.71 +{ dsa->c = fgetc(dsa->fp);
278.72 + if (ferror(dsa->fp))
278.73 + { xprintf("%s:%d: read error - %s\n",
278.74 + dsa->fname, dsa->seqn, strerror(errno));
278.75 + return 1;
278.76 + }
278.77 + if (feof(dsa->fp))
278.78 + dsa->c = EOF;
278.79 + else if (dsa->c == '\n')
278.80 + dsa->seqn++;
278.81 + else if (isspace(dsa->c))
278.82 + dsa->c = ' ';
278.83 + else if (iscntrl(dsa->c))
278.84 + { xprintf("%s:%d: invalid control character 0x%02X\n",
278.85 + dsa->fname, dsa->seqn, dsa->c);
278.86 + return 1;
278.87 + }
278.88 + return 0;
278.89 +}
278.90 +
278.91 +static int skip_spaces(struct dsa *dsa, int across)
278.92 +{ while (dsa->c == ' ' || (across && dsa->c == '\n'))
278.93 + if (get_char(dsa)) return 1;
278.94 + return 0;
278.95 +}
278.96 +
278.97 +static int scan_keyword(struct dsa *dsa)
278.98 +{ int len = 0;
278.99 + if (skip_spaces(dsa, 0)) return 1;
278.100 + dsa->token[0] = '\0';
278.101 + while (isalnum(dsa->c) || dsa->c == '_')
278.102 + { if (len == 31)
278.103 + { xprintf("%s:%d: keyword `%s...' too long\n", dsa->fname,
278.104 + dsa->seqn, dsa->token);
278.105 + return 1;
278.106 + }
278.107 + dsa->token[len++] = (char)dsa->c, dsa->token[len] = '\0';
278.108 + if (get_char(dsa)) return 1;
278.109 + }
278.110 + if (len == 0)
278.111 + { xprintf("%s:%d: missing keyword\n", dsa->fname, dsa->seqn);
278.112 + return 1;
278.113 + }
278.114 + return 0;
278.115 +}
278.116 +
278.117 +static int check_colon(struct dsa *dsa)
278.118 +{ if (skip_spaces(dsa, 0)) return 1;
278.119 + if (dsa->c != ':')
278.120 + { xprintf("%s:%d: missing colon after `%s'\n", dsa->fname,
278.121 + dsa->seqn, dsa->token);
278.122 + return 1;
278.123 + }
278.124 + if (get_char(dsa)) return 1;
278.125 + return 0;
278.126 +}
278.127 +
278.128 +static int scan_token(struct dsa *dsa, int across)
278.129 +{ int len = 0;
278.130 + if (skip_spaces(dsa, across)) return 1;
278.131 + dsa->token[0] = '\0';
278.132 + while (!(dsa->c == EOF || dsa->c == '\n' || dsa->c == ' '))
278.133 + { if (len == 255)
278.134 + { dsa->token[31] = '\0';
278.135 + xprintf("%s:%d: token `%s...' too long\n", dsa->fname,
278.136 + dsa->seqn, dsa->token);
278.137 + return 1;
278.138 + }
278.139 + dsa->token[len++] = (char)dsa->c, dsa->token[len] = '\0';
278.140 + if (get_char(dsa)) return 1;
278.141 + }
278.142 + return 0;
278.143 +}
278.144 +
278.145 +static int check_newline(struct dsa *dsa)
278.146 +{ if (skip_spaces(dsa, 0)) return 1;
278.147 + if (!(dsa->c == EOF || dsa->c == '\n'))
278.148 + { xprintf("%s:%d: extra symbols detected\n", dsa->fname,
278.149 + dsa->seqn);
278.150 + return 1;
278.151 + }
278.152 + if (get_char(dsa)) return 1;
278.153 + return 0;
278.154 +}
278.155 +
278.156 +static int scan_comment(struct dsa *dsa)
278.157 +{ int len = 0;
278.158 + if (skip_spaces(dsa, 0)) return 1;
278.159 + dsa->token[0] = '\0';
278.160 + while (!(dsa->c == EOF || dsa->c == '\n'))
278.161 + { if (len == 255)
278.162 + { xprintf("%s:%d: comment too long\n", dsa->fname, dsa->seqn)
278.163 + ;
278.164 + return 1;
278.165 + }
278.166 + dsa->token[len++] = (char)dsa->c, dsa->token[len] = '\0';
278.167 + if (get_char(dsa)) return 1;
278.168 + }
278.169 + return 0;
278.170 +}
278.171 +
278.172 +static int scan_integer(struct dsa *dsa, int across, int *val)
278.173 +{ if (scan_token(dsa, across)) return 1;
278.174 + if (strlen(dsa->token) == 0)
278.175 + { xprintf("%s:%d: missing integer\n", dsa->fname, dsa->seqn);
278.176 + return 1;
278.177 + }
278.178 + if (str2int(dsa->token, val))
278.179 + { xprintf("%s:%d: integer `%s' invalid\n", dsa->fname, dsa->seqn
278.180 + , dsa->token);
278.181 + return 1;
278.182 + }
278.183 + return 0;
278.184 +}
278.185 +
278.186 +static int scan_number(struct dsa *dsa, int across, double *val)
278.187 +{ if (scan_token(dsa, across)) return 1;
278.188 + if (strlen(dsa->token) == 0)
278.189 + { xprintf("%s:%d: missing number\n", dsa->fname, dsa->seqn);
278.190 + return 1;
278.191 + }
278.192 + if (str2num(dsa->token, val))
278.193 + { xprintf("%s:%d: number `%s' invalid\n", dsa->fname, dsa->seqn,
278.194 + dsa->token);
278.195 + return 1;
278.196 + }
278.197 + return 0;
278.198 +}
278.199 +
278.200 +TSP *tsp_read_data(char *fname)
278.201 +{ struct dsa _dsa, *dsa = &_dsa;
278.202 + TSP *tsp = NULL;
278.203 + dsa->fname = fname;
278.204 + xprintf("tsp_read_data: reading TSP data from `%s'...\n",
278.205 + dsa->fname);
278.206 + dsa->fp = fopen(dsa->fname, "r");
278.207 + if (dsa->fp == NULL)
278.208 + { xprintf("tsp_read_data: unable to open `%s' - %s\n",
278.209 + dsa->fname, strerror(errno));
278.210 + goto fail;
278.211 + }
278.212 + tsp = xmalloc(sizeof(TSP));
278.213 + tsp->name = NULL;
278.214 + tsp->type = TSP_UNDEF;
278.215 + tsp->comment = NULL;
278.216 + tsp->dimension = 0;
278.217 + tsp->edge_weight_type = TSP_UNDEF;
278.218 + tsp->edge_weight_format = TSP_UNDEF;
278.219 + tsp->display_data_type = TSP_UNDEF;
278.220 + tsp->node_x_coord = NULL;
278.221 + tsp->node_y_coord = NULL;
278.222 + tsp->dply_x_coord = NULL;
278.223 + tsp->dply_y_coord = NULL;
278.224 + tsp->tour = NULL;
278.225 + tsp->edge_weight = NULL;
278.226 + dsa->seqn = 1;
278.227 + if (get_char(dsa)) goto fail;
278.228 +loop: if (scan_keyword(dsa)) goto fail;
278.229 + if (strcmp(dsa->token, "NAME") == 0)
278.230 + { if (tsp->name != NULL)
278.231 + { xprintf("%s:%d: NAME entry multiply defined\n", dsa->fname,
278.232 + dsa->seqn);
278.233 + goto fail;
278.234 + }
278.235 + if (check_colon(dsa)) goto fail;
278.236 + if (scan_token(dsa, 0)) goto fail;
278.237 + if (strlen(dsa->token) == 0)
278.238 + { xprintf("%s:%d: NAME entry incomplete\n", dsa->fname,
278.239 + dsa->seqn);
278.240 + goto fail;
278.241 + }
278.242 + tsp->name = xmalloc(strlen(dsa->token) + 1);
278.243 + strcpy(tsp->name, dsa->token);
278.244 + xprintf("tsp_read_data: NAME: %s\n", tsp->name);
278.245 + if (check_newline(dsa)) goto fail;
278.246 + }
278.247 + else if (strcmp(dsa->token, "TYPE") == 0)
278.248 + { if (tsp->type != TSP_UNDEF)
278.249 + { xprintf("%s:%d: TYPE entry multiply defined\n", dsa->fname,
278.250 + dsa->seqn);
278.251 + goto fail;
278.252 + }
278.253 + if (check_colon(dsa)) goto fail;
278.254 + if (scan_keyword(dsa)) goto fail;
278.255 + if (strcmp(dsa->token, "TSP") == 0)
278.256 + tsp->type = TSP_TSP;
278.257 + else if (strcmp(dsa->token, "ATSP") == 0)
278.258 + tsp->type = TSP_ATSP;
278.259 + else if (strcmp(dsa->token, "TOUR") == 0)
278.260 + tsp->type = TSP_TOUR;
278.261 + else
278.262 + { xprintf("%s:%d: data type `%s' not recognized\n",
278.263 + dsa->fname, dsa->seqn, dsa->token);
278.264 + goto fail;
278.265 + }
278.266 + xprintf("tsp_read_data: TYPE: %s\n", dsa->token);
278.267 + if (check_newline(dsa)) goto fail;
278.268 + }
278.269 + else if (strcmp(dsa->token, "COMMENT") == 0)
278.270 + { if (tsp->comment != NULL)
278.271 + { xprintf("%s:%d: COMMENT entry multiply defined\n",
278.272 + dsa->fname, dsa->seqn);
278.273 + goto fail;
278.274 + }
278.275 + if (check_colon(dsa)) goto fail;
278.276 + if (scan_comment(dsa)) goto fail;
278.277 + tsp->comment = xmalloc(strlen(dsa->token) + 1);
278.278 + strcpy(tsp->comment, dsa->token);
278.279 + xprintf("tsp_read_data: COMMENT: %s\n", tsp->comment);
278.280 + if (check_newline(dsa)) goto fail;
278.281 + }
278.282 + else if (strcmp(dsa->token, "DIMENSION") == 0)
278.283 + { if (tsp->dimension != 0)
278.284 + { xprintf("%s:%d: DIMENSION entry multiply defined\n",
278.285 + dsa->fname, dsa->seqn);
278.286 + goto fail;
278.287 + }
278.288 + if (check_colon(dsa)) goto fail;
278.289 + if (scan_integer(dsa, 0, &tsp->dimension)) goto fail;
278.290 + if (tsp->dimension < 1)
278.291 + { xprintf("%s:%d: invalid dimension\n", dsa->fname,
278.292 + dsa->seqn);
278.293 + goto fail;
278.294 + }
278.295 + xprintf("tsp_read_data: DIMENSION: %d\n", tsp->dimension);
278.296 + if (check_newline(dsa)) goto fail;
278.297 + }
278.298 + else if (strcmp(dsa->token, "EDGE_WEIGHT_TYPE") == 0)
278.299 + { if (tsp->edge_weight_type != TSP_UNDEF)
278.300 + { xprintf("%s:%d: EDGE_WEIGHT_TYPE entry multiply defined\n",
278.301 + dsa->fname, dsa->seqn);
278.302 + goto fail;
278.303 + }
278.304 + if (check_colon(dsa)) goto fail;
278.305 + if (scan_keyword(dsa)) goto fail;
278.306 + if (strcmp(dsa->token, "GEO") == 0)
278.307 + tsp->edge_weight_type = TSP_GEO;
278.308 + else if (strcmp(dsa->token, "EUC_2D") == 0)
278.309 + tsp->edge_weight_type = TSP_EUC_2D;
278.310 + else if (strcmp(dsa->token, "ATT") == 0)
278.311 + tsp->edge_weight_type = TSP_ATT;
278.312 + else if (strcmp(dsa->token, "EXPLICIT") == 0)
278.313 + tsp->edge_weight_type = TSP_EXPLICIT;
278.314 + else if (strcmp(dsa->token, "CEIL_2D") == 0)
278.315 + tsp->edge_weight_type = TSP_CEIL_2D;
278.316 + else
278.317 + { xprintf("%s:%d: edge weight type `%s' not recognized\n",
278.318 + dsa->fname, dsa->seqn, dsa->token);
278.319 + goto fail;
278.320 + }
278.321 + xprintf("tsp_read_data: EDGE_WEIGHT_TYPE: %s\n", dsa->token);
278.322 + if (check_newline(dsa)) goto fail;
278.323 + }
278.324 + else if (strcmp(dsa->token, "EDGE_WEIGHT_FORMAT") == 0)
278.325 + { if (tsp->edge_weight_format != TSP_UNDEF)
278.326 + { xprintf(
278.327 + "%s:%d: EDGE_WEIGHT_FORMAT entry multiply defined\n",
278.328 + dsa->fname, dsa->seqn);
278.329 + goto fail;
278.330 + }
278.331 + if (check_colon(dsa)) goto fail;
278.332 + if (scan_keyword(dsa)) goto fail;
278.333 + if (strcmp(dsa->token, "UPPER_ROW") == 0)
278.334 + tsp->edge_weight_format = TSP_UPPER_ROW;
278.335 + else if (strcmp(dsa->token, "FULL_MATRIX") == 0)
278.336 + tsp->edge_weight_format = TSP_FULL_MATRIX;
278.337 + else if (strcmp(dsa->token, "FUNCTION") == 0)
278.338 + tsp->edge_weight_format = TSP_FUNCTION;
278.339 + else if (strcmp(dsa->token, "LOWER_DIAG_ROW") == 0)
278.340 + tsp->edge_weight_format = TSP_LOWER_DIAG_ROW;
278.341 + else
278.342 + { xprintf("%s:%d: edge weight format `%s' not recognized\n",
278.343 + dsa->fname, dsa->seqn, dsa->token);
278.344 + goto fail;
278.345 + }
278.346 + xprintf("tsp_read_data: EDGE_WEIGHT_FORMAT: %s\n", dsa->token);
278.347 + if (check_newline(dsa)) goto fail;
278.348 + }
278.349 + else if (strcmp(dsa->token, "DISPLAY_DATA_TYPE") == 0)
278.350 + { if (tsp->display_data_type != TSP_UNDEF)
278.351 + { xprintf("%s:%d: DISPLAY_DATA_TYPE entry multiply defined\n",
278.352 + dsa->fname, dsa->seqn);
278.353 + goto fail;
278.354 + }
278.355 + if (check_colon(dsa)) goto fail;
278.356 + if (scan_keyword(dsa)) goto fail;
278.357 + if (strcmp(dsa->token, "COORD_DISPLAY") == 0)
278.358 + tsp->display_data_type = TSP_COORD_DISPLAY;
278.359 + else if (strcmp(dsa->token, "TWOD_DISPLAY") == 0)
278.360 + tsp->display_data_type = TSP_TWOD_DISPLAY;
278.361 + else
278.362 + { xprintf("%s:%d: display data type `%s' not recognized\n",
278.363 + dsa->fname, dsa->seqn, dsa->token);
278.364 + goto fail;
278.365 + }
278.366 + xprintf("tsp_read_data: DISPLAY_DATA_TYPE: %s\n", dsa->token);
278.367 + if (check_newline(dsa)) goto fail;
278.368 + }
278.369 + else if (strcmp(dsa->token, "NODE_COORD_SECTION") == 0)
278.370 + { int n = tsp->dimension, k, node;
278.371 + if (n == 0)
278.372 + { xprintf("%s:%d: DIMENSION entry not specified\n",
278.373 + dsa->fname, dsa->seqn);
278.374 + goto fail;
278.375 + }
278.376 + if (tsp->node_x_coord != NULL)
278.377 + { xprintf("%s:%d: NODE_COORD_SECTION multiply specified\n",
278.378 + dsa->fname, dsa->seqn);
278.379 + goto fail;
278.380 + }
278.381 + if (check_newline(dsa)) goto fail;
278.382 + tsp->node_x_coord = xcalloc(1+n, sizeof(double));
278.383 + tsp->node_y_coord = xcalloc(1+n, sizeof(double));
278.384 + for (node = 1; node <= n; node++)
278.385 + tsp->node_x_coord[node] = tsp->node_y_coord[node] = DBL_MAX;
278.386 + for (k = 1; k <= n; k++)
278.387 + { if (scan_integer(dsa, 0, &node)) goto fail;
278.388 + if (!(1 <= node && node <= n))
278.389 + { xprintf("%s:%d: invalid node number %d\n", dsa->fname,
278.390 + dsa->seqn, node);
278.391 + goto fail;
278.392 + }
278.393 + if (tsp->node_x_coord[node] != DBL_MAX)
278.394 + { xprintf("%s:%d: node number %d multiply specified\n",
278.395 + dsa->fname, dsa->seqn, node);
278.396 + goto fail;
278.397 + }
278.398 + if (scan_number(dsa, 0, &tsp->node_x_coord[node]))
278.399 + goto fail;
278.400 + if (scan_number(dsa, 0, &tsp->node_y_coord[node]))
278.401 + goto fail;
278.402 + if (check_newline(dsa)) goto fail;
278.403 + }
278.404 + }
278.405 + else if (strcmp(dsa->token, "DISPLAY_DATA_SECTION") == 0)
278.406 + { int n = tsp->dimension, k, node;
278.407 + if (n == 0)
278.408 + { xprintf("%s:%d: DIMENSION entry not specified\n",
278.409 + dsa->fname, dsa->seqn);
278.410 + goto fail;
278.411 + }
278.412 + if (tsp->dply_x_coord != NULL)
278.413 + { xprintf("%s:%d: DISPLAY_DATA_SECTION multiply specified\n",
278.414 + dsa->fname, dsa->seqn);
278.415 + goto fail;
278.416 + }
278.417 + if (check_newline(dsa)) goto fail;
278.418 + tsp->dply_x_coord = xcalloc(1+n, sizeof(double));
278.419 + tsp->dply_y_coord = xcalloc(1+n, sizeof(double));
278.420 + for (node = 1; node <= n; node++)
278.421 + tsp->dply_x_coord[node] = tsp->dply_y_coord[node] = DBL_MAX;
278.422 + for (k = 1; k <= n; k++)
278.423 + { if (scan_integer(dsa, 0, &node)) goto fail;
278.424 + if (!(1 <= node && node <= n))
278.425 + { xprintf("%s:%d: invalid node number %d\n", dsa->fname,
278.426 + dsa->seqn, node);
278.427 + goto fail;
278.428 + }
278.429 + if (tsp->dply_x_coord[node] != DBL_MAX)
278.430 + { xprintf("%s:%d: node number %d multiply specified\n",
278.431 + dsa->fname, dsa->seqn, node);
278.432 + goto fail;
278.433 + }
278.434 + if (scan_number(dsa, 0, &tsp->dply_x_coord[node]))
278.435 + goto fail;
278.436 + if (scan_number(dsa, 0, &tsp->dply_y_coord[node]))
278.437 + goto fail;
278.438 + if (check_newline(dsa)) goto fail;
278.439 + }
278.440 + }
278.441 + else if (strcmp(dsa->token, "TOUR_SECTION") == 0)
278.442 + { int n = tsp->dimension, k, node;
278.443 + if (n == 0)
278.444 + { xprintf("%s:%d: DIMENSION entry not specified\n",
278.445 + dsa->fname, dsa->seqn);
278.446 + goto fail;
278.447 + }
278.448 + if (tsp->tour != NULL)
278.449 + { xprintf("%s:%d: TOUR_SECTION multiply specified\n",
278.450 + dsa->fname, dsa->seqn);
278.451 + goto fail;
278.452 + }
278.453 + if (check_newline(dsa)) goto fail;
278.454 + tsp->tour = xcalloc(1+n, sizeof(int));
278.455 + for (k = 1; k <= n; k++)
278.456 + { if (scan_integer(dsa, 1, &node)) goto fail;
278.457 + if (!(1 <= node && node <= n))
278.458 + { xprintf("%s:%d: invalid node number %d\n", dsa->fname,
278.459 + dsa->seqn, node);
278.460 + goto fail;
278.461 + }
278.462 + tsp->tour[k] = node;
278.463 + }
278.464 + if (scan_integer(dsa, 1, &node)) goto fail;
278.465 + if (node != -1)
278.466 + { xprintf("%s:%d: extra node(s) detected\n", dsa->fname,
278.467 + dsa->seqn);
278.468 + goto fail;
278.469 + }
278.470 + if (check_newline(dsa)) goto fail;
278.471 + }
278.472 + else if (strcmp(dsa->token, "EDGE_WEIGHT_SECTION") == 0)
278.473 + { int n = tsp->dimension, i, j, temp;
278.474 + if (n == 0)
278.475 + { xprintf("%s:%d: DIMENSION entry not specified\n",
278.476 + dsa->fname, dsa->seqn);
278.477 + goto fail;
278.478 + }
278.479 + if (tsp->edge_weight_format == TSP_UNDEF)
278.480 + { xprintf("%s:%d: EDGE_WEIGHT_FORMAT entry not specified\n",
278.481 + dsa->fname, dsa->seqn);
278.482 + goto fail;
278.483 + }
278.484 + if (tsp->edge_weight != NULL)
278.485 + { xprintf("%s:%d: EDGE_WEIGHT_SECTION multiply specified\n",
278.486 + dsa->fname, dsa->seqn);
278.487 + goto fail;
278.488 + }
278.489 + if (check_newline(dsa)) goto fail;
278.490 + tsp->edge_weight = xcalloc(1+n*n, sizeof(int));
278.491 + switch (tsp->edge_weight_format)
278.492 + { case TSP_FULL_MATRIX:
278.493 + for (i = 1; i <= n; i++)
278.494 + { for (j = 1; j <= n; j++)
278.495 + { if (scan_integer(dsa, 1, &temp)) goto fail;
278.496 + tsp->edge_weight[(i - 1) * n + j] = temp;
278.497 + }
278.498 + }
278.499 + break;
278.500 + case TSP_UPPER_ROW:
278.501 + for (i = 1; i <= n; i++)
278.502 + { tsp->edge_weight[(i - 1) * n + i] = 0;
278.503 + for (j = i + 1; j <= n; j++)
278.504 + { if (scan_integer(dsa, 1, &temp)) goto fail;
278.505 + tsp->edge_weight[(i - 1) * n + j] = temp;
278.506 + tsp->edge_weight[(j - 1) * n + i] = temp;
278.507 + }
278.508 + }
278.509 + break;
278.510 + case TSP_LOWER_DIAG_ROW:
278.511 + for (i = 1; i <= n; i++)
278.512 + { for (j = 1; j <= i; j++)
278.513 + { if (scan_integer(dsa, 1, &temp)) goto fail;
278.514 + tsp->edge_weight[(i - 1) * n + j] = temp;
278.515 + tsp->edge_weight[(j - 1) * n + i] = temp;
278.516 + }
278.517 + }
278.518 + break;
278.519 + default:
278.520 + goto fail;
278.521 + }
278.522 + if (check_newline(dsa)) goto fail;
278.523 + }
278.524 + else if (strcmp(dsa->token, "EOF") == 0)
278.525 + { if (check_newline(dsa)) goto fail;
278.526 + goto done;
278.527 + }
278.528 + else
278.529 + { xprintf("%s:%d: keyword `%s' not recognized\n", dsa->fname,
278.530 + dsa->seqn, dsa->token);
278.531 + goto fail;
278.532 + }
278.533 + goto loop;
278.534 +done: xprintf("tsp_read_data: %d lines were read\n", dsa->seqn-1);
278.535 + fclose(dsa->fp);
278.536 + return tsp;
278.537 +fail: if (tsp != NULL)
278.538 + { if (tsp->name != NULL) xfree(tsp->name);
278.539 + if (tsp->comment != NULL) xfree(tsp->comment);
278.540 + if (tsp->node_x_coord != NULL) xfree(tsp->node_x_coord);
278.541 + if (tsp->node_y_coord != NULL) xfree(tsp->node_y_coord);
278.542 + if (tsp->dply_x_coord != NULL) xfree(tsp->dply_x_coord);
278.543 + if (tsp->dply_y_coord != NULL) xfree(tsp->dply_y_coord);
278.544 + if (tsp->tour != NULL) xfree(tsp->tour);
278.545 + if (tsp->edge_weight != NULL) xfree(tsp->edge_weight);
278.546 + xfree(tsp);
278.547 + }
278.548 + if (dsa->fp != NULL) fclose(dsa->fp);
278.549 + return NULL;
278.550 +}
278.551 +
278.552 +/*----------------------------------------------------------------------
278.553 +-- tsp_free_data - free TSP instance data.
278.554 +--
278.555 +-- *Synopsis*
278.556 +--
278.557 +-- #include "glptsp.h"
278.558 +-- void tsp_free_data(TSP *tsp);
278.559 +--
278.560 +-- *Description*
278.561 +--
278.562 +-- The routine tsp_free_data frees all the memory allocated to the TSP
278.563 +-- instance data block, which the parameter tsp points to. */
278.564 +
278.565 +void tsp_free_data(TSP *tsp)
278.566 +{ if (tsp->name != NULL) xfree(tsp->name);
278.567 + if (tsp->comment != NULL) xfree(tsp->comment);
278.568 + if (tsp->node_x_coord != NULL) xfree(tsp->node_x_coord);
278.569 + if (tsp->node_y_coord != NULL) xfree(tsp->node_y_coord);
278.570 + if (tsp->dply_x_coord != NULL) xfree(tsp->dply_x_coord);
278.571 + if (tsp->dply_y_coord != NULL) xfree(tsp->dply_y_coord);
278.572 + if (tsp->tour != NULL) xfree(tsp->tour);
278.573 + if (tsp->edge_weight != NULL) xfree(tsp->edge_weight);
278.574 + xfree(tsp);
278.575 + return;
278.576 +}
278.577 +
278.578 +/*----------------------------------------------------------------------
278.579 +-- tsp_distance - compute distance between two nodes.
278.580 +--
278.581 +-- *Synopsis*
278.582 +--
278.583 +-- #include "glptsp.h"
278.584 +-- int tsp_distance(TSP *tsp, int i, int j);
278.585 +--
278.586 +-- *Description*
278.587 +--
278.588 +-- The routine tsp_distance computes the distance between i-th and j-th
278.589 +-- nodes for the TSP instance, which tsp points to.
278.590 +--
278.591 +-- *Returns*
278.592 +--
278.593 +-- The routine tsp_distance returns the computed distance. */
278.594 +
278.595 +#define nint(x) ((int)((x) + 0.5))
278.596 +
278.597 +static double rad(double x)
278.598 +{ /* convert input coordinate to longitude/latitude, in radians */
278.599 + double pi = 3.141592, deg, min;
278.600 + deg = (int)x;
278.601 + min = x - deg;
278.602 + return pi * (deg + 5.0 * min / 3.0) / 180.0;
278.603 +}
278.604 +
278.605 +int tsp_distance(TSP *tsp, int i, int j)
278.606 +{ int n = tsp->dimension, dij;
278.607 + if (!(tsp->type == TSP_TSP || tsp->type == TSP_ATSP))
278.608 + xfault("tsp_distance: invalid TSP instance\n");
278.609 + if (!(1 <= i && i <= n && 1 <= j && j <= n))
278.610 + xfault("tsp_distance: node number out of range\n");
278.611 + switch (tsp->edge_weight_type)
278.612 + { case TSP_UNDEF:
278.613 + xfault("tsp_distance: edge weight type not specified\n");
278.614 + case TSP_EXPLICIT:
278.615 + if (tsp->edge_weight == NULL)
278.616 + xfault("tsp_distance: edge weights not specified\n");
278.617 + dij = tsp->edge_weight[(i - 1) * n + j];
278.618 + break;
278.619 + case TSP_EUC_2D:
278.620 + if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL)
278.621 + xfault("tsp_distance: node coordinates not specified\n");
278.622 + { double xd, yd;
278.623 + xd = tsp->node_x_coord[i] - tsp->node_x_coord[j];
278.624 + yd = tsp->node_y_coord[i] - tsp->node_y_coord[j];
278.625 + dij = nint(sqrt(xd * xd + yd * yd));
278.626 + }
278.627 + break;
278.628 + case TSP_CEIL_2D:
278.629 + if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL)
278.630 + xfault("tsp_distance: node coordinates not specified\n");
278.631 + { double xd, yd;
278.632 + xd = tsp->node_x_coord[i] - tsp->node_x_coord[j];
278.633 + yd = tsp->node_y_coord[i] - tsp->node_y_coord[j];
278.634 + dij = (int)ceil(sqrt(xd * xd + yd * yd));
278.635 + }
278.636 + break;
278.637 + case TSP_GEO:
278.638 + if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL)
278.639 + xfault("tsp_distance: node coordinates not specified\n");
278.640 + { double rrr = 6378.388;
278.641 + double latitude_i = rad(tsp->node_x_coord[i]);
278.642 + double latitude_j = rad(tsp->node_x_coord[j]);
278.643 + double longitude_i = rad(tsp->node_y_coord[i]);
278.644 + double longitude_j = rad(tsp->node_y_coord[j]);
278.645 + double q1 = cos(longitude_i - longitude_j);
278.646 + double q2 = cos(latitude_i - latitude_j);
278.647 + double q3 = cos(latitude_i + latitude_j);
278.648 + dij = (int)(rrr * acos(0.5 * ((1.0 + q1) * q2 -
278.649 + (1.0 - q1) *q3)) + 1.0);
278.650 + }
278.651 + break;
278.652 + case TSP_ATT:
278.653 + if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL)
278.654 + xfault("tsp_distance: node coordinates not specified\n");
278.655 + { int tij;
278.656 + double xd, yd, rij;
278.657 + xd = tsp->node_x_coord[i] - tsp->node_x_coord[j];
278.658 + yd = tsp->node_y_coord[i] - tsp->node_y_coord[j];
278.659 + rij = sqrt((xd * xd + yd * yd) / 10.0);
278.660 + tij = nint(rij);
278.661 + if (tij < rij) dij = tij + 1; else dij = tij;
278.662 + }
278.663 + break;
278.664 + default:
278.665 + xassert(tsp->edge_weight_type != tsp->edge_weight_type);
278.666 + }
278.667 + return dij;
278.668 +}
278.669 +
278.670 +/* eof */
279.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
279.2 +++ b/src/glptsp.h Mon Dec 06 13:09:21 2010 +0100
279.3 @@ -0,0 +1,104 @@
279.4 +/* glptsp.h (TSP format) */
279.5 +
279.6 +/***********************************************************************
279.7 +* This code is part of GLPK (GNU Linear Programming Kit).
279.8 +*
279.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
279.10 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
279.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
279.12 +* E-mail: <mao@gnu.org>.
279.13 +*
279.14 +* GLPK is free software: you can redistribute it and/or modify it
279.15 +* under the terms of the GNU General Public License as published by
279.16 +* the Free Software Foundation, either version 3 of the License, or
279.17 +* (at your option) any later version.
279.18 +*
279.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
279.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
279.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
279.22 +* License for more details.
279.23 +*
279.24 +* You should have received a copy of the GNU General Public License
279.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
279.26 +***********************************************************************/
279.27 +
279.28 +#ifndef GLPTSP_H
279.29 +#define GLPTSP_H
279.30 +
279.31 +typedef struct TSP TSP;
279.32 +
279.33 +struct TSP
279.34 +{ /* TSP (or related problem) instance in the format described in
279.35 + the report [G.Reinelt, TSPLIB 95] */
279.36 + /*--------------------------------------------------------------*/
279.37 + /* the specification part */
279.38 + char *name;
279.39 + /* identifies the data file */
279.40 + int type;
279.41 + /* specifies the type of data: */
279.42 +#define TSP_UNDEF 0 /* undefined */
279.43 +#define TSP_TSP 1 /* symmetric TSP */
279.44 +#define TSP_ATSP 2 /* asymmetric TSP */
279.45 +#define TSP_TOUR 3 /* collection of tours */
279.46 + char *comment;
279.47 + /* additional comments (usually the name of the contributor or
279.48 + creator of the problem instance is given here) */
279.49 + int dimension;
279.50 + /* for a TSP or ATSP, the dimension is the number of its nodes
279.51 + for a TOUR it is the dimension of the corresponding problem */
279.52 + int edge_weight_type;
279.53 + /* specifies how the edge weights (or distances) are given: */
279.54 +#define TSP_UNDEF 0 /* undefined */
279.55 +#define TSP_EXPLICIT 1 /* listed explicitly */
279.56 +#define TSP_EUC_2D 2 /* Eucl. distances in 2-D */
279.57 +#define TSP_CEIL_2D 3 /* Eucl. distances in 2-D rounded up */
279.58 +#define TSP_GEO 4 /* geographical distances */
279.59 +#define TSP_ATT 5 /* special distance function */
279.60 + int edge_weight_format;
279.61 + /* describes the format of the edge weights if they are given
279.62 + explicitly: */
279.63 +#define TSP_UNDEF 0 /* undefined */
279.64 +#define TSP_FUNCTION 1 /* given by a function */
279.65 +#define TSP_FULL_MATRIX 2 /* given by a full matrix */
279.66 +#define TSP_UPPER_ROW 3 /* upper triangulat matrix (row-wise
279.67 + without diagonal entries) */
279.68 +#define TSP_LOWER_DIAG_ROW 4 /* lower triangular matrix (row-wise
279.69 + including diagonal entries) */
279.70 + int display_data_type;
279.71 + /* specifies how a graphical display of the nodes can be
279.72 + obtained: */
279.73 +#define TSP_UNDEF 0 /* undefined */
279.74 +#define TSP_COORD_DISPLAY 1 /* display is generated from the node
279.75 + coordinates */
279.76 +#define TSP_TWOD_DISPLAY 2 /* explicit coordinates in 2-D are
279.77 + given */
279.78 + /*--------------------------------------------------------------*/
279.79 + /* data part */
279.80 + /* NODE_COORD_SECTION: */
279.81 + double *node_x_coord; /* double node_x_coord[1+dimension]; */
279.82 + double *node_y_coord; /* double node_y_coord[1+dimension]; */
279.83 + /* DISPLAY_DATA_SECTION: */
279.84 + double *dply_x_coord; /* double dply_x_coord[1+dimension]; */
279.85 + double *dply_y_coord; /* double dply_y_coord[1+dimension]; */
279.86 + /* TOUR_SECTION: */
279.87 + int *tour; /* int tour[1+dimension]; */
279.88 + /* EDGE_WEIGHT_SECTION: */
279.89 + int *edge_weight; /* int edge_weight[1+dimension*dimension]; */
279.90 +};
279.91 +
279.92 +#define tsp_read_data _glp_tsp_read_data
279.93 +#define tsp_free_data _glp_tsp_free_data
279.94 +#define tsp_distance _glp_tsp_distance
279.95 +
279.96 +TSP *tsp_read_data(char *fname);
279.97 +/* read TSP instance data */
279.98 +
279.99 +void tsp_free_data(TSP *tsp);
279.100 +/* free TSP instance data */
279.101 +
279.102 +int tsp_distance(TSP *tsp, int i, int j);
279.103 +/* compute distance between two nodes */
279.104 +
279.105 +#endif
279.106 +
279.107 +/* eof */
280.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
280.2 +++ b/w32/Build_GLPK_with_VC10.bat Mon Dec 06 13:09:21 2010 +0100
280.3 @@ -0,0 +1,11 @@
280.4 +rem Build GLPK with Microsoft Visual Studio Express 2010
280.5 +
280.6 +rem NOTE: Make sure that HOME variable specifies correct path
280.7 +set HOME="C:\Program Files\Microsoft Visual Studio 10.0\VC"
280.8 +
280.9 +call %HOME%\vcvarsall.bat x86
280.10 +copy config_VC config.h
280.11 +%HOME%\bin\nmake.exe /f Makefile_VC
280.12 +%HOME%\bin\nmake.exe /f Makefile_VC check
280.13 +
280.14 +pause
281.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
281.2 +++ b/w32/Build_GLPK_with_VC10_DLL.bat Mon Dec 06 13:09:21 2010 +0100
281.3 @@ -0,0 +1,11 @@
281.4 +rem Build GLPK DLL with Microsoft Visual Studio Express 2010
281.5 +
281.6 +rem NOTE: Make sure that HOME variable specifies correct path
281.7 +set HOME="C:\Program Files\Microsoft Visual Studio 10.0\VC"
281.8 +
281.9 +call %HOME%\vcvarsall.bat x86
281.10 +copy config_VC config.h
281.11 +%HOME%\bin\nmake.exe /f Makefile_VC_DLL
281.12 +%HOME%\bin\nmake.exe /f Makefile_VC_DLL check
281.13 +
281.14 +pause
282.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
282.2 +++ b/w32/Build_GLPK_with_VC9.bat Mon Dec 06 13:09:21 2010 +0100
282.3 @@ -0,0 +1,11 @@
282.4 +rem Build GLPK with Microsoft Visual Studio Express 2008
282.5 +
282.6 +rem NOTE: Make sure that HOME variable specifies correct path
282.7 +set HOME="C:\Program Files\Microsoft Visual Studio 9.0\VC"
282.8 +
282.9 +call %HOME%\bin\vcvars32.bat
282.10 +copy config_VC config.h
282.11 +%HOME%\bin\nmake.exe /f Makefile_VC
282.12 +%HOME%\bin\nmake.exe /f Makefile_VC check
282.13 +
282.14 +pause
283.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
283.2 +++ b/w32/Build_GLPK_with_VC9_DLL.bat Mon Dec 06 13:09:21 2010 +0100
283.3 @@ -0,0 +1,11 @@
283.4 +rem Build GLPK DLL with Microsoft Visual Studio Express 2008
283.5 +
283.6 +rem NOTE: Make sure that HOME variable specifies correct path
283.7 +set HOME="C:\Program Files\Microsoft Visual Studio 9.0\VC"
283.8 +
283.9 +call %HOME%\bin\vcvars32.bat
283.10 +copy config_VC config.h
283.11 +%HOME%\bin\nmake.exe /f Makefile_VC_DLL
283.12 +%HOME%\bin\nmake.exe /f Makefile_VC_DLL check
283.13 +
283.14 +pause
284.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
284.2 +++ b/w32/Makefile_VC Mon Dec 06 13:09:21 2010 +0100
284.3 @@ -0,0 +1,132 @@
284.4 +# Build GLPK with Microsoft Visual Studio Express
284.5 +
284.6 +CFLAGS = /I. /I..\include /I..\src /I..\src\amd /I..\src\colamd \
284.7 + /DHAVE_CONFIG_H /D_CRT_SECURE_NO_WARNINGS /nologo /W3 /O2
284.8 +
284.9 +OBJSET = \
284.10 +..\src\glpapi01.obj \
284.11 +..\src\glpapi02.obj \
284.12 +..\src\glpapi03.obj \
284.13 +..\src\glpapi04.obj \
284.14 +..\src\glpapi05.obj \
284.15 +..\src\glpapi06.obj \
284.16 +..\src\glpapi07.obj \
284.17 +..\src\glpapi08.obj \
284.18 +..\src\glpapi09.obj \
284.19 +..\src\glpapi10.obj \
284.20 +..\src\glpapi11.obj \
284.21 +..\src\glpapi12.obj \
284.22 +..\src\glpapi13.obj \
284.23 +..\src\glpapi14.obj \
284.24 +..\src\glpapi15.obj \
284.25 +..\src\glpapi16.obj \
284.26 +..\src\glpapi17.obj \
284.27 +..\src\glpapi18.obj \
284.28 +..\src\glpapi19.obj \
284.29 +..\src\glpavl.obj \
284.30 +..\src\glpbfd.obj \
284.31 +..\src\glpbfx.obj \
284.32 +..\src\glpcpx.obj \
284.33 +..\src\glpdmp.obj \
284.34 +..\src\glpdmx.obj \
284.35 +..\src\glpenv01.obj \
284.36 +..\src\glpenv02.obj \
284.37 +..\src\glpenv03.obj \
284.38 +..\src\glpenv04.obj \
284.39 +..\src\glpenv05.obj \
284.40 +..\src\glpenv06.obj \
284.41 +..\src\glpenv07.obj \
284.42 +..\src\glpenv08.obj \
284.43 +..\src\glpfhv.obj \
284.44 +..\src\glpgmp.obj \
284.45 +..\src\glphbm.obj \
284.46 +..\src\glpini01.obj \
284.47 +..\src\glpini02.obj \
284.48 +..\src\glpios01.obj \
284.49 +..\src\glpios02.obj \
284.50 +..\src\glpios03.obj \
284.51 +..\src\glpios04.obj \
284.52 +..\src\glpios05.obj \
284.53 +..\src\glpios06.obj \
284.54 +..\src\glpios07.obj \
284.55 +..\src\glpios08.obj \
284.56 +..\src\glpios09.obj \
284.57 +..\src\glpios10.obj \
284.58 +..\src\glpios11.obj \
284.59 +..\src\glpios12.obj \
284.60 +..\src\glpipm.obj \
284.61 +..\src\glplib01.obj \
284.62 +..\src\glplib02.obj \
284.63 +..\src\glplib03.obj \
284.64 +..\src\glplpf.obj \
284.65 +..\src\glplpx01.obj \
284.66 +..\src\glplpx02.obj \
284.67 +..\src\glplpx03.obj \
284.68 +..\src\glpluf.obj \
284.69 +..\src\glplux.obj \
284.70 +..\src\glpmat.obj \
284.71 +..\src\glpmpl01.obj \
284.72 +..\src\glpmpl02.obj \
284.73 +..\src\glpmpl03.obj \
284.74 +..\src\glpmpl04.obj \
284.75 +..\src\glpmpl05.obj \
284.76 +..\src\glpmpl06.obj \
284.77 +..\src\glpmps.obj \
284.78 +..\src\glpnet01.obj \
284.79 +..\src\glpnet02.obj \
284.80 +..\src\glpnet03.obj \
284.81 +..\src\glpnet04.obj \
284.82 +..\src\glpnet05.obj \
284.83 +..\src\glpnet06.obj \
284.84 +..\src\glpnet07.obj \
284.85 +..\src\glpnet08.obj \
284.86 +..\src\glpnet09.obj \
284.87 +..\src\glpnpp01.obj \
284.88 +..\src\glpnpp02.obj \
284.89 +..\src\glpnpp03.obj \
284.90 +..\src\glpnpp04.obj \
284.91 +..\src\glpnpp05.obj \
284.92 +..\src\glpqmd.obj \
284.93 +..\src\glprgr.obj \
284.94 +..\src\glprng01.obj \
284.95 +..\src\glprng02.obj \
284.96 +..\src\glpscf.obj \
284.97 +..\src\glpscl.obj \
284.98 +..\src\glpsdf.obj \
284.99 +..\src\glpspm.obj \
284.100 +..\src\glpspx01.obj \
284.101 +..\src\glpspx02.obj \
284.102 +..\src\glpsql.obj \
284.103 +..\src\glpssx01.obj \
284.104 +..\src\glpssx02.obj \
284.105 +..\src\glptsp.obj \
284.106 +..\src\amd\amd_1.obj \
284.107 +..\src\amd\amd_2.obj \
284.108 +..\src\amd\amd_aat.obj \
284.109 +..\src\amd\amd_control.obj \
284.110 +..\src\amd\amd_defaults.obj \
284.111 +..\src\amd\amd_dump.obj \
284.112 +..\src\amd\amd_info.obj \
284.113 +..\src\amd\amd_order.obj \
284.114 +..\src\amd\amd_post_tree.obj \
284.115 +..\src\amd\amd_postorder.obj \
284.116 +..\src\amd\amd_preprocess.obj \
284.117 +..\src\amd\amd_valid.obj \
284.118 +..\src\colamd\colamd.obj
284.119 +
284.120 +.c.obj:
284.121 + cl.exe $(CFLAGS) /Fo$*.obj /c $*.c
284.122 +
284.123 +all: glpk.lib glpsol.exe
284.124 +
284.125 +glpk.lib: $(OBJSET)
284.126 + lib.exe /out:glpk.lib ..\src\*.obj ..\src\amd\*.obj \
284.127 + ..\src\colamd\*.obj
284.128 +
284.129 +glpsol.exe: ..\examples\glpsol.obj glpk.lib
284.130 + cl.exe $(CFLAGS) /Feglpsol.exe ..\examples\glpsol.obj \
284.131 + glpk.lib
284.132 +
284.133 +check: glpsol.exe
284.134 + .\glpsol.exe --version
284.135 + .\glpsol.exe --mps ..\examples\plan.mps
285.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
285.2 +++ b/w32/Makefile_VC_DLL Mon Dec 06 13:09:21 2010 +0100
285.3 @@ -0,0 +1,132 @@
285.4 +# Build GLPK DLL with Microsoft Visual Studio Express
285.5 +
285.6 +CFLAGS = /I. /I..\include /I..\src /I..\src\amd /I..\src\colamd \
285.7 + /DHAVE_CONFIG_H /D_CRT_SECURE_NO_WARNINGS /nologo /W3 /O2
285.8 +
285.9 +OBJSET = \
285.10 +..\src\glpapi01.obj \
285.11 +..\src\glpapi02.obj \
285.12 +..\src\glpapi03.obj \
285.13 +..\src\glpapi04.obj \
285.14 +..\src\glpapi05.obj \
285.15 +..\src\glpapi06.obj \
285.16 +..\src\glpapi07.obj \
285.17 +..\src\glpapi08.obj \
285.18 +..\src\glpapi09.obj \
285.19 +..\src\glpapi10.obj \
285.20 +..\src\glpapi11.obj \
285.21 +..\src\glpapi12.obj \
285.22 +..\src\glpapi13.obj \
285.23 +..\src\glpapi14.obj \
285.24 +..\src\glpapi15.obj \
285.25 +..\src\glpapi16.obj \
285.26 +..\src\glpapi17.obj \
285.27 +..\src\glpapi18.obj \
285.28 +..\src\glpapi19.obj \
285.29 +..\src\glpavl.obj \
285.30 +..\src\glpbfd.obj \
285.31 +..\src\glpbfx.obj \
285.32 +..\src\glpcpx.obj \
285.33 +..\src\glpdmp.obj \
285.34 +..\src\glpdmx.obj \
285.35 +..\src\glpenv01.obj \
285.36 +..\src\glpenv02.obj \
285.37 +..\src\glpenv03.obj \
285.38 +..\src\glpenv04.obj \
285.39 +..\src\glpenv05.obj \
285.40 +..\src\glpenv06.obj \
285.41 +..\src\glpenv07.obj \
285.42 +..\src\glpenv08.obj \
285.43 +..\src\glpfhv.obj \
285.44 +..\src\glpgmp.obj \
285.45 +..\src\glphbm.obj \
285.46 +..\src\glpini01.obj \
285.47 +..\src\glpini02.obj \
285.48 +..\src\glpios01.obj \
285.49 +..\src\glpios02.obj \
285.50 +..\src\glpios03.obj \
285.51 +..\src\glpios04.obj \
285.52 +..\src\glpios05.obj \
285.53 +..\src\glpios06.obj \
285.54 +..\src\glpios07.obj \
285.55 +..\src\glpios08.obj \
285.56 +..\src\glpios09.obj \
285.57 +..\src\glpios10.obj \
285.58 +..\src\glpios11.obj \
285.59 +..\src\glpios12.obj \
285.60 +..\src\glpipm.obj \
285.61 +..\src\glplib01.obj \
285.62 +..\src\glplib02.obj \
285.63 +..\src\glplib03.obj \
285.64 +..\src\glplpf.obj \
285.65 +..\src\glplpx01.obj \
285.66 +..\src\glplpx02.obj \
285.67 +..\src\glplpx03.obj \
285.68 +..\src\glpluf.obj \
285.69 +..\src\glplux.obj \
285.70 +..\src\glpmat.obj \
285.71 +..\src\glpmpl01.obj \
285.72 +..\src\glpmpl02.obj \
285.73 +..\src\glpmpl03.obj \
285.74 +..\src\glpmpl04.obj \
285.75 +..\src\glpmpl05.obj \
285.76 +..\src\glpmpl06.obj \
285.77 +..\src\glpmps.obj \
285.78 +..\src\glpnet01.obj \
285.79 +..\src\glpnet02.obj \
285.80 +..\src\glpnet03.obj \
285.81 +..\src\glpnet04.obj \
285.82 +..\src\glpnet05.obj \
285.83 +..\src\glpnet06.obj \
285.84 +..\src\glpnet07.obj \
285.85 +..\src\glpnet08.obj \
285.86 +..\src\glpnet09.obj \
285.87 +..\src\glpnpp01.obj \
285.88 +..\src\glpnpp02.obj \
285.89 +..\src\glpnpp03.obj \
285.90 +..\src\glpnpp04.obj \
285.91 +..\src\glpnpp05.obj \
285.92 +..\src\glpqmd.obj \
285.93 +..\src\glprgr.obj \
285.94 +..\src\glprng01.obj \
285.95 +..\src\glprng02.obj \
285.96 +..\src\glpscf.obj \
285.97 +..\src\glpscl.obj \
285.98 +..\src\glpsdf.obj \
285.99 +..\src\glpspm.obj \
285.100 +..\src\glpspx01.obj \
285.101 +..\src\glpspx02.obj \
285.102 +..\src\glpsql.obj \
285.103 +..\src\glpssx01.obj \
285.104 +..\src\glpssx02.obj \
285.105 +..\src\glptsp.obj \
285.106 +..\src\amd\amd_1.obj \
285.107 +..\src\amd\amd_2.obj \
285.108 +..\src\amd\amd_aat.obj \
285.109 +..\src\amd\amd_control.obj \
285.110 +..\src\amd\amd_defaults.obj \
285.111 +..\src\amd\amd_dump.obj \
285.112 +..\src\amd\amd_info.obj \
285.113 +..\src\amd\amd_order.obj \
285.114 +..\src\amd\amd_post_tree.obj \
285.115 +..\src\amd\amd_postorder.obj \
285.116 +..\src\amd\amd_preprocess.obj \
285.117 +..\src\amd\amd_valid.obj \
285.118 +..\src\colamd\colamd.obj
285.119 +
285.120 +.c.obj:
285.121 + cl.exe $(CFLAGS) /Fo$*.obj /c $*.c
285.122 +
285.123 +all: glpk_4_45.dll glpsol.exe
285.124 +
285.125 +glpk_4_45.dll: $(OBJSET)
285.126 + cl.exe $(CFLAGS) /LD /Feglpk_4_45.dll ..\src\*.obj \
285.127 + ..\src\amd\*.obj ..\src\colamd\*.obj glpk_4_45.def
285.128 +
285.129 +glpsol.exe: ..\examples\glpsol.obj glpk_4_45.dll
285.130 + cl.exe $(CFLAGS) /Feglpsol.exe ..\examples\glpsol.obj \
285.131 + glpk_4_45.lib
285.132 +
285.133 +check: glpsol.exe
285.134 + .\glpsol.exe --version
285.135 + .\glpsol.exe --mps ..\examples\plan.mps
286.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
286.2 +++ b/w32/config_VC Mon Dec 06 13:09:21 2010 +0100
286.3 @@ -0,0 +1,13 @@
286.4 +/* GLPK configuration file (Microsoft Visual Studio Express) */
286.5 +
286.6 +#define __WOE__ 1
286.7 +
286.8 +#define ODBC_DLNAME "odbc32.dll"
286.9 +/* ODBC shared library name if this feature is enabled */
286.10 +
286.11 +#if 0
286.12 +#define MYSQL_DLNAME "libmysql.dll"
286.13 +/* MySQL shared library name if this feature is enabled */
286.14 +#endif
286.15 +
286.16 +/* eof */
287.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
287.2 +++ b/w32/glpk_4_45.def Mon Dec 06 13:09:21 2010 +0100
287.3 @@ -0,0 +1,1062 @@
287.4 +LIBRARY glpk_4_45
287.5 +VERSION 4.45
287.6 +DESCRIPTION "GNU Linear Programming Kit"
287.7 +EXPORTS
287.8 +;; from amd_1 ;;
287.9 + _glp_amd_1
287.10 +;; from amd_2 ;;
287.11 + _glp_amd_2
287.12 +;; from amd_aat ;;
287.13 + _glp_amd_aat
287.14 +;; from amd_control ;;
287.15 + _glp_amd_control
287.16 +;; from amd_defaults ;;
287.17 + _glp_amd_defaults
287.18 +;; from amd_dump ;;
287.19 +;; from amd_info ;;
287.20 + _glp_amd_info
287.21 +;; from amd_order ;;
287.22 + _glp_amd_order
287.23 +;; from amd_post_tree ;;
287.24 + _glp_amd_post_tree
287.25 +;; from amd_postorder ;;
287.26 + _glp_amd_postorder
287.27 +;; from amd_preprocess ;;
287.28 + _glp_amd_preprocess
287.29 +;; from amd_valid ;;
287.30 + _glp_amd_valid
287.31 +;; from colamd ;;
287.32 + _glp_colamd
287.33 + _glp_colamd_recommended
287.34 + _glp_colamd_report
287.35 + _glp_colamd_set_defaults
287.36 + _glp_symamd
287.37 + _glp_symamd_report
287.38 +;; from glpapi01 ;;
287.39 + glp_add_cols
287.40 + glp_add_rows
287.41 + glp_check_dup
287.42 + glp_copy_prob
287.43 + glp_create_prob
287.44 + glp_del_cols
287.45 + glp_del_rows
287.46 + glp_delete_prob
287.47 + glp_erase_prob
287.48 + glp_load_matrix
287.49 + glp_set_col_bnds
287.50 + glp_set_col_name
287.51 + glp_set_mat_col
287.52 + glp_set_mat_row
287.53 + glp_set_obj_coef
287.54 + glp_set_obj_dir
287.55 + glp_set_obj_name
287.56 + glp_set_prob_name
287.57 + glp_set_row_bnds
287.58 + glp_set_row_name
287.59 + glp_sort_matrix
287.60 +;; from glpapi02 ;;
287.61 + glp_get_col_lb
287.62 + glp_get_col_name
287.63 + glp_get_col_type
287.64 + glp_get_col_ub
287.65 + glp_get_mat_col
287.66 + glp_get_mat_row
287.67 + glp_get_num_cols
287.68 + glp_get_num_nz
287.69 + glp_get_num_rows
287.70 + glp_get_obj_coef
287.71 + glp_get_obj_dir
287.72 + glp_get_obj_name
287.73 + glp_get_prob_name
287.74 + glp_get_row_lb
287.75 + glp_get_row_name
287.76 + glp_get_row_type
287.77 + glp_get_row_ub
287.78 +;; from glpapi03 ;;
287.79 + glp_create_index
287.80 + glp_delete_index
287.81 + glp_find_col
287.82 + glp_find_row
287.83 +;; from glpapi04 ;;
287.84 + glp_get_rii
287.85 + glp_get_sjj
287.86 + glp_set_rii
287.87 + glp_set_sjj
287.88 + glp_unscale_prob
287.89 +;; from glpapi05 ;;
287.90 + glp_set_col_stat
287.91 + glp_set_row_stat
287.92 + glp_std_basis
287.93 +;; from glpapi06 ;;
287.94 + glp_get_col_dual
287.95 + glp_get_col_prim
287.96 + glp_get_col_stat
287.97 + glp_get_dual_stat
287.98 + glp_get_obj_val
287.99 + glp_get_prim_stat
287.100 + glp_get_row_dual
287.101 + glp_get_row_prim
287.102 + glp_get_row_stat
287.103 + glp_get_status
287.104 + glp_get_unbnd_ray
287.105 + glp_init_smcp
287.106 + glp_simplex
287.107 +;; from glpapi07 ;;
287.108 + glp_exact
287.109 +;; from glpapi08 ;;
287.110 + glp_init_iptcp
287.111 + glp_interior
287.112 + glp_ipt_col_dual
287.113 + glp_ipt_col_prim
287.114 + glp_ipt_obj_val
287.115 + glp_ipt_row_dual
287.116 + glp_ipt_row_prim
287.117 + glp_ipt_status
287.118 +;; from glpapi09 ;;
287.119 + glp_get_col_kind
287.120 + glp_get_num_bin
287.121 + glp_get_num_int
287.122 + glp_init_iocp
287.123 + glp_intopt
287.124 + glp_mip_col_val
287.125 + glp_mip_obj_val
287.126 + glp_mip_row_val
287.127 + glp_mip_status
287.128 + glp_set_col_kind
287.129 +;; from glpapi10 ;;
287.130 + _glp_check_kkt
287.131 +;; from glpapi11 ;;
287.132 + glp_print_ipt
287.133 + glp_print_mip
287.134 + glp_print_ranges
287.135 + glp_print_sol
287.136 + glp_read_ipt
287.137 + glp_read_mip
287.138 + glp_read_sol
287.139 + glp_write_ipt
287.140 + glp_write_mip
287.141 + glp_write_sol
287.142 +;; from glpapi12 ;;
287.143 + _glp_analyze_row
287.144 + glp_analyze_bound
287.145 + glp_analyze_coef
287.146 + glp_bf_exists
287.147 + glp_bf_updated
287.148 + glp_btran
287.149 + glp_dual_rtest
287.150 + glp_eval_tab_col
287.151 + glp_eval_tab_row
287.152 + glp_factorize
287.153 + glp_ftran
287.154 + glp_get_bfcp
287.155 + glp_get_bhead
287.156 + glp_get_col_bind
287.157 + glp_get_row_bind
287.158 + glp_prim_rtest
287.159 + glp_set_bfcp
287.160 + glp_transform_col
287.161 + glp_transform_row
287.162 + glp_warm_up
287.163 +;; from glpapi13 ;;
287.164 + glp_ios_add_row
287.165 + glp_ios_best_node
287.166 + glp_ios_branch_upon
287.167 + glp_ios_can_branch
287.168 + glp_ios_clear_pool
287.169 + glp_ios_curr_node
287.170 + glp_ios_del_row
287.171 + glp_ios_get_prob
287.172 + glp_ios_heur_sol
287.173 + glp_ios_mip_gap
287.174 + glp_ios_next_node
287.175 + glp_ios_node_bound
287.176 + glp_ios_node_data
287.177 + glp_ios_node_level
287.178 + glp_ios_pool_size
287.179 + glp_ios_prev_node
287.180 + glp_ios_reason
287.181 + glp_ios_row_attr
287.182 + glp_ios_select_node
287.183 + glp_ios_terminate
287.184 + glp_ios_tree_size
287.185 + glp_ios_up_node
287.186 +;; from glpapi14 ;;
287.187 + _glp_mpl_init_rand
287.188 + glp_mpl_alloc_wksp
287.189 + glp_mpl_build_prob
287.190 + glp_mpl_free_wksp
287.191 + glp_mpl_generate
287.192 + glp_mpl_postsolve
287.193 + glp_mpl_read_data
287.194 + glp_mpl_read_model
287.195 +;; from glpapi15 ;;
287.196 + glp_add_arc
287.197 + glp_add_vertices
287.198 + glp_create_graph
287.199 + glp_create_v_index
287.200 + glp_del_arc
287.201 + glp_del_vertices
287.202 + glp_delete_graph
287.203 + glp_delete_v_index
287.204 + glp_erase_graph
287.205 + glp_find_vertex
287.206 + glp_read_graph
287.207 + glp_set_graph_name
287.208 + glp_set_vertex_name
287.209 + glp_write_graph
287.210 +;; from glpapi16 ;;
287.211 + glp_strong_comp
287.212 + glp_top_sort
287.213 + glp_weak_comp
287.214 +;; from glpapi17 ;;
287.215 + glp_asnprob_hall
287.216 + glp_asnprob_lp
287.217 + glp_asnprob_okalg
287.218 + glp_check_asnprob
287.219 + glp_cpp
287.220 + glp_maxflow_ffalg
287.221 + glp_maxflow_lp
287.222 + glp_mincost_lp
287.223 + glp_mincost_okalg
287.224 +;; from glpapi18 ;;
287.225 + glp_wclique_exact
287.226 +;; from glpapi19 ;;
287.227 + glp_main
287.228 +;; from glpavl ;;
287.229 + _glp_avl_create_tree
287.230 + _glp_avl_delete_node
287.231 + _glp_avl_delete_tree
287.232 + _glp_avl_find_node
287.233 + _glp_avl_get_node_link
287.234 + _glp_avl_get_node_type
287.235 + _glp_avl_insert_node
287.236 + _glp_avl_set_node_link
287.237 + _glp_avl_set_node_type
287.238 + _glp_avl_strcmp
287.239 +;; from glpbfd ;;
287.240 + _glp_bfd_btran
287.241 + _glp_bfd_create_it
287.242 + _glp_bfd_delete_it
287.243 + _glp_bfd_factorize
287.244 + _glp_bfd_ftran
287.245 + _glp_bfd_get_count
287.246 + _glp_bfd_set_parm
287.247 + _glp_bfd_update_it
287.248 +;; from glpbfx ;;
287.249 + _glp_bfx_btran
287.250 + _glp_bfx_create_binv
287.251 + _glp_bfx_delete_binv
287.252 + _glp_bfx_factorize
287.253 + _glp_bfx_ftran
287.254 + _glp_bfx_update
287.255 +;; from glpcpx ;;
287.256 + glp_init_cpxcp
287.257 + glp_read_lp
287.258 + glp_write_lp
287.259 +;; from glpdmp ;;
287.260 + _glp_dmp_create_pool
287.261 + _glp_dmp_delete_pool
287.262 + _glp_dmp_free_atom
287.263 + _glp_dmp_get_atom
287.264 + _glp_dmp_in_use
287.265 +;; from glpdmx ;;
287.266 + glp_read_asnprob
287.267 + glp_read_ccdata
287.268 + glp_read_maxflow
287.269 + glp_read_mincost
287.270 + glp_read_prob
287.271 + glp_write_asnprob
287.272 + glp_write_ccdata
287.273 + glp_write_maxflow
287.274 + glp_write_mincost
287.275 + glp_write_prob
287.276 +;; from glpenv01 ;;
287.277 + _glp_get_env_ptr
287.278 + glp_free_env
287.279 + glp_init_env
287.280 + glp_version
287.281 +;; from glpenv02 ;;
287.282 + _glp_tls_get_ptr
287.283 + _glp_tls_set_ptr
287.284 +;; from glpenv03 ;;
287.285 + glp_close_tee
287.286 + glp_open_tee
287.287 + glp_printf
287.288 + glp_term_hook
287.289 + glp_term_out
287.290 + glp_vprintf
287.291 +;; from glpenv04 ;;
287.292 + glp_assert_
287.293 + glp_error_
287.294 + glp_error_hook
287.295 +;; from glpenv05 ;;
287.296 + glp_calloc
287.297 + glp_free
287.298 + glp_malloc
287.299 + glp_mem_limit
287.300 + glp_mem_usage
287.301 +;; from glpenv06 ;;
287.302 + glp_difftime
287.303 + glp_time
287.304 +;; from glpenv07 ;;
287.305 + _glp_lib_err_msg
287.306 + _glp_lib_xerrmsg
287.307 + _glp_lib_xfclose
287.308 + _glp_lib_xfeof
287.309 + _glp_lib_xferror
287.310 + _glp_lib_xfflush
287.311 + _glp_lib_xfgetc
287.312 + _glp_lib_xfopen
287.313 + _glp_lib_xfprintf
287.314 + _glp_lib_xfputc
287.315 +;; from glpenv08 ;;
287.316 + _glp_xdlclose
287.317 + _glp_xdlopen
287.318 + _glp_xdlsym
287.319 +;; from glpfhv ;;
287.320 + _glp_fhv_btran
287.321 + _glp_fhv_create_it
287.322 + _glp_fhv_delete_it
287.323 + _glp_fhv_factorize
287.324 + _glp_fhv_ftran
287.325 + _glp_fhv_h_solve
287.326 + _glp_fhv_update_it
287.327 +;; from glpgmp ;;
287.328 + _glp_gmp_free_atom
287.329 + _glp_gmp_free_mem
287.330 + _glp_gmp_get_atom
287.331 + _glp_gmp_get_work
287.332 + _glp_gmp_pool_count
287.333 + _glp_mpq_abs
287.334 + _glp_mpq_add
287.335 + _glp_mpq_canonicalize
287.336 + _glp_mpq_clear
287.337 + _glp_mpq_cmp
287.338 + _glp_mpq_div
287.339 + _glp_mpq_get_d
287.340 + _glp_mpq_init
287.341 + _glp_mpq_mul
287.342 + _glp_mpq_neg
287.343 + _glp_mpq_out_str
287.344 + _glp_mpq_set
287.345 + _glp_mpq_set_d
287.346 + _glp_mpq_set_si
287.347 + _glp_mpq_sgn
287.348 + _glp_mpq_sub
287.349 + _glp_mpz_abs
287.350 + _glp_mpz_add
287.351 + _glp_mpz_clear
287.352 + _glp_mpz_cmp
287.353 + _glp_mpz_div
287.354 + _glp_mpz_gcd
287.355 + _glp_mpz_get_d
287.356 + _glp_mpz_get_d_2exp
287.357 + _glp_mpz_init
287.358 + _glp_mpz_mul
287.359 + _glp_mpz_neg
287.360 + _glp_mpz_out_str
287.361 + _glp_mpz_set
287.362 + _glp_mpz_set_si
287.363 + _glp_mpz_sgn
287.364 + _glp_mpz_sub
287.365 + _glp_mpz_swap
287.366 +;; from glphbm ;;
287.367 + _glp_hbm_free_mat
287.368 + _glp_hbm_read_mat
287.369 +;; from glpini01 ;;
287.370 + glp_adv_basis
287.371 +;; from glpini02 ;;
287.372 + glp_cpx_basis
287.373 +;; from glpios01 ;;
287.374 + _glp_ios_add_row
287.375 + _glp_ios_best_node
287.376 + _glp_ios_clear_pool
287.377 + _glp_ios_clone_node
287.378 + _glp_ios_create_pool
287.379 + _glp_ios_create_tree
287.380 + _glp_ios_del_row
287.381 + _glp_ios_delete_node
287.382 + _glp_ios_delete_pool
287.383 + _glp_ios_delete_tree
287.384 + _glp_ios_eval_degrad
287.385 + _glp_ios_find_row
287.386 + _glp_ios_freeze_node
287.387 + _glp_ios_is_hopeful
287.388 + _glp_ios_relative_gap
287.389 + _glp_ios_revive_node
287.390 + _glp_ios_round_bound
287.391 + _glp_ios_solve_node
287.392 +;; from glpios02 ;;
287.393 + _glp_ios_preprocess_node
287.394 +;; from glpios03 ;;
287.395 + _glp_ios_driver
287.396 +;; from glpios04 ;;
287.397 + _glp_ios_check_vec
287.398 + _glp_ios_clean_vec
287.399 + _glp_ios_clear_vec
287.400 + _glp_ios_copy_vec
287.401 + _glp_ios_create_vec
287.402 + _glp_ios_delete_vec
287.403 + _glp_ios_get_vj
287.404 + _glp_ios_linear_comb
287.405 + _glp_ios_set_vj
287.406 +;; from glpios05 ;;
287.407 + _glp_ios_gmi_gen
287.408 +;; from glpios06 ;;
287.409 + _glp_ios_mir_gen
287.410 + _glp_ios_mir_init
287.411 + _glp_ios_mir_term
287.412 +;; from glpios07 ;;
287.413 + _glp_ios_cov_gen
287.414 +;; from glpios08 ;;
287.415 + _glp_ios_clq_gen
287.416 + _glp_ios_clq_init
287.417 + _glp_ios_clq_term
287.418 +;; from glpios09 ;;
287.419 + _glp_ios_choose_var
287.420 + _glp_ios_pcost_branch
287.421 + _glp_ios_pcost_free
287.422 + _glp_ios_pcost_init
287.423 + _glp_ios_pcost_update
287.424 +;; from glpios10 ;;
287.425 + _glp_ios_feas_pump
287.426 +;; from glpios11 ;;
287.427 + _glp_ios_process_cuts
287.428 +;; from glpios12 ;;
287.429 + _glp_ios_choose_node
287.430 +;; from glpipm ;;
287.431 + _glp_ipm_solve
287.432 +;; from glplib01 ;;
287.433 + _glp_lib_bigdiv
287.434 + _glp_lib_bigmul
287.435 +;; from glplib02 ;;
287.436 + _glp_lib_xladd
287.437 + _glp_lib_xlcmp
287.438 + _glp_lib_xldiv
287.439 + _glp_lib_xlmul
287.440 + _glp_lib_xlneg
287.441 + _glp_lib_xlset
287.442 + _glp_lib_xlsub
287.443 + _glp_lib_xltoa
287.444 + _glp_lib_xltod
287.445 +;; from glplib03 ;;
287.446 + _glp_lib_fp2rat
287.447 + _glp_lib_gcd
287.448 + _glp_lib_gcdn
287.449 + _glp_lib_jdate
287.450 + _glp_lib_jday
287.451 + _glp_lib_lcm
287.452 + _glp_lib_lcmn
287.453 + _glp_lib_round2n
287.454 + _glp_lib_str2int
287.455 + _glp_lib_str2num
287.456 + _glp_lib_strrev
287.457 + _glp_lib_strspx
287.458 + _glp_lib_strtrim
287.459 +;; from glplpf ;;
287.460 + _glp_lpf_btran
287.461 + _glp_lpf_create_it
287.462 + _glp_lpf_delete_it
287.463 + _glp_lpf_factorize
287.464 + _glp_lpf_ftran
287.465 + _glp_lpf_update_it
287.466 +;; from glplpx01 ;;
287.467 + _glp_lpx_add_cols
287.468 + _glp_lpx_add_rows
287.469 + _glp_lpx_adv_basis
287.470 + _glp_lpx_check_int
287.471 + _glp_lpx_check_kkt
287.472 + _glp_lpx_cpx_basis
287.473 + _glp_lpx_create_index
287.474 + _glp_lpx_create_prob
287.475 + _glp_lpx_del_cols
287.476 + _glp_lpx_del_rows
287.477 + _glp_lpx_delete_index
287.478 + _glp_lpx_delete_prob
287.479 + _glp_lpx_dual_ratio_test
287.480 + _glp_lpx_eval_tab_col
287.481 + _glp_lpx_eval_tab_row
287.482 + _glp_lpx_exact
287.483 + _glp_lpx_find_col
287.484 + _glp_lpx_find_row
287.485 + _glp_lpx_get_class
287.486 + _glp_lpx_get_col_bnds
287.487 + _glp_lpx_get_col_dual
287.488 + _glp_lpx_get_col_info
287.489 + _glp_lpx_get_col_kind
287.490 + _glp_lpx_get_col_lb
287.491 + _glp_lpx_get_col_name
287.492 + _glp_lpx_get_col_prim
287.493 + _glp_lpx_get_col_stat
287.494 + _glp_lpx_get_col_type
287.495 + _glp_lpx_get_col_ub
287.496 + _glp_lpx_get_dual_stat
287.497 + _glp_lpx_get_int_parm
287.498 + _glp_lpx_get_mat_col
287.499 + _glp_lpx_get_mat_row
287.500 + _glp_lpx_get_num_bin
287.501 + _glp_lpx_get_num_cols
287.502 + _glp_lpx_get_num_int
287.503 + _glp_lpx_get_num_nz
287.504 + _glp_lpx_get_num_rows
287.505 + _glp_lpx_get_obj_coef
287.506 + _glp_lpx_get_obj_dir
287.507 + _glp_lpx_get_obj_name
287.508 + _glp_lpx_get_obj_val
287.509 + _glp_lpx_get_prim_stat
287.510 + _glp_lpx_get_prob_name
287.511 + _glp_lpx_get_ray_info
287.512 + _glp_lpx_get_real_parm
287.513 + _glp_lpx_get_row_bnds
287.514 + _glp_lpx_get_row_dual
287.515 + _glp_lpx_get_row_info
287.516 + _glp_lpx_get_row_lb
287.517 + _glp_lpx_get_row_name
287.518 + _glp_lpx_get_row_prim
287.519 + _glp_lpx_get_row_stat
287.520 + _glp_lpx_get_row_type
287.521 + _glp_lpx_get_row_ub
287.522 + _glp_lpx_get_status
287.523 + _glp_lpx_integer
287.524 + _glp_lpx_interior
287.525 + _glp_lpx_intopt
287.526 + _glp_lpx_ipt_col_dual
287.527 + _glp_lpx_ipt_col_prim
287.528 + _glp_lpx_ipt_obj_val
287.529 + _glp_lpx_ipt_row_dual
287.530 + _glp_lpx_ipt_row_prim
287.531 + _glp_lpx_ipt_status
287.532 + _glp_lpx_is_b_avail
287.533 + _glp_lpx_load_matrix
287.534 + _glp_lpx_main
287.535 + _glp_lpx_mip_col_val
287.536 + _glp_lpx_mip_obj_val
287.537 + _glp_lpx_mip_row_val
287.538 + _glp_lpx_mip_status
287.539 + _glp_lpx_prim_ratio_test
287.540 + _glp_lpx_print_ips
287.541 + _glp_lpx_print_mip
287.542 + _glp_lpx_print_prob
287.543 + _glp_lpx_print_sens_bnds
287.544 + _glp_lpx_print_sol
287.545 + _glp_lpx_read_bas
287.546 + _glp_lpx_read_cpxlp
287.547 + _glp_lpx_read_freemps
287.548 + _glp_lpx_read_model
287.549 + _glp_lpx_read_mps
287.550 + _glp_lpx_reset_parms
287.551 + _glp_lpx_scale_prob
287.552 + _glp_lpx_set_class
287.553 + _glp_lpx_set_col_bnds
287.554 + _glp_lpx_set_col_kind
287.555 + _glp_lpx_set_col_name
287.556 + _glp_lpx_set_col_stat
287.557 + _glp_lpx_set_int_parm
287.558 + _glp_lpx_set_mat_col
287.559 + _glp_lpx_set_mat_row
287.560 + _glp_lpx_set_obj_coef
287.561 + _glp_lpx_set_obj_dir
287.562 + _glp_lpx_set_obj_name
287.563 + _glp_lpx_set_prob_name
287.564 + _glp_lpx_set_real_parm
287.565 + _glp_lpx_set_row_bnds
287.566 + _glp_lpx_set_row_name
287.567 + _glp_lpx_set_row_stat
287.568 + _glp_lpx_simplex
287.569 + _glp_lpx_std_basis
287.570 + _glp_lpx_transform_col
287.571 + _glp_lpx_transform_row
287.572 + _glp_lpx_unscale_prob
287.573 + _glp_lpx_warm_up
287.574 + _glp_lpx_write_bas
287.575 + _glp_lpx_write_cpxlp
287.576 + _glp_lpx_write_freemps
287.577 + _glp_lpx_write_mps
287.578 +;; from glplpx02 ;;
287.579 + _glp_put_mip_soln
287.580 + _glp_put_solution
287.581 +;; from glplpx03 ;;
287.582 + _glp_lpx_write_pb
287.583 +;; from glpluf ;;
287.584 + _glp_luf_a_solve
287.585 + _glp_luf_create_it
287.586 + _glp_luf_defrag_sva
287.587 + _glp_luf_delete_it
287.588 + _glp_luf_enlarge_col
287.589 + _glp_luf_enlarge_row
287.590 + _glp_luf_f_solve
287.591 + _glp_luf_factorize
287.592 + _glp_luf_v_solve
287.593 +;; from glplux ;;
287.594 + _glp_lux_create
287.595 + _glp_lux_decomp
287.596 + _glp_lux_delete
287.597 + _glp_lux_f_solve
287.598 + _glp_lux_solve
287.599 + _glp_lux_v_solve
287.600 +;; from glpmat ;;
287.601 + _glp_mat_adat_numeric
287.602 + _glp_mat_adat_symbolic
287.603 + _glp_mat_amd_order1
287.604 + _glp_mat_check_fvs
287.605 + _glp_mat_check_pattern
287.606 + _glp_mat_chol_numeric
287.607 + _glp_mat_chol_symbolic
287.608 + _glp_mat_min_degree
287.609 + _glp_mat_symamd_ord
287.610 + _glp_mat_transpose
287.611 + _glp_mat_u_solve
287.612 + _glp_mat_ut_solve
287.613 +;; from glpmpl01 ;;
287.614 + _glp_mpl_append_block
287.615 + _glp_mpl_append_char
287.616 + _glp_mpl_append_slot
287.617 + _glp_mpl_arg_list_len
287.618 + _glp_mpl_branched_expression
287.619 + _glp_mpl_check_statement
287.620 + _glp_mpl_close_scope
287.621 + _glp_mpl_constraint_statement
287.622 + _glp_mpl_create_arg_list
287.623 + _glp_mpl_create_block
287.624 + _glp_mpl_create_domain
287.625 + _glp_mpl_display_statement
287.626 + _glp_mpl_domain_arity
287.627 + _glp_mpl_elemset_argument
287.628 + _glp_mpl_end_statement
287.629 + _glp_mpl_enter_context
287.630 + _glp_mpl_error_dimension
287.631 + _glp_mpl_error_following
287.632 + _glp_mpl_error_preceding
287.633 + _glp_mpl_expand_arg_list
287.634 + _glp_mpl_expression_0
287.635 + _glp_mpl_expression_1
287.636 + _glp_mpl_expression_10
287.637 + _glp_mpl_expression_11
287.638 + _glp_mpl_expression_12
287.639 + _glp_mpl_expression_13
287.640 + _glp_mpl_expression_2
287.641 + _glp_mpl_expression_3
287.642 + _glp_mpl_expression_4
287.643 + _glp_mpl_expression_5
287.644 + _glp_mpl_expression_6
287.645 + _glp_mpl_expression_7
287.646 + _glp_mpl_expression_8
287.647 + _glp_mpl_expression_9
287.648 + _glp_mpl_expression_list
287.649 + _glp_mpl_for_statement
287.650 + _glp_mpl_function_reference
287.651 + _glp_mpl_get_char
287.652 + _glp_mpl_get_token
287.653 + _glp_mpl_indexing_expression
287.654 + _glp_mpl_is_keyword
287.655 + _glp_mpl_is_reserved
287.656 + _glp_mpl_iterated_expression
287.657 + _glp_mpl_literal_set
287.658 + _glp_mpl_make_binary
287.659 + _glp_mpl_make_code
287.660 + _glp_mpl_make_ternary
287.661 + _glp_mpl_make_unary
287.662 + _glp_mpl_model_section
287.663 + _glp_mpl_numeric_argument
287.664 + _glp_mpl_numeric_literal
287.665 + _glp_mpl_object_reference
287.666 + _glp_mpl_objective_statement
287.667 + _glp_mpl_parameter_statement
287.668 + _glp_mpl_primary_expression
287.669 + _glp_mpl_print_context
287.670 + _glp_mpl_printf_statement
287.671 + _glp_mpl_set_expression
287.672 + _glp_mpl_set_statement
287.673 + _glp_mpl_simple_statement
287.674 + _glp_mpl_solve_statement
287.675 + _glp_mpl_string_literal
287.676 + _glp_mpl_subscript_list
287.677 + _glp_mpl_symbolic_argument
287.678 + _glp_mpl_table_statement
287.679 + _glp_mpl_unget_token
287.680 + _glp_mpl_variable_statement
287.681 +;; from glpmpl02 ;;
287.682 + _glp_mpl_create_slice
287.683 + _glp_mpl_data_section
287.684 + _glp_mpl_delete_slice
287.685 + _glp_mpl_expand_slice
287.686 + _glp_mpl_fake_slice
287.687 + _glp_mpl_is_literal
287.688 + _glp_mpl_is_number
287.689 + _glp_mpl_is_symbol
287.690 + _glp_mpl_matrix_format
287.691 + _glp_mpl_parameter_data
287.692 + _glp_mpl_plain_format
287.693 + _glp_mpl_read_number
287.694 + _glp_mpl_read_slice
287.695 + _glp_mpl_read_symbol
287.696 + _glp_mpl_read_value
287.697 + _glp_mpl_select_parameter
287.698 + _glp_mpl_select_set
287.699 + _glp_mpl_set_data
287.700 + _glp_mpl_set_default
287.701 + _glp_mpl_simple_format
287.702 + _glp_mpl_slice_arity
287.703 + _glp_mpl_slice_dimen
287.704 + _glp_mpl_tabbing_format
287.705 + _glp_mpl_tabular_format
287.706 +;; from glpmpl03 ;;
287.707 + _glp_mpl_add_member
287.708 + _glp_mpl_add_tuple
287.709 + _glp_mpl_arelset_member
287.710 + _glp_mpl_arelset_size
287.711 + _glp_mpl_assign_dummy_index
287.712 + _glp_mpl_build_subtuple
287.713 + _glp_mpl_check_elem_set
287.714 + _glp_mpl_check_then_add
287.715 + _glp_mpl_check_value_num
287.716 + _glp_mpl_check_value_sym
287.717 + _glp_mpl_clean_check
287.718 + _glp_mpl_clean_code
287.719 + _glp_mpl_clean_constraint
287.720 + _glp_mpl_clean_display
287.721 + _glp_mpl_clean_domain
287.722 + _glp_mpl_clean_for
287.723 + _glp_mpl_clean_parameter
287.724 + _glp_mpl_clean_printf
287.725 + _glp_mpl_clean_set
287.726 + _glp_mpl_clean_statement
287.727 + _glp_mpl_clean_table
287.728 + _glp_mpl_clean_variable
287.729 + _glp_mpl_compare_strings
287.730 + _glp_mpl_compare_symbols
287.731 + _glp_mpl_compare_tuples
287.732 + _glp_mpl_concat_symbols
287.733 + _glp_mpl_constant_term
287.734 + _glp_mpl_copy_elemset
287.735 + _glp_mpl_copy_formula
287.736 + _glp_mpl_copy_string
287.737 + _glp_mpl_copy_symbol
287.738 + _glp_mpl_copy_tuple
287.739 + _glp_mpl_create_arelset
287.740 + _glp_mpl_create_array
287.741 + _glp_mpl_create_elemset
287.742 + _glp_mpl_create_string
287.743 + _glp_mpl_create_symbol_num
287.744 + _glp_mpl_create_symbol_str
287.745 + _glp_mpl_create_tuple
287.746 + _glp_mpl_delete_array
287.747 + _glp_mpl_delete_elemset
287.748 + _glp_mpl_delete_formula
287.749 + _glp_mpl_delete_string
287.750 + _glp_mpl_delete_symbol
287.751 + _glp_mpl_delete_tuple
287.752 + _glp_mpl_delete_value
287.753 + _glp_mpl_enter_domain_block
287.754 + _glp_mpl_eval_elemset
287.755 + _glp_mpl_eval_formula
287.756 + _glp_mpl_eval_logical
287.757 + _glp_mpl_eval_member_con
287.758 + _glp_mpl_eval_member_num
287.759 + _glp_mpl_eval_member_set
287.760 + _glp_mpl_eval_member_sym
287.761 + _glp_mpl_eval_member_var
287.762 + _glp_mpl_eval_numeric
287.763 + _glp_mpl_eval_symbolic
287.764 + _glp_mpl_eval_tuple
287.765 + _glp_mpl_eval_whole_con
287.766 + _glp_mpl_eval_whole_par
287.767 + _glp_mpl_eval_whole_set
287.768 + _glp_mpl_eval_whole_var
287.769 + _glp_mpl_eval_within_domain
287.770 + _glp_mpl_execute_check
287.771 + _glp_mpl_execute_display
287.772 + _glp_mpl_execute_for
287.773 + _glp_mpl_execute_printf
287.774 + _glp_mpl_execute_statement
287.775 + _glp_mpl_execute_table
287.776 + _glp_mpl_expand_tuple
287.777 + _glp_mpl_fetch_string
287.778 + _glp_mpl_find_member
287.779 + _glp_mpl_find_tuple
287.780 + _glp_mpl_format_symbol
287.781 + _glp_mpl_format_tuple
287.782 + _glp_mpl_fp_add
287.783 + _glp_mpl_fp_atan
287.784 + _glp_mpl_fp_atan2
287.785 + _glp_mpl_fp_cos
287.786 + _glp_mpl_fp_div
287.787 + _glp_mpl_fp_exp
287.788 + _glp_mpl_fp_idiv
287.789 + _glp_mpl_fp_irand224
287.790 + _glp_mpl_fp_less
287.791 + _glp_mpl_fp_log
287.792 + _glp_mpl_fp_log10
287.793 + _glp_mpl_fp_mod
287.794 + _glp_mpl_fp_mul
287.795 + _glp_mpl_fp_normal
287.796 + _glp_mpl_fp_normal01
287.797 + _glp_mpl_fp_power
287.798 + _glp_mpl_fp_round
287.799 + _glp_mpl_fp_sin
287.800 + _glp_mpl_fp_sqrt
287.801 + _glp_mpl_fp_sub
287.802 + _glp_mpl_fp_trunc
287.803 + _glp_mpl_fp_uniform01
287.804 + _glp_mpl_free_dca
287.805 + _glp_mpl_get_domain_tuple
287.806 + _glp_mpl_is_member
287.807 + _glp_mpl_linear_comb
287.808 + _glp_mpl_loop_within_domain
287.809 + _glp_mpl_out_of_domain
287.810 + _glp_mpl_reduce_terms
287.811 + _glp_mpl_remove_constant
287.812 + _glp_mpl_set_cross
287.813 + _glp_mpl_set_diff
287.814 + _glp_mpl_set_inter
287.815 + _glp_mpl_set_symdiff
287.816 + _glp_mpl_set_union
287.817 + _glp_mpl_single_variable
287.818 + _glp_mpl_tab_get_arg
287.819 + _glp_mpl_tab_get_name
287.820 + _glp_mpl_tab_get_num
287.821 + _glp_mpl_tab_get_str
287.822 + _glp_mpl_tab_get_type
287.823 + _glp_mpl_tab_num_args
287.824 + _glp_mpl_tab_num_flds
287.825 + _glp_mpl_tab_set_num
287.826 + _glp_mpl_tab_set_str
287.827 + _glp_mpl_take_member_con
287.828 + _glp_mpl_take_member_num
287.829 + _glp_mpl_take_member_set
287.830 + _glp_mpl_take_member_sym
287.831 + _glp_mpl_take_member_var
287.832 + _glp_mpl_tuple_dimen
287.833 + _glp_mpl_uniform
287.834 + _glp_mpl_update_dummy_indices
287.835 +;; from glpmpl04 ;;
287.836 + _glp_mpl_alloc_content
287.837 + _glp_mpl_build_problem
287.838 + _glp_mpl_clean_model
287.839 + _glp_mpl_close_input
287.840 + _glp_mpl_error
287.841 + _glp_mpl_flush_output
287.842 + _glp_mpl_generate
287.843 + _glp_mpl_generate_model
287.844 + _glp_mpl_get_col_bnds
287.845 + _glp_mpl_get_col_kind
287.846 + _glp_mpl_get_col_name
287.847 + _glp_mpl_get_mat_row
287.848 + _glp_mpl_get_num_cols
287.849 + _glp_mpl_get_num_rows
287.850 + _glp_mpl_get_prob_name
287.851 + _glp_mpl_get_row_bnds
287.852 + _glp_mpl_get_row_c0
287.853 + _glp_mpl_get_row_kind
287.854 + _glp_mpl_get_row_name
287.855 + _glp_mpl_has_solve_stmt
287.856 + _glp_mpl_initialize
287.857 + _glp_mpl_open_input
287.858 + _glp_mpl_open_output
287.859 + _glp_mpl_postsolve
287.860 + _glp_mpl_postsolve_model
287.861 + _glp_mpl_put_col_soln
287.862 + _glp_mpl_put_row_soln
287.863 + _glp_mpl_read_char
287.864 + _glp_mpl_read_data
287.865 + _glp_mpl_read_model
287.866 + _glp_mpl_terminate
287.867 + _glp_mpl_warning
287.868 + _glp_mpl_write_char
287.869 + _glp_mpl_write_text
287.870 +;; from glpmpl05 ;;
287.871 + _glp_mpl_fn_gmtime
287.872 + _glp_mpl_fn_str2time
287.873 + _glp_mpl_fn_time2str
287.874 +;; from glpmpl06 ;;
287.875 + _glp_mpl_tab_drv_close
287.876 + _glp_mpl_tab_drv_open
287.877 + _glp_mpl_tab_drv_read
287.878 + _glp_mpl_tab_drv_write
287.879 +;; from glpmps ;;
287.880 + glp_init_mpscp
287.881 + glp_read_mps
287.882 + glp_write_mps
287.883 +;; from glpnet01 ;;
287.884 + _glp_mc21a
287.885 +;; from glpnet02 ;;
287.886 + _glp_mc13d
287.887 +;; from glpnet03 ;;
287.888 + glp_netgen
287.889 +;; from glpnet04 ;;
287.890 + glp_gridgen
287.891 +;; from glpnet05 ;;
287.892 + glp_rmfgen
287.893 +;; from glpnet06 ;;
287.894 + _glp_okalg
287.895 +;; from glpnet07 ;;
287.896 + _glp_ffalg
287.897 +;; from glpnet08 ;;
287.898 + _glp_wclique
287.899 +;; from glpnet09 ;;
287.900 + _glp_kellerman
287.901 +;; from glpnpp01 ;;
287.902 + _glp_npp_activate_col
287.903 + _glp_npp_activate_row
287.904 + _glp_npp_add_aij
287.905 + _glp_npp_add_col
287.906 + _glp_npp_add_row
287.907 + _glp_npp_build_prob
287.908 + _glp_npp_col_nnz
287.909 + _glp_npp_create_wksp
287.910 + _glp_npp_deactivate_col
287.911 + _glp_npp_deactivate_row
287.912 + _glp_npp_del_aij
287.913 + _glp_npp_del_col
287.914 + _glp_npp_del_row
287.915 + _glp_npp_delete_wksp
287.916 + _glp_npp_erase_row
287.917 + _glp_npp_insert_col
287.918 + _glp_npp_insert_row
287.919 + _glp_npp_load_prob
287.920 + _glp_npp_postprocess
287.921 + _glp_npp_push_tse
287.922 + _glp_npp_remove_col
287.923 + _glp_npp_remove_row
287.924 + _glp_npp_row_nnz
287.925 + _glp_npp_unload_sol
287.926 +;; from glpnpp02 ;;
287.927 + _glp_npp_dbnd_col
287.928 + _glp_npp_fixed_col
287.929 + _glp_npp_free_col
287.930 + _glp_npp_free_row
287.931 + _glp_npp_geq_row
287.932 + _glp_npp_lbnd_col
287.933 + _glp_npp_leq_row
287.934 + _glp_npp_make_equality
287.935 + _glp_npp_make_fixed
287.936 + _glp_npp_ubnd_col
287.937 +;; from glpnpp03 ;;
287.938 + _glp_npp_analyze_row
287.939 + _glp_npp_empty_col
287.940 + _glp_npp_empty_row
287.941 + _glp_npp_eq_doublet
287.942 + _glp_npp_eq_singlet
287.943 + _glp_npp_forcing_row
287.944 + _glp_npp_implied_bounds
287.945 + _glp_npp_implied_free
287.946 + _glp_npp_implied_lower
287.947 + _glp_npp_implied_slack
287.948 + _glp_npp_implied_upper
287.949 + _glp_npp_implied_value
287.950 + _glp_npp_inactive_bound
287.951 + _glp_npp_ineq_singlet
287.952 +;; from glpnpp04 ;;
287.953 + _glp_npp_binarize_prob
287.954 + _glp_npp_hidden_covering
287.955 + _glp_npp_hidden_packing
287.956 + _glp_npp_implied_packing
287.957 + _glp_npp_is_covering
287.958 + _glp_npp_is_packing
287.959 + _glp_npp_is_partitioning
287.960 + _glp_npp_reduce_ineq_coef
287.961 +;; from glpnpp05 ;;
287.962 + _glp_npp_clean_prob
287.963 + _glp_npp_improve_bounds
287.964 + _glp_npp_integer
287.965 + _glp_npp_process_col
287.966 + _glp_npp_process_prob
287.967 + _glp_npp_process_row
287.968 + _glp_npp_simplex
287.969 +;; from glpqmd ;;
287.970 + _glp_qmd_genqmd
287.971 + _glp_qmd_qmdmrg
287.972 + _glp_qmd_qmdqt
287.973 + _glp_qmd_qmdrch
287.974 + _glp_qmd_qmdupd
287.975 +;; from glprgr ;;
287.976 + _glp_rgr_write_bmp16
287.977 +;; from glprng01 ;;
287.978 + _glp_rng_create_rand
287.979 + _glp_rng_delete_rand
287.980 + _glp_rng_init_rand
287.981 + _glp_rng_next_rand
287.982 + _glp_rng_unif_rand
287.983 +;; from glprng02 ;;
287.984 + _glp_rng_unif_01
287.985 + _glp_rng_uniform
287.986 +;; from glpscf ;;
287.987 + _glp_scf_create_it
287.988 + _glp_scf_delete_it
287.989 + _glp_scf_reset_it
287.990 + _glp_scf_solve_it
287.991 + _glp_scf_update_exp
287.992 +;; from glpscl ;;
287.993 + glp_scale_prob
287.994 +;; from glpsdf ;;
287.995 + glp_sdf_close_file
287.996 + glp_sdf_error
287.997 + glp_sdf_line
287.998 + glp_sdf_open_file
287.999 + glp_sdf_read_int
287.1000 + glp_sdf_read_item
287.1001 + glp_sdf_read_num
287.1002 + glp_sdf_read_text
287.1003 + glp_sdf_set_jump
287.1004 + glp_sdf_warning
287.1005 +;; from glpspm ;;
287.1006 + _glp_spm_add_mat
287.1007 + _glp_spm_add_num
287.1008 + _glp_spm_add_sym
287.1009 + _glp_spm_check_per
287.1010 + _glp_spm_count_nnz
287.1011 + _glp_spm_create_mat
287.1012 + _glp_spm_create_per
287.1013 + _glp_spm_delete_mat
287.1014 + _glp_spm_delete_per
287.1015 + _glp_spm_drop_zeros
287.1016 + _glp_spm_mul_mat
287.1017 + _glp_spm_mul_num
287.1018 + _glp_spm_mul_sym
287.1019 + _glp_spm_new_elem
287.1020 + _glp_spm_read_hbm
287.1021 + _glp_spm_read_mat
287.1022 + _glp_spm_show_mat
287.1023 + _glp_spm_test_mat_d
287.1024 + _glp_spm_test_mat_e
287.1025 + _glp_spm_transpose
287.1026 + _glp_spm_write_mat
287.1027 +;; from glpspx01 ;;
287.1028 + _glp_spx_primal
287.1029 +;; from glpspx02 ;;
287.1030 + _glp_spx_dual
287.1031 +;; from glpsql ;;
287.1032 + _glp_db_iodbc_close
287.1033 + _glp_db_iodbc_open
287.1034 + _glp_db_iodbc_read
287.1035 + _glp_db_iodbc_write
287.1036 + _glp_db_mysql_close
287.1037 + _glp_db_mysql_open
287.1038 + _glp_db_mysql_read
287.1039 + _glp_db_mysql_write
287.1040 +;; from glpssx01 ;;
287.1041 + _glp_ssx_change_basis
287.1042 + _glp_ssx_chuzc
287.1043 + _glp_ssx_chuzr
287.1044 + _glp_ssx_create
287.1045 + _glp_ssx_delete
287.1046 + _glp_ssx_eval_bbar
287.1047 + _glp_ssx_eval_cbar
287.1048 + _glp_ssx_eval_col
287.1049 + _glp_ssx_eval_dj
287.1050 + _glp_ssx_eval_pi
287.1051 + _glp_ssx_eval_rho
287.1052 + _glp_ssx_eval_row
287.1053 + _glp_ssx_factorize
287.1054 + _glp_ssx_get_xNj
287.1055 + _glp_ssx_update_bbar
287.1056 + _glp_ssx_update_cbar
287.1057 + _glp_ssx_update_pi
287.1058 +;; from glpssx02 ;;
287.1059 + _glp_ssx_driver
287.1060 + _glp_ssx_phase_I
287.1061 + _glp_ssx_phase_II
287.1062 +;; from glptsp ;;
287.1063 + _glp_tsp_distance
287.1064 + _glp_tsp_free_data
287.1065 + _glp_tsp_read_data
288.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
288.2 +++ b/w32/readme.txt Mon Dec 06 13:09:21 2010 +0100
288.3 @@ -0,0 +1,24 @@
288.4 +This directory contains batch files and other stuff which you can use
288.5 +to build GLPK for 32-bit Windows with the native C/C++ compilers.
288.6 +
288.7 +Before running the batch file do the following:
288.8 +
288.9 +1. Make sure that you have installed the compiler you are going to use
288.10 + to build GLPK.
288.11 +
288.12 +2. Look into corresponding batch file (just right-click it and choose
288.13 + 'Edit' in the popup menu; DO NOT choose 'Open'). Make sure that HOME
288.14 + variable specifies correct path to the compiler directory; if not,
288.15 + make necessary changes.
288.16 +
288.17 +To run the batch file just double-click it and wait a bit while the
288.18 +Make utility does its job. The message 'OPTIMAL SOLUTION FOUND' in the
288.19 +MS-DOS window means that all is OK. If you do not see it, something is
288.20 +wrong.
288.21 +
288.22 +Once GLPK has been successfully built, there must appear two files in
288.23 +this directory:
288.24 +
288.25 +glpk.lib, which is the GLPK object library, and
288.26 +
288.27 +glpsol.exe, which is the stand-alone GLPK LP/MIP solver.
289.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
289.2 +++ b/w64/Build_GLPK_with_VC10.bat Mon Dec 06 13:09:21 2010 +0100
289.3 @@ -0,0 +1,11 @@
289.4 +rem Build GLPK with Microsoft Visual Studio Express 2010
289.5 +
289.6 +rem NOTE: Make sure that HOME variable specifies correct path
289.7 +set HOME="C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC"
289.8 +
289.9 +call %HOME%\vcvarsall.bat x64
289.10 +copy config_VC config.h
289.11 +%HOME%\bin\nmake.exe /f Makefile_VC
289.12 +%HOME%\bin\nmake.exe /f Makefile_VC check
289.13 +
289.14 +pause
290.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
290.2 +++ b/w64/Build_GLPK_with_VC10_DLL.bat Mon Dec 06 13:09:21 2010 +0100
290.3 @@ -0,0 +1,11 @@
290.4 +rem Build GLPK DLL with Microsoft Visual Studio Express 2010
290.5 +
290.6 +rem NOTE: Make sure that HOME variable specifies correct path
290.7 +set HOME="C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC"
290.8 +
290.9 +call %HOME%\vcvarsall.bat x64
290.10 +copy config_VC config.h
290.11 +%HOME%\bin\nmake.exe /f Makefile_VC_DLL
290.12 +%HOME%\bin\nmake.exe /f Makefile_VC_DLL check
290.13 +
290.14 +pause
291.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
291.2 +++ b/w64/Build_GLPK_with_VC9.bat Mon Dec 06 13:09:21 2010 +0100
291.3 @@ -0,0 +1,11 @@
291.4 +rem Build GLPK with Microsoft Visual Studio Express 2008
291.5 +
291.6 +rem NOTE: Make sure that HOME variable specifies correct path
291.7 +set HOME="C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC"
291.8 +
291.9 +call %HOME%\bin\vcvars64.bat
291.10 +copy config_VC config.h
291.11 +%HOME%\bin\nmake.exe /f Makefile_VC
291.12 +%HOME%\bin\nmake.exe /f Makefile_VC check
291.13 +
291.14 +pause
292.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
292.2 +++ b/w64/Build_GLPK_with_VC9_DLL.bat Mon Dec 06 13:09:21 2010 +0100
292.3 @@ -0,0 +1,11 @@
292.4 +rem Build GLPK DLL with Microsoft Visual Studio Express 2008
292.5 +
292.6 +rem NOTE: Make sure that HOME variable specifies correct path
292.7 +set HOME="C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC"
292.8 +
292.9 +call %HOME%\bin\vcvars64.bat
292.10 +copy config_VC config.h
292.11 +%HOME%\bin\nmake.exe /f Makefile_VC_DLL
292.12 +%HOME%\bin\nmake.exe /f Makefile_VC_DLL check
292.13 +
292.14 +pause
293.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
293.2 +++ b/w64/config_VC Mon Dec 06 13:09:21 2010 +0100
293.3 @@ -0,0 +1,13 @@
293.4 +/* GLPK configuration file (Microsoft Visual Studio Express) */
293.5 +
293.6 +#define __WOE__ 1
293.7 +
293.8 +#define ODBC_DLNAME "odbc32.dll"
293.9 +/* ODBC shared library name if this feature is enabled */
293.10 +
293.11 +#if 0
293.12 +#define MYSQL_DLNAME "libmysql.dll"
293.13 +/* MySQL shared library name if this feature is enabled */
293.14 +#endif
293.15 +
293.16 +/* eof */
294.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
294.2 +++ b/w64/glpk_4_45.def Mon Dec 06 13:09:21 2010 +0100
294.3 @@ -0,0 +1,1062 @@
294.4 +LIBRARY glpk_4_45
294.5 +VERSION 4.45
294.6 +DESCRIPTION "GNU Linear Programming Kit"
294.7 +EXPORTS
294.8 +;; from amd_1 ;;
294.9 + _glp_amd_1
294.10 +;; from amd_2 ;;
294.11 + _glp_amd_2
294.12 +;; from amd_aat ;;
294.13 + _glp_amd_aat
294.14 +;; from amd_control ;;
294.15 + _glp_amd_control
294.16 +;; from amd_defaults ;;
294.17 + _glp_amd_defaults
294.18 +;; from amd_dump ;;
294.19 +;; from amd_info ;;
294.20 + _glp_amd_info
294.21 +;; from amd_order ;;
294.22 + _glp_amd_order
294.23 +;; from amd_post_tree ;;
294.24 + _glp_amd_post_tree
294.25 +;; from amd_postorder ;;
294.26 + _glp_amd_postorder
294.27 +;; from amd_preprocess ;;
294.28 + _glp_amd_preprocess
294.29 +;; from amd_valid ;;
294.30 + _glp_amd_valid
294.31 +;; from colamd ;;
294.32 + _glp_colamd
294.33 + _glp_colamd_recommended
294.34 + _glp_colamd_report
294.35 + _glp_colamd_set_defaults
294.36 + _glp_symamd
294.37 + _glp_symamd_report
294.38 +;; from glpapi01 ;;
294.39 + glp_add_cols
294.40 + glp_add_rows
294.41 + glp_check_dup
294.42 + glp_copy_prob
294.43 + glp_create_prob
294.44 + glp_del_cols
294.45 + glp_del_rows
294.46 + glp_delete_prob
294.47 + glp_erase_prob
294.48 + glp_load_matrix
294.49 + glp_set_col_bnds
294.50 + glp_set_col_name
294.51 + glp_set_mat_col
294.52 + glp_set_mat_row
294.53 + glp_set_obj_coef
294.54 + glp_set_obj_dir
294.55 + glp_set_obj_name
294.56 + glp_set_prob_name
294.57 + glp_set_row_bnds
294.58 + glp_set_row_name
294.59 + glp_sort_matrix
294.60 +;; from glpapi02 ;;
294.61 + glp_get_col_lb
294.62 + glp_get_col_name
294.63 + glp_get_col_type
294.64 + glp_get_col_ub
294.65 + glp_get_mat_col
294.66 + glp_get_mat_row
294.67 + glp_get_num_cols
294.68 + glp_get_num_nz
294.69 + glp_get_num_rows
294.70 + glp_get_obj_coef
294.71 + glp_get_obj_dir
294.72 + glp_get_obj_name
294.73 + glp_get_prob_name
294.74 + glp_get_row_lb
294.75 + glp_get_row_name
294.76 + glp_get_row_type
294.77 + glp_get_row_ub
294.78 +;; from glpapi03 ;;
294.79 + glp_create_index
294.80 + glp_delete_index
294.81 + glp_find_col
294.82 + glp_find_row
294.83 +;; from glpapi04 ;;
294.84 + glp_get_rii
294.85 + glp_get_sjj
294.86 + glp_set_rii
294.87 + glp_set_sjj
294.88 + glp_unscale_prob
294.89 +;; from glpapi05 ;;
294.90 + glp_set_col_stat
294.91 + glp_set_row_stat
294.92 + glp_std_basis
294.93 +;; from glpapi06 ;;
294.94 + glp_get_col_dual
294.95 + glp_get_col_prim
294.96 + glp_get_col_stat
294.97 + glp_get_dual_stat
294.98 + glp_get_obj_val
294.99 + glp_get_prim_stat
294.100 + glp_get_row_dual
294.101 + glp_get_row_prim
294.102 + glp_get_row_stat
294.103 + glp_get_status
294.104 + glp_get_unbnd_ray
294.105 + glp_init_smcp
294.106 + glp_simplex
294.107 +;; from glpapi07 ;;
294.108 + glp_exact
294.109 +;; from glpapi08 ;;
294.110 + glp_init_iptcp
294.111 + glp_interior
294.112 + glp_ipt_col_dual
294.113 + glp_ipt_col_prim
294.114 + glp_ipt_obj_val
294.115 + glp_ipt_row_dual
294.116 + glp_ipt_row_prim
294.117 + glp_ipt_status
294.118 +;; from glpapi09 ;;
294.119 + glp_get_col_kind
294.120 + glp_get_num_bin
294.121 + glp_get_num_int
294.122 + glp_init_iocp
294.123 + glp_intopt
294.124 + glp_mip_col_val
294.125 + glp_mip_obj_val
294.126 + glp_mip_row_val
294.127 + glp_mip_status
294.128 + glp_set_col_kind
294.129 +;; from glpapi10 ;;
294.130 + _glp_check_kkt
294.131 +;; from glpapi11 ;;
294.132 + glp_print_ipt
294.133 + glp_print_mip
294.134 + glp_print_ranges
294.135 + glp_print_sol
294.136 + glp_read_ipt
294.137 + glp_read_mip
294.138 + glp_read_sol
294.139 + glp_write_ipt
294.140 + glp_write_mip
294.141 + glp_write_sol
294.142 +;; from glpapi12 ;;
294.143 + _glp_analyze_row
294.144 + glp_analyze_bound
294.145 + glp_analyze_coef
294.146 + glp_bf_exists
294.147 + glp_bf_updated
294.148 + glp_btran
294.149 + glp_dual_rtest
294.150 + glp_eval_tab_col
294.151 + glp_eval_tab_row
294.152 + glp_factorize
294.153 + glp_ftran
294.154 + glp_get_bfcp
294.155 + glp_get_bhead
294.156 + glp_get_col_bind
294.157 + glp_get_row_bind
294.158 + glp_prim_rtest
294.159 + glp_set_bfcp
294.160 + glp_transform_col
294.161 + glp_transform_row
294.162 + glp_warm_up
294.163 +;; from glpapi13 ;;
294.164 + glp_ios_add_row
294.165 + glp_ios_best_node
294.166 + glp_ios_branch_upon
294.167 + glp_ios_can_branch
294.168 + glp_ios_clear_pool
294.169 + glp_ios_curr_node
294.170 + glp_ios_del_row
294.171 + glp_ios_get_prob
294.172 + glp_ios_heur_sol
294.173 + glp_ios_mip_gap
294.174 + glp_ios_next_node
294.175 + glp_ios_node_bound
294.176 + glp_ios_node_data
294.177 + glp_ios_node_level
294.178 + glp_ios_pool_size
294.179 + glp_ios_prev_node
294.180 + glp_ios_reason
294.181 + glp_ios_row_attr
294.182 + glp_ios_select_node
294.183 + glp_ios_terminate
294.184 + glp_ios_tree_size
294.185 + glp_ios_up_node
294.186 +;; from glpapi14 ;;
294.187 + _glp_mpl_init_rand
294.188 + glp_mpl_alloc_wksp
294.189 + glp_mpl_build_prob
294.190 + glp_mpl_free_wksp
294.191 + glp_mpl_generate
294.192 + glp_mpl_postsolve
294.193 + glp_mpl_read_data
294.194 + glp_mpl_read_model
294.195 +;; from glpapi15 ;;
294.196 + glp_add_arc
294.197 + glp_add_vertices
294.198 + glp_create_graph
294.199 + glp_create_v_index
294.200 + glp_del_arc
294.201 + glp_del_vertices
294.202 + glp_delete_graph
294.203 + glp_delete_v_index
294.204 + glp_erase_graph
294.205 + glp_find_vertex
294.206 + glp_read_graph
294.207 + glp_set_graph_name
294.208 + glp_set_vertex_name
294.209 + glp_write_graph
294.210 +;; from glpapi16 ;;
294.211 + glp_strong_comp
294.212 + glp_top_sort
294.213 + glp_weak_comp
294.214 +;; from glpapi17 ;;
294.215 + glp_asnprob_hall
294.216 + glp_asnprob_lp
294.217 + glp_asnprob_okalg
294.218 + glp_check_asnprob
294.219 + glp_cpp
294.220 + glp_maxflow_ffalg
294.221 + glp_maxflow_lp
294.222 + glp_mincost_lp
294.223 + glp_mincost_okalg
294.224 +;; from glpapi18 ;;
294.225 + glp_wclique_exact
294.226 +;; from glpapi19 ;;
294.227 + glp_main
294.228 +;; from glpavl ;;
294.229 + _glp_avl_create_tree
294.230 + _glp_avl_delete_node
294.231 + _glp_avl_delete_tree
294.232 + _glp_avl_find_node
294.233 + _glp_avl_get_node_link
294.234 + _glp_avl_get_node_type
294.235 + _glp_avl_insert_node
294.236 + _glp_avl_set_node_link
294.237 + _glp_avl_set_node_type
294.238 + _glp_avl_strcmp
294.239 +;; from glpbfd ;;
294.240 + _glp_bfd_btran
294.241 + _glp_bfd_create_it
294.242 + _glp_bfd_delete_it
294.243 + _glp_bfd_factorize
294.244 + _glp_bfd_ftran
294.245 + _glp_bfd_get_count
294.246 + _glp_bfd_set_parm
294.247 + _glp_bfd_update_it
294.248 +;; from glpbfx ;;
294.249 + _glp_bfx_btran
294.250 + _glp_bfx_create_binv
294.251 + _glp_bfx_delete_binv
294.252 + _glp_bfx_factorize
294.253 + _glp_bfx_ftran
294.254 + _glp_bfx_update
294.255 +;; from glpcpx ;;
294.256 + glp_init_cpxcp
294.257 + glp_read_lp
294.258 + glp_write_lp
294.259 +;; from glpdmp ;;
294.260 + _glp_dmp_create_pool
294.261 + _glp_dmp_delete_pool
294.262 + _glp_dmp_free_atom
294.263 + _glp_dmp_get_atom
294.264 + _glp_dmp_in_use
294.265 +;; from glpdmx ;;
294.266 + glp_read_asnprob
294.267 + glp_read_ccdata
294.268 + glp_read_maxflow
294.269 + glp_read_mincost
294.270 + glp_read_prob
294.271 + glp_write_asnprob
294.272 + glp_write_ccdata
294.273 + glp_write_maxflow
294.274 + glp_write_mincost
294.275 + glp_write_prob
294.276 +;; from glpenv01 ;;
294.277 + _glp_get_env_ptr
294.278 + glp_free_env
294.279 + glp_init_env
294.280 + glp_version
294.281 +;; from glpenv02 ;;
294.282 + _glp_tls_get_ptr
294.283 + _glp_tls_set_ptr
294.284 +;; from glpenv03 ;;
294.285 + glp_close_tee
294.286 + glp_open_tee
294.287 + glp_printf
294.288 + glp_term_hook
294.289 + glp_term_out
294.290 + glp_vprintf
294.291 +;; from glpenv04 ;;
294.292 + glp_assert_
294.293 + glp_error_
294.294 + glp_error_hook
294.295 +;; from glpenv05 ;;
294.296 + glp_calloc
294.297 + glp_free
294.298 + glp_malloc
294.299 + glp_mem_limit
294.300 + glp_mem_usage
294.301 +;; from glpenv06 ;;
294.302 + glp_difftime
294.303 + glp_time
294.304 +;; from glpenv07 ;;
294.305 + _glp_lib_err_msg
294.306 + _glp_lib_xerrmsg
294.307 + _glp_lib_xfclose
294.308 + _glp_lib_xfeof
294.309 + _glp_lib_xferror
294.310 + _glp_lib_xfflush
294.311 + _glp_lib_xfgetc
294.312 + _glp_lib_xfopen
294.313 + _glp_lib_xfprintf
294.314 + _glp_lib_xfputc
294.315 +;; from glpenv08 ;;
294.316 + _glp_xdlclose
294.317 + _glp_xdlopen
294.318 + _glp_xdlsym
294.319 +;; from glpfhv ;;
294.320 + _glp_fhv_btran
294.321 + _glp_fhv_create_it
294.322 + _glp_fhv_delete_it
294.323 + _glp_fhv_factorize
294.324 + _glp_fhv_ftran
294.325 + _glp_fhv_h_solve
294.326 + _glp_fhv_update_it
294.327 +;; from glpgmp ;;
294.328 + _glp_gmp_free_atom
294.329 + _glp_gmp_free_mem
294.330 + _glp_gmp_get_atom
294.331 + _glp_gmp_get_work
294.332 + _glp_gmp_pool_count
294.333 + _glp_mpq_abs
294.334 + _glp_mpq_add
294.335 + _glp_mpq_canonicalize
294.336 + _glp_mpq_clear
294.337 + _glp_mpq_cmp
294.338 + _glp_mpq_div
294.339 + _glp_mpq_get_d
294.340 + _glp_mpq_init
294.341 + _glp_mpq_mul
294.342 + _glp_mpq_neg
294.343 + _glp_mpq_out_str
294.344 + _glp_mpq_set
294.345 + _glp_mpq_set_d
294.346 + _glp_mpq_set_si
294.347 + _glp_mpq_sgn
294.348 + _glp_mpq_sub
294.349 + _glp_mpz_abs
294.350 + _glp_mpz_add
294.351 + _glp_mpz_clear
294.352 + _glp_mpz_cmp
294.353 + _glp_mpz_div
294.354 + _glp_mpz_gcd
294.355 + _glp_mpz_get_d
294.356 + _glp_mpz_get_d_2exp
294.357 + _glp_mpz_init
294.358 + _glp_mpz_mul
294.359 + _glp_mpz_neg
294.360 + _glp_mpz_out_str
294.361 + _glp_mpz_set
294.362 + _glp_mpz_set_si
294.363 + _glp_mpz_sgn
294.364 + _glp_mpz_sub
294.365 + _glp_mpz_swap
294.366 +;; from glphbm ;;
294.367 + _glp_hbm_free_mat
294.368 + _glp_hbm_read_mat
294.369 +;; from glpini01 ;;
294.370 + glp_adv_basis
294.371 +;; from glpini02 ;;
294.372 + glp_cpx_basis
294.373 +;; from glpios01 ;;
294.374 + _glp_ios_add_row
294.375 + _glp_ios_best_node
294.376 + _glp_ios_clear_pool
294.377 + _glp_ios_clone_node
294.378 + _glp_ios_create_pool
294.379 + _glp_ios_create_tree
294.380 + _glp_ios_del_row
294.381 + _glp_ios_delete_node
294.382 + _glp_ios_delete_pool
294.383 + _glp_ios_delete_tree
294.384 + _glp_ios_eval_degrad
294.385 + _glp_ios_find_row
294.386 + _glp_ios_freeze_node
294.387 + _glp_ios_is_hopeful
294.388 + _glp_ios_relative_gap
294.389 + _glp_ios_revive_node
294.390 + _glp_ios_round_bound
294.391 + _glp_ios_solve_node
294.392 +;; from glpios02 ;;
294.393 + _glp_ios_preprocess_node
294.394 +;; from glpios03 ;;
294.395 + _glp_ios_driver
294.396 +;; from glpios04 ;;
294.397 + _glp_ios_check_vec
294.398 + _glp_ios_clean_vec
294.399 + _glp_ios_clear_vec
294.400 + _glp_ios_copy_vec
294.401 + _glp_ios_create_vec
294.402 + _glp_ios_delete_vec
294.403 + _glp_ios_get_vj
294.404 + _glp_ios_linear_comb
294.405 + _glp_ios_set_vj
294.406 +;; from glpios05 ;;
294.407 + _glp_ios_gmi_gen
294.408 +;; from glpios06 ;;
294.409 + _glp_ios_mir_gen
294.410 + _glp_ios_mir_init
294.411 + _glp_ios_mir_term
294.412 +;; from glpios07 ;;
294.413 + _glp_ios_cov_gen
294.414 +;; from glpios08 ;;
294.415 + _glp_ios_clq_gen
294.416 + _glp_ios_clq_init
294.417 + _glp_ios_clq_term
294.418 +;; from glpios09 ;;
294.419 + _glp_ios_choose_var
294.420 + _glp_ios_pcost_branch
294.421 + _glp_ios_pcost_free
294.422 + _glp_ios_pcost_init
294.423 + _glp_ios_pcost_update
294.424 +;; from glpios10 ;;
294.425 + _glp_ios_feas_pump
294.426 +;; from glpios11 ;;
294.427 + _glp_ios_process_cuts
294.428 +;; from glpios12 ;;
294.429 + _glp_ios_choose_node
294.430 +;; from glpipm ;;
294.431 + _glp_ipm_solve
294.432 +;; from glplib01 ;;
294.433 + _glp_lib_bigdiv
294.434 + _glp_lib_bigmul
294.435 +;; from glplib02 ;;
294.436 + _glp_lib_xladd
294.437 + _glp_lib_xlcmp
294.438 + _glp_lib_xldiv
294.439 + _glp_lib_xlmul
294.440 + _glp_lib_xlneg
294.441 + _glp_lib_xlset
294.442 + _glp_lib_xlsub
294.443 + _glp_lib_xltoa
294.444 + _glp_lib_xltod
294.445 +;; from glplib03 ;;
294.446 + _glp_lib_fp2rat
294.447 + _glp_lib_gcd
294.448 + _glp_lib_gcdn
294.449 + _glp_lib_jdate
294.450 + _glp_lib_jday
294.451 + _glp_lib_lcm
294.452 + _glp_lib_lcmn
294.453 + _glp_lib_round2n
294.454 + _glp_lib_str2int
294.455 + _glp_lib_str2num
294.456 + _glp_lib_strrev
294.457 + _glp_lib_strspx
294.458 + _glp_lib_strtrim
294.459 +;; from glplpf ;;
294.460 + _glp_lpf_btran
294.461 + _glp_lpf_create_it
294.462 + _glp_lpf_delete_it
294.463 + _glp_lpf_factorize
294.464 + _glp_lpf_ftran
294.465 + _glp_lpf_update_it
294.466 +;; from glplpx01 ;;
294.467 + _glp_lpx_add_cols
294.468 + _glp_lpx_add_rows
294.469 + _glp_lpx_adv_basis
294.470 + _glp_lpx_check_int
294.471 + _glp_lpx_check_kkt
294.472 + _glp_lpx_cpx_basis
294.473 + _glp_lpx_create_index
294.474 + _glp_lpx_create_prob
294.475 + _glp_lpx_del_cols
294.476 + _glp_lpx_del_rows
294.477 + _glp_lpx_delete_index
294.478 + _glp_lpx_delete_prob
294.479 + _glp_lpx_dual_ratio_test
294.480 + _glp_lpx_eval_tab_col
294.481 + _glp_lpx_eval_tab_row
294.482 + _glp_lpx_exact
294.483 + _glp_lpx_find_col
294.484 + _glp_lpx_find_row
294.485 + _glp_lpx_get_class
294.486 + _glp_lpx_get_col_bnds
294.487 + _glp_lpx_get_col_dual
294.488 + _glp_lpx_get_col_info
294.489 + _glp_lpx_get_col_kind
294.490 + _glp_lpx_get_col_lb
294.491 + _glp_lpx_get_col_name
294.492 + _glp_lpx_get_col_prim
294.493 + _glp_lpx_get_col_stat
294.494 + _glp_lpx_get_col_type
294.495 + _glp_lpx_get_col_ub
294.496 + _glp_lpx_get_dual_stat
294.497 + _glp_lpx_get_int_parm
294.498 + _glp_lpx_get_mat_col
294.499 + _glp_lpx_get_mat_row
294.500 + _glp_lpx_get_num_bin
294.501 + _glp_lpx_get_num_cols
294.502 + _glp_lpx_get_num_int
294.503 + _glp_lpx_get_num_nz
294.504 + _glp_lpx_get_num_rows
294.505 + _glp_lpx_get_obj_coef
294.506 + _glp_lpx_get_obj_dir
294.507 + _glp_lpx_get_obj_name
294.508 + _glp_lpx_get_obj_val
294.509 + _glp_lpx_get_prim_stat
294.510 + _glp_lpx_get_prob_name
294.511 + _glp_lpx_get_ray_info
294.512 + _glp_lpx_get_real_parm
294.513 + _glp_lpx_get_row_bnds
294.514 + _glp_lpx_get_row_dual
294.515 + _glp_lpx_get_row_info
294.516 + _glp_lpx_get_row_lb
294.517 + _glp_lpx_get_row_name
294.518 + _glp_lpx_get_row_prim
294.519 + _glp_lpx_get_row_stat
294.520 + _glp_lpx_get_row_type
294.521 + _glp_lpx_get_row_ub
294.522 + _glp_lpx_get_status
294.523 + _glp_lpx_integer
294.524 + _glp_lpx_interior
294.525 + _glp_lpx_intopt
294.526 + _glp_lpx_ipt_col_dual
294.527 + _glp_lpx_ipt_col_prim
294.528 + _glp_lpx_ipt_obj_val
294.529 + _glp_lpx_ipt_row_dual
294.530 + _glp_lpx_ipt_row_prim
294.531 + _glp_lpx_ipt_status
294.532 + _glp_lpx_is_b_avail
294.533 + _glp_lpx_load_matrix
294.534 + _glp_lpx_main
294.535 + _glp_lpx_mip_col_val
294.536 + _glp_lpx_mip_obj_val
294.537 + _glp_lpx_mip_row_val
294.538 + _glp_lpx_mip_status
294.539 + _glp_lpx_prim_ratio_test
294.540 + _glp_lpx_print_ips
294.541 + _glp_lpx_print_mip
294.542 + _glp_lpx_print_prob
294.543 + _glp_lpx_print_sens_bnds
294.544 + _glp_lpx_print_sol
294.545 + _glp_lpx_read_bas
294.546 + _glp_lpx_read_cpxlp
294.547 + _glp_lpx_read_freemps
294.548 + _glp_lpx_read_model
294.549 + _glp_lpx_read_mps
294.550 + _glp_lpx_reset_parms
294.551 + _glp_lpx_scale_prob
294.552 + _glp_lpx_set_class
294.553 + _glp_lpx_set_col_bnds
294.554 + _glp_lpx_set_col_kind
294.555 + _glp_lpx_set_col_name
294.556 + _glp_lpx_set_col_stat
294.557 + _glp_lpx_set_int_parm
294.558 + _glp_lpx_set_mat_col
294.559 + _glp_lpx_set_mat_row
294.560 + _glp_lpx_set_obj_coef
294.561 + _glp_lpx_set_obj_dir
294.562 + _glp_lpx_set_obj_name
294.563 + _glp_lpx_set_prob_name
294.564 + _glp_lpx_set_real_parm
294.565 + _glp_lpx_set_row_bnds
294.566 + _glp_lpx_set_row_name
294.567 + _glp_lpx_set_row_stat
294.568 + _glp_lpx_simplex
294.569 + _glp_lpx_std_basis
294.570 + _glp_lpx_transform_col
294.571 + _glp_lpx_transform_row
294.572 + _glp_lpx_unscale_prob
294.573 + _glp_lpx_warm_up
294.574 + _glp_lpx_write_bas
294.575 + _glp_lpx_write_cpxlp
294.576 + _glp_lpx_write_freemps
294.577 + _glp_lpx_write_mps
294.578 +;; from glplpx02 ;;
294.579 + _glp_put_mip_soln
294.580 + _glp_put_solution
294.581 +;; from glplpx03 ;;
294.582 + _glp_lpx_write_pb
294.583 +;; from glpluf ;;
294.584 + _glp_luf_a_solve
294.585 + _glp_luf_create_it
294.586 + _glp_luf_defrag_sva
294.587 + _glp_luf_delete_it
294.588 + _glp_luf_enlarge_col
294.589 + _glp_luf_enlarge_row
294.590 + _glp_luf_f_solve
294.591 + _glp_luf_factorize
294.592 + _glp_luf_v_solve
294.593 +;; from glplux ;;
294.594 + _glp_lux_create
294.595 + _glp_lux_decomp
294.596 + _glp_lux_delete
294.597 + _glp_lux_f_solve
294.598 + _glp_lux_solve
294.599 + _glp_lux_v_solve
294.600 +;; from glpmat ;;
294.601 + _glp_mat_adat_numeric
294.602 + _glp_mat_adat_symbolic
294.603 + _glp_mat_amd_order1
294.604 + _glp_mat_check_fvs
294.605 + _glp_mat_check_pattern
294.606 + _glp_mat_chol_numeric
294.607 + _glp_mat_chol_symbolic
294.608 + _glp_mat_min_degree
294.609 + _glp_mat_symamd_ord
294.610 + _glp_mat_transpose
294.611 + _glp_mat_u_solve
294.612 + _glp_mat_ut_solve
294.613 +;; from glpmpl01 ;;
294.614 + _glp_mpl_append_block
294.615 + _glp_mpl_append_char
294.616 + _glp_mpl_append_slot
294.617 + _glp_mpl_arg_list_len
294.618 + _glp_mpl_branched_expression
294.619 + _glp_mpl_check_statement
294.620 + _glp_mpl_close_scope
294.621 + _glp_mpl_constraint_statement
294.622 + _glp_mpl_create_arg_list
294.623 + _glp_mpl_create_block
294.624 + _glp_mpl_create_domain
294.625 + _glp_mpl_display_statement
294.626 + _glp_mpl_domain_arity
294.627 + _glp_mpl_elemset_argument
294.628 + _glp_mpl_end_statement
294.629 + _glp_mpl_enter_context
294.630 + _glp_mpl_error_dimension
294.631 + _glp_mpl_error_following
294.632 + _glp_mpl_error_preceding
294.633 + _glp_mpl_expand_arg_list
294.634 + _glp_mpl_expression_0
294.635 + _glp_mpl_expression_1
294.636 + _glp_mpl_expression_10
294.637 + _glp_mpl_expression_11
294.638 + _glp_mpl_expression_12
294.639 + _glp_mpl_expression_13
294.640 + _glp_mpl_expression_2
294.641 + _glp_mpl_expression_3
294.642 + _glp_mpl_expression_4
294.643 + _glp_mpl_expression_5
294.644 + _glp_mpl_expression_6
294.645 + _glp_mpl_expression_7
294.646 + _glp_mpl_expression_8
294.647 + _glp_mpl_expression_9
294.648 + _glp_mpl_expression_list
294.649 + _glp_mpl_for_statement
294.650 + _glp_mpl_function_reference
294.651 + _glp_mpl_get_char
294.652 + _glp_mpl_get_token
294.653 + _glp_mpl_indexing_expression
294.654 + _glp_mpl_is_keyword
294.655 + _glp_mpl_is_reserved
294.656 + _glp_mpl_iterated_expression
294.657 + _glp_mpl_literal_set
294.658 + _glp_mpl_make_binary
294.659 + _glp_mpl_make_code
294.660 + _glp_mpl_make_ternary
294.661 + _glp_mpl_make_unary
294.662 + _glp_mpl_model_section
294.663 + _glp_mpl_numeric_argument
294.664 + _glp_mpl_numeric_literal
294.665 + _glp_mpl_object_reference
294.666 + _glp_mpl_objective_statement
294.667 + _glp_mpl_parameter_statement
294.668 + _glp_mpl_primary_expression
294.669 + _glp_mpl_print_context
294.670 + _glp_mpl_printf_statement
294.671 + _glp_mpl_set_expression
294.672 + _glp_mpl_set_statement
294.673 + _glp_mpl_simple_statement
294.674 + _glp_mpl_solve_statement
294.675 + _glp_mpl_string_literal
294.676 + _glp_mpl_subscript_list
294.677 + _glp_mpl_symbolic_argument
294.678 + _glp_mpl_table_statement
294.679 + _glp_mpl_unget_token
294.680 + _glp_mpl_variable_statement
294.681 +;; from glpmpl02 ;;
294.682 + _glp_mpl_create_slice
294.683 + _glp_mpl_data_section
294.684 + _glp_mpl_delete_slice
294.685 + _glp_mpl_expand_slice
294.686 + _glp_mpl_fake_slice
294.687 + _glp_mpl_is_literal
294.688 + _glp_mpl_is_number
294.689 + _glp_mpl_is_symbol
294.690 + _glp_mpl_matrix_format
294.691 + _glp_mpl_parameter_data
294.692 + _glp_mpl_plain_format
294.693 + _glp_mpl_read_number
294.694 + _glp_mpl_read_slice
294.695 + _glp_mpl_read_symbol
294.696 + _glp_mpl_read_value
294.697 + _glp_mpl_select_parameter
294.698 + _glp_mpl_select_set
294.699 + _glp_mpl_set_data
294.700 + _glp_mpl_set_default
294.701 + _glp_mpl_simple_format
294.702 + _glp_mpl_slice_arity
294.703 + _glp_mpl_slice_dimen
294.704 + _glp_mpl_tabbing_format
294.705 + _glp_mpl_tabular_format
294.706 +;; from glpmpl03 ;;
294.707 + _glp_mpl_add_member
294.708 + _glp_mpl_add_tuple
294.709 + _glp_mpl_arelset_member
294.710 + _glp_mpl_arelset_size
294.711 + _glp_mpl_assign_dummy_index
294.712 + _glp_mpl_build_subtuple
294.713 + _glp_mpl_check_elem_set
294.714 + _glp_mpl_check_then_add
294.715 + _glp_mpl_check_value_num
294.716 + _glp_mpl_check_value_sym
294.717 + _glp_mpl_clean_check
294.718 + _glp_mpl_clean_code
294.719 + _glp_mpl_clean_constraint
294.720 + _glp_mpl_clean_display
294.721 + _glp_mpl_clean_domain
294.722 + _glp_mpl_clean_for
294.723 + _glp_mpl_clean_parameter
294.724 + _glp_mpl_clean_printf
294.725 + _glp_mpl_clean_set
294.726 + _glp_mpl_clean_statement
294.727 + _glp_mpl_clean_table
294.728 + _glp_mpl_clean_variable
294.729 + _glp_mpl_compare_strings
294.730 + _glp_mpl_compare_symbols
294.731 + _glp_mpl_compare_tuples
294.732 + _glp_mpl_concat_symbols
294.733 + _glp_mpl_constant_term
294.734 + _glp_mpl_copy_elemset
294.735 + _glp_mpl_copy_formula
294.736 + _glp_mpl_copy_string
294.737 + _glp_mpl_copy_symbol
294.738 + _glp_mpl_copy_tuple
294.739 + _glp_mpl_create_arelset
294.740 + _glp_mpl_create_array
294.741 + _glp_mpl_create_elemset
294.742 + _glp_mpl_create_string
294.743 + _glp_mpl_create_symbol_num
294.744 + _glp_mpl_create_symbol_str
294.745 + _glp_mpl_create_tuple
294.746 + _glp_mpl_delete_array
294.747 + _glp_mpl_delete_elemset
294.748 + _glp_mpl_delete_formula
294.749 + _glp_mpl_delete_string
294.750 + _glp_mpl_delete_symbol
294.751 + _glp_mpl_delete_tuple
294.752 + _glp_mpl_delete_value
294.753 + _glp_mpl_enter_domain_block
294.754 + _glp_mpl_eval_elemset
294.755 + _glp_mpl_eval_formula
294.756 + _glp_mpl_eval_logical
294.757 + _glp_mpl_eval_member_con
294.758 + _glp_mpl_eval_member_num
294.759 + _glp_mpl_eval_member_set
294.760 + _glp_mpl_eval_member_sym
294.761 + _glp_mpl_eval_member_var
294.762 + _glp_mpl_eval_numeric
294.763 + _glp_mpl_eval_symbolic
294.764 + _glp_mpl_eval_tuple
294.765 + _glp_mpl_eval_whole_con
294.766 + _glp_mpl_eval_whole_par
294.767 + _glp_mpl_eval_whole_set
294.768 + _glp_mpl_eval_whole_var
294.769 + _glp_mpl_eval_within_domain
294.770 + _glp_mpl_execute_check
294.771 + _glp_mpl_execute_display
294.772 + _glp_mpl_execute_for
294.773 + _glp_mpl_execute_printf
294.774 + _glp_mpl_execute_statement
294.775 + _glp_mpl_execute_table
294.776 + _glp_mpl_expand_tuple
294.777 + _glp_mpl_fetch_string
294.778 + _glp_mpl_find_member
294.779 + _glp_mpl_find_tuple
294.780 + _glp_mpl_format_symbol
294.781 + _glp_mpl_format_tuple
294.782 + _glp_mpl_fp_add
294.783 + _glp_mpl_fp_atan
294.784 + _glp_mpl_fp_atan2
294.785 + _glp_mpl_fp_cos
294.786 + _glp_mpl_fp_div
294.787 + _glp_mpl_fp_exp
294.788 + _glp_mpl_fp_idiv
294.789 + _glp_mpl_fp_irand224
294.790 + _glp_mpl_fp_less
294.791 + _glp_mpl_fp_log
294.792 + _glp_mpl_fp_log10
294.793 + _glp_mpl_fp_mod
294.794 + _glp_mpl_fp_mul
294.795 + _glp_mpl_fp_normal
294.796 + _glp_mpl_fp_normal01
294.797 + _glp_mpl_fp_power
294.798 + _glp_mpl_fp_round
294.799 + _glp_mpl_fp_sin
294.800 + _glp_mpl_fp_sqrt
294.801 + _glp_mpl_fp_sub
294.802 + _glp_mpl_fp_trunc
294.803 + _glp_mpl_fp_uniform01
294.804 + _glp_mpl_free_dca
294.805 + _glp_mpl_get_domain_tuple
294.806 + _glp_mpl_is_member
294.807 + _glp_mpl_linear_comb
294.808 + _glp_mpl_loop_within_domain
294.809 + _glp_mpl_out_of_domain
294.810 + _glp_mpl_reduce_terms
294.811 + _glp_mpl_remove_constant
294.812 + _glp_mpl_set_cross
294.813 + _glp_mpl_set_diff
294.814 + _glp_mpl_set_inter
294.815 + _glp_mpl_set_symdiff
294.816 + _glp_mpl_set_union
294.817 + _glp_mpl_single_variable
294.818 + _glp_mpl_tab_get_arg
294.819 + _glp_mpl_tab_get_name
294.820 + _glp_mpl_tab_get_num
294.821 + _glp_mpl_tab_get_str
294.822 + _glp_mpl_tab_get_type
294.823 + _glp_mpl_tab_num_args
294.824 + _glp_mpl_tab_num_flds
294.825 + _glp_mpl_tab_set_num
294.826 + _glp_mpl_tab_set_str
294.827 + _glp_mpl_take_member_con
294.828 + _glp_mpl_take_member_num
294.829 + _glp_mpl_take_member_set
294.830 + _glp_mpl_take_member_sym
294.831 + _glp_mpl_take_member_var
294.832 + _glp_mpl_tuple_dimen
294.833 + _glp_mpl_uniform
294.834 + _glp_mpl_update_dummy_indices
294.835 +;; from glpmpl04 ;;
294.836 + _glp_mpl_alloc_content
294.837 + _glp_mpl_build_problem
294.838 + _glp_mpl_clean_model
294.839 + _glp_mpl_close_input
294.840 + _glp_mpl_error
294.841 + _glp_mpl_flush_output
294.842 + _glp_mpl_generate
294.843 + _glp_mpl_generate_model
294.844 + _glp_mpl_get_col_bnds
294.845 + _glp_mpl_get_col_kind
294.846 + _glp_mpl_get_col_name
294.847 + _glp_mpl_get_mat_row
294.848 + _glp_mpl_get_num_cols
294.849 + _glp_mpl_get_num_rows
294.850 + _glp_mpl_get_prob_name
294.851 + _glp_mpl_get_row_bnds
294.852 + _glp_mpl_get_row_c0
294.853 + _glp_mpl_get_row_kind
294.854 + _glp_mpl_get_row_name
294.855 + _glp_mpl_has_solve_stmt
294.856 + _glp_mpl_initialize
294.857 + _glp_mpl_open_input
294.858 + _glp_mpl_open_output
294.859 + _glp_mpl_postsolve
294.860 + _glp_mpl_postsolve_model
294.861 + _glp_mpl_put_col_soln
294.862 + _glp_mpl_put_row_soln
294.863 + _glp_mpl_read_char
294.864 + _glp_mpl_read_data
294.865 + _glp_mpl_read_model
294.866 + _glp_mpl_terminate
294.867 + _glp_mpl_warning
294.868 + _glp_mpl_write_char
294.869 + _glp_mpl_write_text
294.870 +;; from glpmpl05 ;;
294.871 + _glp_mpl_fn_gmtime
294.872 + _glp_mpl_fn_str2time
294.873 + _glp_mpl_fn_time2str
294.874 +;; from glpmpl06 ;;
294.875 + _glp_mpl_tab_drv_close
294.876 + _glp_mpl_tab_drv_open
294.877 + _glp_mpl_tab_drv_read
294.878 + _glp_mpl_tab_drv_write
294.879 +;; from glpmps ;;
294.880 + glp_init_mpscp
294.881 + glp_read_mps
294.882 + glp_write_mps
294.883 +;; from glpnet01 ;;
294.884 + _glp_mc21a
294.885 +;; from glpnet02 ;;
294.886 + _glp_mc13d
294.887 +;; from glpnet03 ;;
294.888 + glp_netgen
294.889 +;; from glpnet04 ;;
294.890 + glp_gridgen
294.891 +;; from glpnet05 ;;
294.892 + glp_rmfgen
294.893 +;; from glpnet06 ;;
294.894 + _glp_okalg
294.895 +;; from glpnet07 ;;
294.896 + _glp_ffalg
294.897 +;; from glpnet08 ;;
294.898 + _glp_wclique
294.899 +;; from glpnet09 ;;
294.900 + _glp_kellerman
294.901 +;; from glpnpp01 ;;
294.902 + _glp_npp_activate_col
294.903 + _glp_npp_activate_row
294.904 + _glp_npp_add_aij
294.905 + _glp_npp_add_col
294.906 + _glp_npp_add_row
294.907 + _glp_npp_build_prob
294.908 + _glp_npp_col_nnz
294.909 + _glp_npp_create_wksp
294.910 + _glp_npp_deactivate_col
294.911 + _glp_npp_deactivate_row
294.912 + _glp_npp_del_aij
294.913 + _glp_npp_del_col
294.914 + _glp_npp_del_row
294.915 + _glp_npp_delete_wksp
294.916 + _glp_npp_erase_row
294.917 + _glp_npp_insert_col
294.918 + _glp_npp_insert_row
294.919 + _glp_npp_load_prob
294.920 + _glp_npp_postprocess
294.921 + _glp_npp_push_tse
294.922 + _glp_npp_remove_col
294.923 + _glp_npp_remove_row
294.924 + _glp_npp_row_nnz
294.925 + _glp_npp_unload_sol
294.926 +;; from glpnpp02 ;;
294.927 + _glp_npp_dbnd_col
294.928 + _glp_npp_fixed_col
294.929 + _glp_npp_free_col
294.930 + _glp_npp_free_row
294.931 + _glp_npp_geq_row
294.932 + _glp_npp_lbnd_col
294.933 + _glp_npp_leq_row
294.934 + _glp_npp_make_equality
294.935 + _glp_npp_make_fixed
294.936 + _glp_npp_ubnd_col
294.937 +;; from glpnpp03 ;;
294.938 + _glp_npp_analyze_row
294.939 + _glp_npp_empty_col
294.940 + _glp_npp_empty_row
294.941 + _glp_npp_eq_doublet
294.942 + _glp_npp_eq_singlet
294.943 + _glp_npp_forcing_row
294.944 + _glp_npp_implied_bounds
294.945 + _glp_npp_implied_free
294.946 + _glp_npp_implied_lower
294.947 + _glp_npp_implied_slack
294.948 + _glp_npp_implied_upper
294.949 + _glp_npp_implied_value
294.950 + _glp_npp_inactive_bound
294.951 + _glp_npp_ineq_singlet
294.952 +;; from glpnpp04 ;;
294.953 + _glp_npp_binarize_prob
294.954 + _glp_npp_hidden_covering
294.955 + _glp_npp_hidden_packing
294.956 + _glp_npp_implied_packing
294.957 + _glp_npp_is_covering
294.958 + _glp_npp_is_packing
294.959 + _glp_npp_is_partitioning
294.960 + _glp_npp_reduce_ineq_coef
294.961 +;; from glpnpp05 ;;
294.962 + _glp_npp_clean_prob
294.963 + _glp_npp_improve_bounds
294.964 + _glp_npp_integer
294.965 + _glp_npp_process_col
294.966 + _glp_npp_process_prob
294.967 + _glp_npp_process_row
294.968 + _glp_npp_simplex
294.969 +;; from glpqmd ;;
294.970 + _glp_qmd_genqmd
294.971 + _glp_qmd_qmdmrg
294.972 + _glp_qmd_qmdqt
294.973 + _glp_qmd_qmdrch
294.974 + _glp_qmd_qmdupd
294.975 +;; from glprgr ;;
294.976 + _glp_rgr_write_bmp16
294.977 +;; from glprng01 ;;
294.978 + _glp_rng_create_rand
294.979 + _glp_rng_delete_rand
294.980 + _glp_rng_init_rand
294.981 + _glp_rng_next_rand
294.982 + _glp_rng_unif_rand
294.983 +;; from glprng02 ;;
294.984 + _glp_rng_unif_01
294.985 + _glp_rng_uniform
294.986 +;; from glpscf ;;
294.987 + _glp_scf_create_it
294.988 + _glp_scf_delete_it
294.989 + _glp_scf_reset_it
294.990 + _glp_scf_solve_it
294.991 + _glp_scf_update_exp
294.992 +;; from glpscl ;;
294.993 + glp_scale_prob
294.994 +;; from glpsdf ;;
294.995 + glp_sdf_close_file
294.996 + glp_sdf_error
294.997 + glp_sdf_line
294.998 + glp_sdf_open_file
294.999 + glp_sdf_read_int
294.1000 + glp_sdf_read_item
294.1001 + glp_sdf_read_num
294.1002 + glp_sdf_read_text
294.1003 + glp_sdf_set_jump
294.1004 + glp_sdf_warning
294.1005 +;; from glpspm ;;
294.1006 + _glp_spm_add_mat
294.1007 + _glp_spm_add_num
294.1008 + _glp_spm_add_sym
294.1009 + _glp_spm_check_per
294.1010 + _glp_spm_count_nnz
294.1011 + _glp_spm_create_mat
294.1012 + _glp_spm_create_per
294.1013 + _glp_spm_delete_mat
294.1014 + _glp_spm_delete_per
294.1015 + _glp_spm_drop_zeros
294.1016 + _glp_spm_mul_mat
294.1017 + _glp_spm_mul_num
294.1018 + _glp_spm_mul_sym
294.1019 + _glp_spm_new_elem
294.1020 + _glp_spm_read_hbm
294.1021 + _glp_spm_read_mat
294.1022 + _glp_spm_show_mat
294.1023 + _glp_spm_test_mat_d
294.1024 + _glp_spm_test_mat_e
294.1025 + _glp_spm_transpose
294.1026 + _glp_spm_write_mat
294.1027 +;; from glpspx01 ;;
294.1028 + _glp_spx_primal
294.1029 +;; from glpspx02 ;;
294.1030 + _glp_spx_dual
294.1031 +;; from glpsql ;;
294.1032 + _glp_db_iodbc_close
294.1033 + _glp_db_iodbc_open
294.1034 + _glp_db_iodbc_read
294.1035 + _glp_db_iodbc_write
294.1036 + _glp_db_mysql_close
294.1037 + _glp_db_mysql_open
294.1038 + _glp_db_mysql_read
294.1039 + _glp_db_mysql_write
294.1040 +;; from glpssx01 ;;
294.1041 + _glp_ssx_change_basis
294.1042 + _glp_ssx_chuzc
294.1043 + _glp_ssx_chuzr
294.1044 + _glp_ssx_create
294.1045 + _glp_ssx_delete
294.1046 + _glp_ssx_eval_bbar
294.1047 + _glp_ssx_eval_cbar
294.1048 + _glp_ssx_eval_col
294.1049 + _glp_ssx_eval_dj
294.1050 + _glp_ssx_eval_pi
294.1051 + _glp_ssx_eval_rho
294.1052 + _glp_ssx_eval_row
294.1053 + _glp_ssx_factorize
294.1054 + _glp_ssx_get_xNj
294.1055 + _glp_ssx_update_bbar
294.1056 + _glp_ssx_update_cbar
294.1057 + _glp_ssx_update_pi
294.1058 +;; from glpssx02 ;;
294.1059 + _glp_ssx_driver
294.1060 + _glp_ssx_phase_I
294.1061 + _glp_ssx_phase_II
294.1062 +;; from glptsp ;;
294.1063 + _glp_tsp_distance
294.1064 + _glp_tsp_free_data
294.1065 + _glp_tsp_read_data
295.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
295.2 +++ b/w64/makefile_VC Mon Dec 06 13:09:21 2010 +0100
295.3 @@ -0,0 +1,132 @@
295.4 +# Build GLPK with Microsoft Visual Studio Express
295.5 +
295.6 +CFLAGS = /I. /I..\include /I..\src /I..\src\amd /I..\src\colamd \
295.7 + /DHAVE_CONFIG_H /D_CRT_SECURE_NO_WARNINGS /nologo /W3 /O2
295.8 +
295.9 +OBJSET = \
295.10 +..\src\glpapi01.obj \
295.11 +..\src\glpapi02.obj \
295.12 +..\src\glpapi03.obj \
295.13 +..\src\glpapi04.obj \
295.14 +..\src\glpapi05.obj \
295.15 +..\src\glpapi06.obj \
295.16 +..\src\glpapi07.obj \
295.17 +..\src\glpapi08.obj \
295.18 +..\src\glpapi09.obj \
295.19 +..\src\glpapi10.obj \
295.20 +..\src\glpapi11.obj \
295.21 +..\src\glpapi12.obj \
295.22 +..\src\glpapi13.obj \
295.23 +..\src\glpapi14.obj \
295.24 +..\src\glpapi15.obj \
295.25 +..\src\glpapi16.obj \
295.26 +..\src\glpapi17.obj \
295.27 +..\src\glpapi18.obj \
295.28 +..\src\glpapi19.obj \
295.29 +..\src\glpavl.obj \
295.30 +..\src\glpbfd.obj \
295.31 +..\src\glpbfx.obj \
295.32 +..\src\glpcpx.obj \
295.33 +..\src\glpdmp.obj \
295.34 +..\src\glpdmx.obj \
295.35 +..\src\glpenv01.obj \
295.36 +..\src\glpenv02.obj \
295.37 +..\src\glpenv03.obj \
295.38 +..\src\glpenv04.obj \
295.39 +..\src\glpenv05.obj \
295.40 +..\src\glpenv06.obj \
295.41 +..\src\glpenv07.obj \
295.42 +..\src\glpenv08.obj \
295.43 +..\src\glpfhv.obj \
295.44 +..\src\glpgmp.obj \
295.45 +..\src\glphbm.obj \
295.46 +..\src\glpini01.obj \
295.47 +..\src\glpini02.obj \
295.48 +..\src\glpios01.obj \
295.49 +..\src\glpios02.obj \
295.50 +..\src\glpios03.obj \
295.51 +..\src\glpios04.obj \
295.52 +..\src\glpios05.obj \
295.53 +..\src\glpios06.obj \
295.54 +..\src\glpios07.obj \
295.55 +..\src\glpios08.obj \
295.56 +..\src\glpios09.obj \
295.57 +..\src\glpios10.obj \
295.58 +..\src\glpios11.obj \
295.59 +..\src\glpios12.obj \
295.60 +..\src\glpipm.obj \
295.61 +..\src\glplib01.obj \
295.62 +..\src\glplib02.obj \
295.63 +..\src\glplib03.obj \
295.64 +..\src\glplpf.obj \
295.65 +..\src\glplpx01.obj \
295.66 +..\src\glplpx02.obj \
295.67 +..\src\glplpx03.obj \
295.68 +..\src\glpluf.obj \
295.69 +..\src\glplux.obj \
295.70 +..\src\glpmat.obj \
295.71 +..\src\glpmpl01.obj \
295.72 +..\src\glpmpl02.obj \
295.73 +..\src\glpmpl03.obj \
295.74 +..\src\glpmpl04.obj \
295.75 +..\src\glpmpl05.obj \
295.76 +..\src\glpmpl06.obj \
295.77 +..\src\glpmps.obj \
295.78 +..\src\glpnet01.obj \
295.79 +..\src\glpnet02.obj \
295.80 +..\src\glpnet03.obj \
295.81 +..\src\glpnet04.obj \
295.82 +..\src\glpnet05.obj \
295.83 +..\src\glpnet06.obj \
295.84 +..\src\glpnet07.obj \
295.85 +..\src\glpnet08.obj \
295.86 +..\src\glpnet09.obj \
295.87 +..\src\glpnpp01.obj \
295.88 +..\src\glpnpp02.obj \
295.89 +..\src\glpnpp03.obj \
295.90 +..\src\glpnpp04.obj \
295.91 +..\src\glpnpp05.obj \
295.92 +..\src\glpqmd.obj \
295.93 +..\src\glprgr.obj \
295.94 +..\src\glprng01.obj \
295.95 +..\src\glprng02.obj \
295.96 +..\src\glpscf.obj \
295.97 +..\src\glpscl.obj \
295.98 +..\src\glpsdf.obj \
295.99 +..\src\glpspm.obj \
295.100 +..\src\glpspx01.obj \
295.101 +..\src\glpspx02.obj \
295.102 +..\src\glpsql.obj \
295.103 +..\src\glpssx01.obj \
295.104 +..\src\glpssx02.obj \
295.105 +..\src\glptsp.obj \
295.106 +..\src\amd\amd_1.obj \
295.107 +..\src\amd\amd_2.obj \
295.108 +..\src\amd\amd_aat.obj \
295.109 +..\src\amd\amd_control.obj \
295.110 +..\src\amd\amd_defaults.obj \
295.111 +..\src\amd\amd_dump.obj \
295.112 +..\src\amd\amd_info.obj \
295.113 +..\src\amd\amd_order.obj \
295.114 +..\src\amd\amd_post_tree.obj \
295.115 +..\src\amd\amd_postorder.obj \
295.116 +..\src\amd\amd_preprocess.obj \
295.117 +..\src\amd\amd_valid.obj \
295.118 +..\src\colamd\colamd.obj
295.119 +
295.120 +.c.obj:
295.121 + cl.exe $(CFLAGS) /Fo$*.obj /c $*.c
295.122 +
295.123 +all: glpk.lib glpsol.exe
295.124 +
295.125 +glpk.lib: $(OBJSET)
295.126 + lib.exe /out:glpk.lib ..\src\*.obj ..\src\amd\*.obj \
295.127 + ..\src\colamd\*.obj
295.128 +
295.129 +glpsol.exe: ..\examples\glpsol.obj glpk.lib
295.130 + cl.exe $(CFLAGS) /Feglpsol.exe ..\examples\glpsol.obj \
295.131 + glpk.lib
295.132 +
295.133 +check: glpsol.exe
295.134 + .\glpsol.exe --version
295.135 + .\glpsol.exe --mps ..\examples\plan.mps
296.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
296.2 +++ b/w64/makefile_VC_DLL Mon Dec 06 13:09:21 2010 +0100
296.3 @@ -0,0 +1,132 @@
296.4 +# Build GLPK DLL with Microsoft Visual Studio Express
296.5 +
296.6 +CFLAGS = /I. /I..\include /I..\src /I..\src\amd /I..\src\colamd \
296.7 + /DHAVE_CONFIG_H /D_CRT_SECURE_NO_WARNINGS /nologo /W3 /O2
296.8 +
296.9 +OBJSET = \
296.10 +..\src\glpapi01.obj \
296.11 +..\src\glpapi02.obj \
296.12 +..\src\glpapi03.obj \
296.13 +..\src\glpapi04.obj \
296.14 +..\src\glpapi05.obj \
296.15 +..\src\glpapi06.obj \
296.16 +..\src\glpapi07.obj \
296.17 +..\src\glpapi08.obj \
296.18 +..\src\glpapi09.obj \
296.19 +..\src\glpapi10.obj \
296.20 +..\src\glpapi11.obj \
296.21 +..\src\glpapi12.obj \
296.22 +..\src\glpapi13.obj \
296.23 +..\src\glpapi14.obj \
296.24 +..\src\glpapi15.obj \
296.25 +..\src\glpapi16.obj \
296.26 +..\src\glpapi17.obj \
296.27 +..\src\glpapi18.obj \
296.28 +..\src\glpapi19.obj \
296.29 +..\src\glpavl.obj \
296.30 +..\src\glpbfd.obj \
296.31 +..\src\glpbfx.obj \
296.32 +..\src\glpcpx.obj \
296.33 +..\src\glpdmp.obj \
296.34 +..\src\glpdmx.obj \
296.35 +..\src\glpenv01.obj \
296.36 +..\src\glpenv02.obj \
296.37 +..\src\glpenv03.obj \
296.38 +..\src\glpenv04.obj \
296.39 +..\src\glpenv05.obj \
296.40 +..\src\glpenv06.obj \
296.41 +..\src\glpenv07.obj \
296.42 +..\src\glpenv08.obj \
296.43 +..\src\glpfhv.obj \
296.44 +..\src\glpgmp.obj \
296.45 +..\src\glphbm.obj \
296.46 +..\src\glpini01.obj \
296.47 +..\src\glpini02.obj \
296.48 +..\src\glpios01.obj \
296.49 +..\src\glpios02.obj \
296.50 +..\src\glpios03.obj \
296.51 +..\src\glpios04.obj \
296.52 +..\src\glpios05.obj \
296.53 +..\src\glpios06.obj \
296.54 +..\src\glpios07.obj \
296.55 +..\src\glpios08.obj \
296.56 +..\src\glpios09.obj \
296.57 +..\src\glpios10.obj \
296.58 +..\src\glpios11.obj \
296.59 +..\src\glpios12.obj \
296.60 +..\src\glpipm.obj \
296.61 +..\src\glplib01.obj \
296.62 +..\src\glplib02.obj \
296.63 +..\src\glplib03.obj \
296.64 +..\src\glplpf.obj \
296.65 +..\src\glplpx01.obj \
296.66 +..\src\glplpx02.obj \
296.67 +..\src\glplpx03.obj \
296.68 +..\src\glpluf.obj \
296.69 +..\src\glplux.obj \
296.70 +..\src\glpmat.obj \
296.71 +..\src\glpmpl01.obj \
296.72 +..\src\glpmpl02.obj \
296.73 +..\src\glpmpl03.obj \
296.74 +..\src\glpmpl04.obj \
296.75 +..\src\glpmpl05.obj \
296.76 +..\src\glpmpl06.obj \
296.77 +..\src\glpmps.obj \
296.78 +..\src\glpnet01.obj \
296.79 +..\src\glpnet02.obj \
296.80 +..\src\glpnet03.obj \
296.81 +..\src\glpnet04.obj \
296.82 +..\src\glpnet05.obj \
296.83 +..\src\glpnet06.obj \
296.84 +..\src\glpnet07.obj \
296.85 +..\src\glpnet08.obj \
296.86 +..\src\glpnet09.obj \
296.87 +..\src\glpnpp01.obj \
296.88 +..\src\glpnpp02.obj \
296.89 +..\src\glpnpp03.obj \
296.90 +..\src\glpnpp04.obj \
296.91 +..\src\glpnpp05.obj \
296.92 +..\src\glpqmd.obj \
296.93 +..\src\glprgr.obj \
296.94 +..\src\glprng01.obj \
296.95 +..\src\glprng02.obj \
296.96 +..\src\glpscf.obj \
296.97 +..\src\glpscl.obj \
296.98 +..\src\glpsdf.obj \
296.99 +..\src\glpspm.obj \
296.100 +..\src\glpspx01.obj \
296.101 +..\src\glpspx02.obj \
296.102 +..\src\glpsql.obj \
296.103 +..\src\glpssx01.obj \
296.104 +..\src\glpssx02.obj \
296.105 +..\src\glptsp.obj \
296.106 +..\src\amd\amd_1.obj \
296.107 +..\src\amd\amd_2.obj \
296.108 +..\src\amd\amd_aat.obj \
296.109 +..\src\amd\amd_control.obj \
296.110 +..\src\amd\amd_defaults.obj \
296.111 +..\src\amd\amd_dump.obj \
296.112 +..\src\amd\amd_info.obj \
296.113 +..\src\amd\amd_order.obj \
296.114 +..\src\amd\amd_post_tree.obj \
296.115 +..\src\amd\amd_postorder.obj \
296.116 +..\src\amd\amd_preprocess.obj \
296.117 +..\src\amd\amd_valid.obj \
296.118 +..\src\colamd\colamd.obj
296.119 +
296.120 +.c.obj:
296.121 + cl.exe $(CFLAGS) /Fo$*.obj /c $*.c
296.122 +
296.123 +all: glpk_4_45.dll glpsol.exe
296.124 +
296.125 +glpk_4_45.dll: $(OBJSET)
296.126 + cl.exe $(CFLAGS) /LD /Feglpk_4_45.dll ..\src\*.obj \
296.127 + ..\src\amd\*.obj ..\src\colamd\*.obj glpk_4_45.def
296.128 +
296.129 +glpsol.exe: ..\examples\glpsol.obj glpk_4_45.dll
296.130 + cl.exe $(CFLAGS) /Feglpsol.exe ..\examples\glpsol.obj \
296.131 + glpk_4_45.lib
296.132 +
296.133 +check: glpsol.exe
296.134 + .\glpsol.exe --version
296.135 + .\glpsol.exe --mps ..\examples\plan.mps
297.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
297.2 +++ b/w64/readme.txt Mon Dec 06 13:09:21 2010 +0100
297.3 @@ -0,0 +1,24 @@
297.4 +This directory contains batch files and other stuff which you can use
297.5 +to build GLPK for 64-bit Windows with the native C/C++ compilers.
297.6 +
297.7 +Before running the batch file do the following:
297.8 +
297.9 +1. Make sure that you have installed the compiler you are going to use
297.10 + to build GLPK.
297.11 +
297.12 +2. Look into corresponding batch file (just right-click it and choose
297.13 + 'Edit' in the popup menu; DO NOT choose 'Open'). Make sure that HOME
297.14 + variable specifies correct path to the compiler directory; if not,
297.15 + make necessary changes.
297.16 +
297.17 +To run the batch file just double-click it and wait a bit while the
297.18 +Make utility does its job. The message 'OPTIMAL SOLUTION FOUND' in the
297.19 +MS-DOS window means that all is OK. If you do not see it, something is
297.20 +wrong.
297.21 +
297.22 +Once GLPK has been successfully built, there must appear two files in
297.23 +this directory:
297.24 +
297.25 +glpk.lib, which is the GLPK object library, and
297.26 +
297.27 +glpsol.exe, which is the stand-alone GLPK LP/MIP solver.